1package daemonrpc
2
3import (
4 "encoding/json"
5 "fmt"
6 "net"
7 "sync"
8)
9
10// Conn wraps a net.Conn with newline-delimited JSON encoding/decoding.
11type Conn struct {
12 conn net.Conn
13 enc *json.Encoder
14 dec *json.Decoder
15 mu sync.Mutex // serializes writes
16}
17
18// NewConn wraps an existing network connection.
19func NewConn(c net.Conn) *Conn {
20 return &Conn{
21 conn: c,
22 enc: json.NewEncoder(c),
23 dec: json.NewDecoder(c),
24 }
25}
26
27// Send writes a JSON-encoded message followed by a newline.
28// Thread-safe.
29func (c *Conn) Send(v interface{}) error {
30 c.mu.Lock()
31 defer c.mu.Unlock()
32 return c.enc.Encode(v)
33}
34
35// SendResponse sends a successful response with the given result.
36func (c *Conn) SendResponse(id uint64, result interface{}) error {
37 raw, err := json.Marshal(result)
38 if err != nil {
39 return fmt.Errorf("marshal result: %w", err)
40 }
41 return c.Send(&Response{
42 ID: id,
43 Result: raw,
44 })
45}
46
47// SendError sends an error response.
48func (c *Conn) SendError(id uint64, code int, message string) error {
49 return c.Send(&Response{
50 ID: id,
51 Error: &Error{Code: code, Message: message},
52 })
53}
54
55// SendEvent sends a push event to the client.
56func (c *Conn) SendEvent(eventType string, data interface{}) error {
57 raw, err := json.Marshal(data)
58 if err != nil {
59 return fmt.Errorf("marshal event data: %w", err)
60 }
61 return c.Send(&Event{
62 Type: eventType,
63 Data: raw,
64 })
65}
66
67// ReceiveMessage reads and decodes the next JSON message, returning
68// a discriminated Message (Request, Response, or Event).
69func (c *Conn) ReceiveMessage() (Message, error) {
70 var raw json.RawMessage
71 if err := c.dec.Decode(&raw); err != nil {
72 return Message{}, err
73 }
74 return DecodeMessage(raw)
75}
76
77// Close closes the underlying connection.
78func (c *Conn) Close() error {
79 return c.conn.Close()
80}
81
82// RemoteAddr returns the remote address of the connection.
83func (c *Conn) RemoteAddr() net.Addr {
84 return c.conn.RemoteAddr()
85}
86
87// LocalAddr returns the local address of the connection.
88func (c *Conn) LocalAddr() net.Addr {
89 return c.conn.LocalAddr()
90}