rpc

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 5, 2026 License: AGPL-3.0 Imports: 23 Imported by: 0

Documentation

Overview

Package rpc implements gmcli's local control surface: newline-delimited JSON-RPC 2.0 over a unix domain socket. `gmcli serve` hosts the server; the bundled Go client (client.go), the gmtui Rust client, and any agent runtime that can speak NDJSON are consumers.

Wire format, one JSON document per line:

-> {"jsonrpc":"2.0","id":1,"method":"chats.list","params":{"limit":20}}
<- {"jsonrpc":"2.0","id":1,"result":[...]}

After a client calls "subscribe", the server pushes events as JSON-RPC notifications:

<- {"jsonrpc":"2.0","method":"event","params":{"type":"message.new","data":{...}}}

Index

Constants

View Source
const (
	CodeParse          = -32700
	CodeInvalidRequest = -32600
	CodeMethodNotFound = -32601
	CodeInvalidParams  = -32602
	CodeInternal       = -32603

	// CodeSendsDisabled: the daemon was started read-only (the default);
	// nothing may touch the phone.
	CodeSendsDisabled = 1001
	// CodeNotFound: the referenced entity does not exist.
	CodeNotFound = 1002
	// CodeAlreadyResolved: the approval was resolved by someone else first.
	CodeAlreadyResolved = 1003
	// CodeUnavailable: the phone or relay connection is not usable.
	CodeUnavailable = 1004
)

Standard JSON-RPC codes plus gmcli application codes.

View Source
const (
	EventMessageNew          = "message.new"
	EventConversationUpdated = "conversation.updated"
	EventSyncStatus          = "sync.status"
	EventApprovalRequested   = "approval.requested"
	EventApprovalResolved    = "approval.resolved"
	// Pairing flow (auth.pair): the QR to render, then success or error.
	// After pair.success the daemon restarts itself to load the new
	// session; clients reconnect and refetch.
	EventPairQR      = "pair.qr"
	EventPairEmoji   = "pair.emoji"
	EventPairSuccess = "pair.success"
	EventPairError   = "pair.error"
)

Event types pushed to subscribed clients.

Variables

This section is empty.

Functions

func Listen

func Listen(path string) (net.Listener, error)

Listen prepares the unix socket at path. A stale socket file from a crashed daemon is removed; a live one (something accepts connections) aborts with an error so two daemons never fight over one store.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a minimal Go client for the gmcli daemon socket. Safe for concurrent Call use; events arrive on the channel returned by Events after Subscribe.

func Dial

func Dial(socketPath string) (*Client, error)

Dial connects to the daemon socket. Returns a wrapped error mentioning `gmcli serve` when nothing is listening, since that is by far the most common failure.

func (*Client) Call

func (c *Client) Call(ctx context.Context, method string, params, result any) error

Call performs one RPC round trip, decoding the result into result when non-nil. Server-side failures come back as *Error.

func (*Client) Close

func (c *Client) Close() error

Close tears down the connection. Pending calls fail once the read loop notices the closed socket; the events channel closes with it.

func (*Client) Events

func (c *Client) Events() <-chan Event

Events is the stream of server pushes. Call Subscribe first; events are dropped (oldest-first pressure on the server side, newest dropped here) if the consumer falls more than the buffer behind.

func (*Client) Subscribe

func (c *Client) Subscribe(ctx context.Context) error

Subscribe asks the server to start pushing events on this connection.

type Deps

type Deps struct {
	Store       *store.Store
	Client      *gm.Client
	Pump        *gmsync.Pump
	Logger      zerolog.Logger
	Version     string
	SendMode    SendMode
	LiveTimeout time.Duration // 0 means defaultLiveTimeout
	// Layout enables the in-daemon pairing flow (auth.pair). Zero value
	// disables it (tests).
	Layout paths.Layout
	// IdleExit, when > 0, arms the Idle() signal: it fires once the server
	// has had no client connections for this long (including never having
	// had one). Used by auto-started daemons to retire themselves.
	IdleExit time.Duration
}

Deps carries everything the server needs. Client and Pump may be nil in tests that only exercise store-backed methods; phone-touching methods then return CodeUnavailable.

type Error

type Error struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    any    `json:"data,omitempty"`
}

Error is a JSON-RPC error object.

func (*Error) Error

func (e *Error) Error() string

type Event

type Event struct {
	Type string `json:"type"`
	Data any    `json:"data,omitempty"`
}

Event is the payload of an "event" notification.

type Notification

type Notification struct {
	JSONRPC string `json:"jsonrpc"`
	Method  string `json:"method"`
	Params  Event  `json:"params"`
}

Notification is a server-initiated push (no ID). The only method the server emits is "event".

type Request

type Request struct {
	JSONRPC string          `json:"jsonrpc,omitempty"`
	ID      json.RawMessage `json:"id,omitempty"`
	Method  string          `json:"method"`
	Params  json.RawMessage `json:"params,omitempty"`
}

Request is one inbound JSON-RPC call.

type Response

type Response struct {
	JSONRPC string          `json:"jsonrpc"`
	ID      json.RawMessage `json:"id,omitempty"`
	Result  any             `json:"result,omitempty"`
	Error   *Error          `json:"error,omitempty"`
}

Response is one outbound JSON-RPC reply.

type SendMode

type SendMode string

SendMode controls how the daemon treats phone-mutating requests.

const (
	// SendOff blocks all sends (daemon started with --read-only, the default).
	SendOff SendMode = "off"
	// SendApprove queues send.text requests as approvals; a human resolves
	// them via approvals.approve (TUI, `gmcli approvals approve`).
	SendApprove SendMode = "approve"
	// SendDirect performs send.text immediately. An audit row is still
	// written to the approvals table with a terminal status.
	SendDirect SendMode = "direct"
)

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server hosts the RPC surface. Construct with NewServer, run with Serve.

func NewServer

func NewServer(deps Deps) *Server

NewServer builds a Server around deps.

func (*Server) Broadcast

func (s *Server) Broadcast(typ string, data any)

Broadcast pushes an event to every subscribed connection.

func (*Server) HandleGMEvent

func (s *Server) HandleGMEvent(evt any)

HandleGMEvent converts libgm events into subscriber pushes. Register it on gm.Client *after* the sync pump so the store row already exists when a client reacts to the event.

func (*Server) Idle

func (s *Server) Idle() <-chan struct{}

Idle fires once when the server has been client-free for Deps.IdleExit. Returns nil (blocks forever in a select) when idle exit is disabled.

func (*Server) MarkAuthExpired added in v0.3.4

func (s *Server) MarkAuthExpired()

MarkAuthExpired flags the pairing as dead (also broadcast as a sync.status logged_out event by HandleGMEvent).

func (*Server) Serve

func (s *Server) Serve(ctx context.Context, ln net.Listener) error

Serve accepts connections until ctx is cancelled or the listener fails. It closes the listener (and removes the socket file) on return.

func (*Server) ShutdownRequested added in v0.3.4

func (s *Server) ShutdownRequested() <-chan struct{}

ShutdownRequested fires when a client asked the daemon to exit (daemon.shutdown — used by `gmcli auth` to hand over a fresh session).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL