返回 DeepSeek-Reasonix
protocol.go
根目录 / internal / skill / skillwatch / protocol.go
1 package skillwatch
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io"
7 )
8
9 // wireKind identifies one frame of the host <-> watcher helper pipe protocol.
10 // The helper process is an internal entry of the existing host executable; the
11 // protocol must stay compatible across a helper and host built from the same
12 // source tree, which the host enforces by spawning its own executable.
13 type wireKind uint8
14
15 const (
16 // Host -> helper.
17 wireRegister wireKind = 1 // watch dirs under one logical registration
18 wireCancel wireKind = 2 // revoke a logical registration
19 wireShutdown wireKind = 3 // helper exits after replying
20 wirePing wireKind = 4 // control-path liveness probe
21
22 // Helper -> host.
23 wireReady wireKind = 5 // helper finished initializing
24 wireRegistered wireKind = 6 // registration confirmed
25 wireEvent wireKind = 7 // coalescing input: one filesystem event
26 wireError wireKind = 8 // registration or backend failure
27 wirePong wireKind = 9 // ping reply
28 )
29
30 // Op flags mirror the fsnotify operations the service reacts to. Keeping the
31 // protocol independent of fsnotify types lets the helper binary compile without
32 // dragging host-side assumptions across the pipe.
33 type Op uint32
34
35 const (
36 OpCreate Op = 1 << iota
37 OpRemove
38 OpRename
39 OpWrite
40 OpChmod
41 )
42
43 func (o Op) String() string {
44 switch o {
45 case OpCreate:
46 return "create"
47 case OpRemove:
48 return "remove"
49 case OpRename:
50 return "rename"
51 case OpWrite:
52 return "write"
53 case OpChmod:
54 return "chmod"
55 }
56 return "op"
57 }
58
59 const wireMaxFrameBytes = 8 << 20
60
61 // frame is one length-prefixed JSON message. ID is a logical registration;
62 // RootGen is the host generation the registration was created under, so late
63 // events from a superseded registration stay recognizable and get dropped.
64 type frame struct {
65 Kind wireKind `json:"kind"`
66 ID uint64 `json:"id,omitempty"`
67 RootGen uint64 `json:"rootGen,omitempty"`
68 Op Op `json:"op,omitempty"`
69 Dirs []string `json:"dirs,omitempty"`
70 Msg string `json:"msg,omitempty"`
71 }
72
73 func writeFrame(w io.Writer, f frame) error {
74 payload, err := json.Marshal(f)
75 if err != nil {
76 return err
77 }
78 if len(payload) > wireMaxFrameBytes {
79 return fmt.Errorf("watch helper frame exceeds %d bytes", wireMaxFrameBytes)
80 }
81 var size [4]byte
82 n := uint32(len(payload))
83 size[0], size[1], size[2], size[3] = byte(n), byte(n>>8), byte(n>>16), byte(n>>24)
84 if _, err := w.Write(size[:]); err != nil {
85 return err
86 }
87 _, err = w.Write(payload)
88 return err
89 }
90
91 func readFrame(r io.Reader) (frame, error) {
92 var size [4]byte
93 if _, err := io.ReadFull(r, size[:]); err != nil {
94 return frame{}, err
95 }
96 n := uint32(size[0]) | uint32(size[1])<<8 | uint32(size[2])<<16 | uint32(size[3])<<24
97 if n == 0 || n > wireMaxFrameBytes {
98 return frame{}, fmt.Errorf("watch helper frame size %d out of range", n)
99 }
100 payload := make([]byte, n)
101 if _, err := io.ReadFull(r, payload); err != nil {
102 return frame{}, err
103 }
104 var f frame
105 if err := json.Unmarshal(payload, &f); err != nil {
106 return frame{}, err
107 }
108 return f, nil
109 }
110
110 lines GO