Files
simplexmq/spec/clients.md
T
2026-03-15 13:00:27 +00:00

6.8 KiB

Client Architecture

SimpleX clients are the Layer 2 libraries that connect to routers. This document shows their internal architecture: component topology and command processing flows.

For deployment and usage, see docs/CLIENT.md. For protocol specifications, see SMP, XFTP, Push Notifications.


SMP Client (ProtocolClient)

Four threads: Send and receive threads are separate to allow backpressure - a slow receiver doesn't block sending. The process thread decouples parsing from delivery, preventing a slow consumer from stalling the receive loop. The monitor thread provides application-level keepalive beyond TCP - detecting protocol-level stalls. See transport.md.

Correlation ID lifecycle: IDs are generated before send and removed on response OR timeout. Removal on timeout prevents unbounded growth of sentCommands when the router is unresponsive.

Module specs: Client · Protocol · Transport · Crypto

Generic protocol client used for both SMP and NTF connections. Manages a single TLS connection with multiplexed command/response matching via correlation IDs.

SMP Client components

SMP Client components

Command/result flow

sequenceDiagram
    participant C as Caller<br>(Agent / router)

    box ProtocolClient
        participant SC as sentCommands<br>(TMap CorrId Request)
        participant SQ as sndQ
        participant S as send thread
        participant R as receive thread
        participant RQ as rcvQ
        participant P as process thread
    end

    participant Router as SMP Router

    C->>SC: mkTransmission<br/>(generate CorrId, create Request<br/>with empty responseVar)
    C->>SQ: write (Request, encoded command)
    S->>SQ: read
    S-->>S: check pending flag (drop if timed out)
    S->>Router: tPutLog (transmit bytes)

    Router->>R: tGetClient (receive batch)
    R->>RQ: write transmissions

    P->>RQ: read
    P->>SC: lookup CorrId
    alt command response (CorrId matches, pending)
        P->>SC: remove CorrId + fill responseVar (TMVar)
    else expired response (CorrId matches, already timed out)
        P->>C: write to msgQ (STResponse)
    else server event (empty CorrId)
        P->>C: write to msgQ (STEvent)
    end

    Note over C: getResponse: takeTMVar with timeout

SMPClientAgent

Dual consumers: Used by both SMP router (for proxy connections to relays) and NTF router (for NSUB subscriptions to SMP routers). Same connection pooling and reconnection logic, different command sets.

Session ID gating: Subscription responses are validated against the current TLS session ID. A response from a stale session (connection dropped and reconnected between send and receive) is discarded rather than corrupting state. See infrastructure.md.

Module specs: Client Agent

Connection manager that multiplexes multiple ProtocolClient connections. Tracks subscriptions, handles reconnection with backoff, and forwards server messages and connection events upward. Used by SMP router (proxying) and NTF router (subscriptions).

SMPClientAgent components

SMPClientAgent components

Connection lifecycle

sequenceDiagram
    participant C as Consumer<br>(router / app)

    box
        participant A as SMPClientAgent
        participant PC as ProtocolClient
    end

    participant Router as SMP Router

    C->>A: getSMPServerClient'' (server)
    alt client exists in smpClients
        A->>C: return existing client
    else no client
        A->>PC: connectClient (create new ProtocolClient)
        PC->>Router: TLS handshake
        A->>A: register disconnect handler
        A->>C: return new client
    end

    C->>A: subscribeQueuesNtfs (queueIds)
    A->>A: add to pendingQueueSubs
    A->>PC: sendProtocolCommands (SUB batch)
    PC->>Router: SUB commands
    Router->>PC: OK responses
    A->>A: move pending → activeQueueSubs
    A->>C: CASubscribed (via agentQ)

    Note over Router: connection drops

    PC->>A: disconnect handler fires
    A->>A: filter by SessionId (only remove subs matching disconnected session)
    A->>A: move active → pending (queue subs + service subs)
    A->>C: CAServiceDisconnected (via agentQ, if service sub existed)
    A->>C: CADisconnected (via agentQ, if queue subs existed)
    A->>A: spawn smpSubWorker (retry with backoff)
    A->>PC: reconnect + resubscribe pending subs
    A->>C: CAConnected + CASubscribed (via agentQ)

XFTP Client

No subscriptions: File operations complete independently - no persistent server-side state to track. This allows XFTPClient to be a thin wrapper with no threads of its own.

Module specs: Client · Protocol · HTTP/2 Client

Stateless wrapper around HTTP2Client. XFTPClient adds no threads of its own. Serialization and multiplexing happen inside HTTP2Client's internal request queue and process thread.

XFTP Client components

XFTP Client components

Packet delivery flow

sequenceDiagram
    participant C as Caller<br>(Agent / app)
    participant X as XFTPClient
    participant H as HTTP2Client
    participant Router as XFTP Router

    C->>X: createXFTPChunk (FNEW)
    X->>H: HTTP/2 POST (encoded command)
    H->>Router: request
    Router->>H: response (sender ID + recipient IDs)
    H->>X: decode response
    X->>C: return IDs

    C->>X: uploadXFTPChunk (FPUT + file data)
    X->>H: HTTP/2 POST (streaming body)
    H->>Router: request with file stream
    Router->>H: OK
    H->>X: OK
    X->>C: return OK

    C->>X: downloadXFTPChunk (FGET + ephemeral DH key)
    X->>H: HTTP/2 POST (command)
    H->>Router: request
    Router->>H: streaming response (server DH key + nonce + encrypted data)
    H->>X: streaming body
    X->>X: compute DH secret, decrypt + save to file
    X->>C: return ()

NTF Client

Module specs: Client · Protocol

Type alias for ProtocolClient - same architecture as SMP Client:

type NtfClient = ProtocolClient NTFVersion ErrorType NtfResponse

Same threads (send, receive, process, monitor), same queues (sndQ, rcvQ, sentCommands, msgQ), same command/response flow. Different command types: TNEW, TVFY, TCHK, TRPL, TDEL, TCRN, SNEW, SCHK, SDEL, PING.