Documentation
¶
Overview ¶
Package sdk provides reusable daemon-client infrastructure for agent CLI tools. It is game-agnostic; all game-specific behavior is injected via callbacks.
Index ¶
- func HTTPGET(url string) (string, error)
- func IsTerminal(f *os.File) bool
- func SaveSession(path string, s SessionState) error
- func SocketPath(sessionPath string) string
- func WSURLToHTTP(wsURL string) string
- type CommandClient
- type CommandHandler
- type DaemonClient
- func (d *DaemonClient) ConnectionID() string
- func (d *DaemonClient) IsBroadcast(data []byte) bool
- func (d *DaemonClient) Run(ctx context.Context) error
- func (d *DaemonClient) SendWS(data []byte) error
- func (d *DaemonClient) Session() *SessionState
- func (d *DaemonClient) Subscribe() *ResponseSubscriber
- func (d *DaemonClient) Unsubscribe(sub *ResponseSubscriber)
- func (d *DaemonClient) WSConn() *websocket.Conn
- type DaemonConfig
- type EventEntry
- type EventWriter
- type IPCServer
- type ResponseSubscriber
- type SessionState
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func HTTPGET ¶
HTTPGET performs a GET request and returns the response body as a compact JSON string if the body is valid JSON, or the raw trimmed string otherwise.
func IsTerminal ¶
IsTerminal returns true if f is connected to a TTY (best-effort; defaults to false).
func SaveSession ¶
func SaveSession(path string, s SessionState) error
SaveSession writes the session state to path, creating or overwriting the file. The file is written with mode 0600 (owner read/write only).
func SocketPath ¶
SocketPath returns the canonical Unix socket path for a given session file path. Uses the first 12 hex chars of a SHA-256 hash to keep the path short and unique.
func WSURLToHTTP ¶
WSURLToHTTP converts a WebSocket URL to its HTTP equivalent and strips the path so that only the base URL (scheme + host) is returned. Examples:
ws://localhost:8080/ws → http://localhost:8080 wss://api.example.com/ws → https://api.example.com
Types ¶
type CommandClient ¶
type CommandClient struct {
// contains filtered or unexported fields
}
CommandClient sends commands to a running daemon via its Unix socket.
func NewCommandClient ¶
func NewCommandClient(sockPath string) *CommandClient
NewCommandClient creates a CommandClient that talks to the daemon at sockPath.
func (*CommandClient) IsRunning ¶
func (c *CommandClient) IsRunning() bool
IsRunning returns true if a daemon is listening on the socket path.
type CommandHandler ¶
type CommandHandler func(cmd string, sess *SessionState) (response []byte, err error)
CommandHandler is called by IPCServer for each incoming command. cmd is the raw command string sent by the client. sess is the current session state (may be modified in place; caller saves it). Return (response, nil) to send a JSON response, or (nil, err) to send an error.
type DaemonClient ¶
type DaemonClient struct {
// contains filtered or unexported fields
}
DaemonClient maintains a persistent WebSocket connection, appends all received messages to an events file, and provides fan-out delivery to registered subscribers.
func NewDaemonClient ¶
func NewDaemonClient(cfg DaemonConfig) *DaemonClient
NewDaemonClient creates a DaemonClient with the given configuration. Call Run to start it.
func (*DaemonClient) ConnectionID ¶
func (d *DaemonClient) ConnectionID() string
ConnectionID returns the server-assigned connection ID received in the welcome message.
func (*DaemonClient) IsBroadcast ¶
func (d *DaemonClient) IsBroadcast(data []byte) bool
IsBroadcast delegates to DaemonConfig.BroadcastFilter. Returns false if no filter is configured.
func (*DaemonClient) Run ¶
func (d *DaemonClient) Run(ctx context.Context) error
Run connects to the WebSocket, performs session resume if a token is stored, writes a PID file, opens the events file, then blocks until ctx is cancelled or the WebSocket connection is lost.
func (*DaemonClient) SendWS ¶
func (d *DaemonClient) SendWS(data []byte) error
SendWS sends raw bytes as a WebSocket text message.
func (*DaemonClient) Session ¶
func (d *DaemonClient) Session() *SessionState
Session returns a pointer to the current session state.
func (*DaemonClient) Subscribe ¶
func (d *DaemonClient) Subscribe() *ResponseSubscriber
Subscribe registers a new ResponseSubscriber to receive all subsequent WebSocket messages. Unsubscribe when done to avoid leaking goroutines.
func (*DaemonClient) Unsubscribe ¶
func (d *DaemonClient) Unsubscribe(sub *ResponseSubscriber)
Unsubscribe removes a subscriber registered with Subscribe.
func (*DaemonClient) WSConn ¶
func (d *DaemonClient) WSConn() *websocket.Conn
WSConn returns the underlying WebSocket connection. Do NOT read from it directly — the daemon's reader goroutine is the sole reader.
type DaemonConfig ¶
type DaemonConfig struct {
// WSURL is the WebSocket URL to connect to (e.g. "ws://localhost:8080/ws").
WSURL string
// SessionPath is the path to the session JSON file.
// The daemon also writes a PID file at SessionPath+".pid" and events at
// SessionPath+".events".
SessionPath string
// OnMessage is called for every WebSocket message received, including the
// welcome message. It is called from the dispatcher goroutine; do not block.
OnMessage func(data []byte)
// BroadcastFilter returns true if data is a known server broadcast that
// should never be treated as a direct response to a command. Used by the
// IPC server to skip stale messages while waiting for command responses.
// If nil, no filtering is applied.
BroadcastFilter func(data []byte) bool
}
DaemonConfig configures a DaemonClient.
type EventEntry ¶
type EventEntry struct {
Seq int `json:"seq"`
Ts string `json:"ts"`
Msg json.RawMessage `json:"msg"`
}
EventEntry is one line in the JSONL events file.
type EventWriter ¶
type EventWriter struct {
// contains filtered or unexported fields
}
EventWriter appends JSONL event entries to a file in a goroutine-safe manner. Each call to Append assigns a monotonically increasing sequence number.
func NewEventWriter ¶
func NewEventWriter(path string) (*EventWriter, error)
NewEventWriter opens (or creates) the file at path in append mode and returns an EventWriter ready to use. The caller must call Close when done.
func (*EventWriter) Append ¶
func (w *EventWriter) Append(raw []byte) int64
Append writes raw as a JSON event entry (with seq + timestamp) and returns the assigned sequence number. Errors writing to disk are silently ignored to avoid disrupting the caller's read loop.
func (*EventWriter) Close ¶
func (w *EventWriter) Close() error
Close flushes and closes the underlying file.
type IPCServer ¶
type IPCServer struct {
// contains filtered or unexported fields
}
IPCServer listens on a Unix socket and dispatches incoming commands to a CommandHandler. Each connection is handled in its own goroutine.
func NewIPCServer ¶
NewIPCServer creates a Unix socket listener at sockPath, removing any stale socket file first.
func (*IPCServer) Serve ¶
func (s *IPCServer) Serve(handler CommandHandler)
Serve accepts connections and calls handler for each command. It blocks until the listener is closed. Callers typically run it in a goroutine. The socket file is removed when Serve returns.
type ResponseSubscriber ¶
type ResponseSubscriber struct {
// contains filtered or unexported fields
}
ResponseSubscriber receives a copy of every WebSocket message via fan-out. Register one with DaemonClient.Subscribe before sending a command to ensure no messages are missed between send and receive.
func (*ResponseSubscriber) C ¶
func (s *ResponseSubscriber) C() <-chan []byte
C returns the channel on which messages are delivered.
type SessionState ¶
type SessionState struct {
GameID string `json:"gameId"`
LastConnectionID string `json:"lastConnectionId"`
Token string `json:"token,omitempty"`
Custom map[string]any `json:"custom,omitempty"` // app-specific state
}
SessionState is persisted to disk between daemon-mode invocations so that reconnecting clients can resume their identity and active game/room.
func LoadSession ¶
func LoadSession(path string) SessionState
LoadSession reads a session file and returns the state. Returns a zero value if the file is missing or unreadable.