forked from opencode/ocgo
feat: improve Windows support
This commit is contained in:
parent
e2d9bb5038
commit
cc7e1e8921
7 changed files with 130 additions and 23 deletions
6
Makefile
6
Makefile
|
|
@ -1,12 +1,14 @@
|
|||
.PHONY: build run test clean install release
|
||||
|
||||
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
|
||||
EXE := $(shell go env GOEXE)
|
||||
OCGO_BIN := bin/ocgo$(EXE)
|
||||
GOBIN := $(shell go env GOBIN)
|
||||
GOPATH := $(shell go env GOPATH)
|
||||
INSTALL_DIR := $(if $(GOBIN),$(GOBIN),$(GOPATH)/bin)
|
||||
|
||||
build:
|
||||
go build -ldflags "-X main.version=$(VERSION)" -o bin/ocgo ./cmd/ocgo
|
||||
go build -ldflags "-X main.version=$(VERSION)" -o $(OCGO_BIN) ./cmd/ocgo
|
||||
|
||||
run:
|
||||
go run ./cmd/ocgo
|
||||
|
|
@ -19,7 +21,7 @@ clean:
|
|||
|
||||
install: build
|
||||
mkdir -p "$(INSTALL_DIR)"
|
||||
install -m 0755 bin/ocgo "$(INSTALL_DIR)/ocgo"
|
||||
install -m 0755 "$(OCGO_BIN)" "$(INSTALL_DIR)/ocgo$(EXE)"
|
||||
|
||||
release:
|
||||
@[ -n "$(TAG)" ] || (echo "Usage: make release TAG=v0.1.0" && exit 1)
|
||||
|
|
|
|||
9
build.bat
Normal file
9
build.bat
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@echo off
|
||||
setlocal
|
||||
|
||||
for /f "delims=" %%v in ('git describe --tags --always --dirty 2^>NUL') do set "OCGO_VERSION=%%v"
|
||||
if not defined OCGO_VERSION set "OCGO_VERSION=dev"
|
||||
|
||||
if not exist bin mkdir bin
|
||||
go build -ldflags "-X main.version=%OCGO_VERSION%" -o bin\ocgo.exe .\cmd\ocgo
|
||||
exit /b %ERRORLEVEL%
|
||||
40
cmd/ocgo/listener_pid_netstat.go
Normal file
40
cmd/ocgo/listener_pid_netstat.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parseWindowsNetstatPID(output string, port int) (int, error) {
|
||||
wanted := strconv.Itoa(port)
|
||||
for _, line := range strings.Split(output, "\n") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 5 || !strings.EqualFold(fields[0], "tcp") {
|
||||
continue
|
||||
}
|
||||
if !strings.EqualFold(fields[len(fields)-2], "listening") {
|
||||
continue
|
||||
}
|
||||
if !netstatAddressUsesPort(fields[1], wanted) {
|
||||
continue
|
||||
}
|
||||
pid, err := strconv.Atoi(fields[len(fields)-1])
|
||||
if err == nil && pid > 0 {
|
||||
return pid, nil
|
||||
}
|
||||
}
|
||||
return 0, errors.New("no listener found")
|
||||
}
|
||||
|
||||
func netstatAddressUsesPort(address, port string) bool {
|
||||
address = strings.TrimSpace(address)
|
||||
if address == "" {
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(address, "[") {
|
||||
return strings.HasSuffix(address, "]:"+port)
|
||||
}
|
||||
idx := strings.LastIndex(address, ":")
|
||||
return idx >= 0 && address[idx+1:] == port
|
||||
}
|
||||
27
cmd/ocgo/listener_pid_unix.go
Normal file
27
cmd/ocgo/listener_pid_unix.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//go:build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func findListenerPID(port int) (int, error) {
|
||||
if port == 0 {
|
||||
return 0, errors.New("missing port")
|
||||
}
|
||||
out, err := exec.Command("lsof", "-nP", "-tiTCP:"+strconv.Itoa(port), "-sTCP:LISTEN").Output()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
||||
pid, err := strconv.Atoi(strings.TrimSpace(line))
|
||||
if err == nil && pid > 0 {
|
||||
return pid, nil
|
||||
}
|
||||
}
|
||||
return 0, errors.New("no listener found")
|
||||
}
|
||||
19
cmd/ocgo/listener_pid_windows.go
Normal file
19
cmd/ocgo/listener_pid_windows.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func findListenerPID(port int) (int, error) {
|
||||
if port == 0 {
|
||||
return 0, errors.New("missing port")
|
||||
}
|
||||
out, err := exec.Command("netstat", "-ano", "-p", "tcp").Output()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return parseWindowsNetstatPID(string(out), port)
|
||||
}
|
||||
|
|
@ -330,6 +330,10 @@ func statusCmd() *cobra.Command {
|
|||
fmt.Printf("Proxy is running on %s:%d (PID %d)\n", cfg.Host, cfg.Port, pid)
|
||||
return
|
||||
}
|
||||
if pid, err := findListenerPID(cfg.Port); err == nil {
|
||||
fmt.Printf("Proxy is running on %s:%d (PID %d, discovered from listener)\n", cfg.Host, cfg.Port, pid)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Proxy is running on %s:%d (no ocgo PID file)\n", cfg.Host, cfg.Port)
|
||||
}}
|
||||
}
|
||||
|
|
@ -1508,24 +1512,3 @@ func readPID() (int, error) {
|
|||
_, err = fmt.Sscan(string(b), &pid)
|
||||
return pid, err
|
||||
}
|
||||
|
||||
func findListenerPID(port int) (int, error) {
|
||||
if port == 0 {
|
||||
return 0, errors.New("missing port")
|
||||
}
|
||||
out, err := exec.Command("lsof", "-nP", "-tiTCP:"+strconv.Itoa(port), "-sTCP:LISTEN").Output()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
pid, err := strconv.Atoi(line)
|
||||
if err == nil && pid > 0 {
|
||||
return pid, nil
|
||||
}
|
||||
}
|
||||
return 0, errors.New("no listener found")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,6 +262,33 @@ func contentString(v any) string {
|
|||
return s
|
||||
}
|
||||
|
||||
func TestParseWindowsNetstatPID(t *testing.T) {
|
||||
output := strings.Join([]string{
|
||||
"Proto Local Address Foreign Address State PID",
|
||||
"TCP 127.0.0.1:3456 0.0.0.0:0 LISTENING 4321",
|
||||
"TCP [::1]:9999 [::]:0 LISTENING 8765",
|
||||
"TCP 127.0.0.1:34560 0.0.0.0:0 LISTENING 1111",
|
||||
}, "\n")
|
||||
pid, err := parseWindowsNetstatPID(output, 3456)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pid != 4321 {
|
||||
t.Fatalf("pid = %d, want 4321", pid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWindowsNetstatPIDMatchesIPv6(t *testing.T) {
|
||||
output := "TCP [::]:3456 [::]:0 LISTENING 2468\n"
|
||||
pid, err := parseWindowsNetstatPID(output, 3456)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pid != 2468 {
|
||||
t.Fatalf("pid = %d, want 2468", pid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStreamAnthropicForwardsToolCalls(t *testing.T) {
|
||||
reasoningContentCache.Lock()
|
||||
reasoningContentCache.byCallID = map[string]string{}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue