-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprotocol.go
More file actions
116 lines (106 loc) · 3.54 KB
/
protocol.go
File metadata and controls
116 lines (106 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Package udsrpc is a tiny newline-delimited JSON-RPC implementation
// designed for daemon ↔ client communication over Unix domain sockets.
//
// It sits between net/rpc (too rigid, gob-only) and full gRPC (too heavy).
// Messages are JSON objects separated by newlines; the wire format is
// language-agnostic, debuggable by hand, and trivial to bridge to any
// other runtime.
//
// Three message shapes share the wire:
//
// - Request: {"id": N, "method": "...", "params": {...}}
// - Response: {"id": N, "result": {...}} or {"id": N, "error": {...}}
// - Event: {"type": "...", "data": {...}} (server → client push)
//
// DecodeMessage discriminates between the three by inspecting the keys
// present in the raw JSON: "type" → Event, "method" → Request, else
// Response.
package udsrpc
import "encoding/json"
// Request from client to server. The ID is echoed in the matching
// Response so callers can correlate concurrent in-flight requests.
type Request struct {
ID uint64 `json:"id"`
Method string `json:"method"`
Params json.RawMessage `json:"params,omitempty"`
}
// Response from server to client. Either Result or Error is populated,
// never both.
type Response struct {
ID uint64 `json:"id"`
Result json.RawMessage `json:"result,omitempty"`
Error *Error `json:"error,omitempty"`
}
// Event is a server-pushed message with no Request. It has no ID and
// is not acknowledged.
type Event struct {
Type string `json:"type"`
Data json.RawMessage `json:"data,omitempty"`
}
// Error is the error payload inside a Response.
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
}
// Error implements the error interface so an *Error can be returned
// from handlers directly.
func (e *Error) Error() string { return e.Message }
// Message is a discriminated union for wire decoding. Exactly one of
// Request, Response, or Event is non-nil after DecodeMessage succeeds.
type Message struct {
Request *Request
Response *Response
Event *Event
}
// DecodeMessage inspects raw and returns a discriminated Message.
//
// Discriminator order: "type" present → Event, "method" present →
// Request, else → Response. This matches how peers should produce
// messages — never include both "type" and "method", never set "id"
// on Events.
func DecodeMessage(raw json.RawMessage) (Message, error) {
var probe struct {
Type string `json:"type"`
Method string `json:"method"`
ID *uint64 `json:"id"`
}
if err := json.Unmarshal(raw, &probe); err != nil {
return Message{}, err
}
var m Message
switch {
case probe.Type != "":
var ev Event
if err := json.Unmarshal(raw, &ev); err != nil {
return m, err
}
m.Event = &ev
case probe.Method != "":
var req Request
if err := json.Unmarshal(raw, &req); err != nil {
return m, err
}
m.Request = &req
default:
var resp Response
if err := json.Unmarshal(raw, &resp); err != nil {
return m, err
}
m.Response = &resp
}
return m, nil
}
// Standard error codes, borrowed from JSON-RPC 2.0 so existing
// tooling and client libraries recognize them.
const (
// ErrCodeParse — invalid JSON was received.
ErrCodeParse = -32700
// ErrCodeInvalidReq — request was not a valid Request object.
ErrCodeInvalidReq = -32600
// ErrCodeNotFound — method does not exist or is not registered.
ErrCodeNotFound = -32601
// ErrCodeInvalidParams — method exists but params are invalid.
ErrCodeInvalidParams = -32602
// ErrCodeInternal — internal server error.
ErrCodeInternal = -32603
)