Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

91 lines
2.3 KiB
Go

package hooks
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/zzet/gortex/internal/daemon"
)
func unmarshalResult(raw json.RawMessage, v any) error {
if len(raw) == 0 {
return nil
}
return json.Unmarshal(raw, v)
}
// probeViaDaemon dials the local daemon over its unix socket and runs one
// search_symbols control RPC. The whole exchange (dial + handshake + RPC)
// must fit inside timeout; otherwise errProbeTimeout is returned and the
// caller falls through to soft guidance.
//
// Returns errDaemonUnreachable when the daemon isn't running — the hook
// distinguishes "no signal" from "probed and missed" so telemetry stays
// clean.
func probeViaDaemon(pattern string, timeout time.Duration) ([]grepSymbolHit, error) {
deadline := time.Now().Add(timeout)
type probeResult struct {
hits []grepSymbolHit
err error
}
done := make(chan probeResult, 1)
go func() {
client, err := daemon.Dial(daemon.Handshake{
Mode: daemon.ModeControl,
ClientName: "gortex-hook",
})
if err != nil {
if errors.Is(err, daemon.ErrDaemonUnavailable) {
done <- probeResult{err: errDaemonUnreachable}
return
}
done <- probeResult{err: fmt.Errorf("dial daemon: %w", err)}
return
}
defer client.Close()
// Cap each socket op at the remaining budget so a stuck daemon
// can't pin the goroutine past timeout.
_ = client.Conn.SetDeadline(deadline)
resp, err := client.Control(daemon.ControlSearchSymbols, daemon.SearchSymbolsParams{
Query: pattern,
Limit: 10,
})
if err != nil {
done <- probeResult{err: fmt.Errorf("control rpc: %w", err)}
return
}
if !resp.OK {
done <- probeResult{err: fmt.Errorf("daemon rejected search [%s]: %s", resp.ErrorCode, resp.ErrorMsg)}
return
}
var result daemon.SearchSymbolsResult
if err := unmarshalResult(resp.Result, &result); err != nil {
done <- probeResult{err: fmt.Errorf("decode result: %w", err)}
return
}
hits := make([]grepSymbolHit, 0, len(result.Hits))
for _, h := range result.Hits {
hits = append(hits, grepSymbolHit{
Name: h.Name,
Kind: h.Kind,
FilePath: h.FilePath,
Line: h.Line,
})
}
done <- probeResult{hits: hits}
}()
select {
case r := <-done:
return r.hits, r.err
case <-time.After(time.Until(deadline)):
return nil, errProbeTimeout
}
}