transport.go

 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}