rpc

package
v0.3.2 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: 20 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"
)

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
	// 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) 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.

Jump to

Keyboard shortcuts

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