Skip to content

feat(jsonrpc): JSON-RPC 2.0 over WebSocket external API - #80

Open
EnriqueParodi wants to merge 1 commit into
feat/libs-genfrom
feat/jsonrpc
Open

feat(jsonrpc): JSON-RPC 2.0 over WebSocket external API#80
EnriqueParodi wants to merge 1 commit into
feat/libs-genfrom
feat/jsonrpc

Conversation

@EnriqueParodi

Copy link
Copy Markdown
Collaborator

Sen's external API for programmatic access: every Sen object's properties,
methods, and events reachable over a single WebSocket per process,
typed end-to-end through STL.

Wire surface:

  • Standard JSON-RPC 2.0 envelope; one WebSocket per process serves all
    sessions and buses.
  • Per-call interest model: clients open a named interest (live SQL
    query against a bus), receive the initial match-set, then read /
    write / invoke / subscribe against named objects in that match-set.
    Server pushes interestUpdate frames as the match-set changes.
  • getObjectsBatchState batches per-object reads (capped at 512 per call)
    for snapshot-style use cases; one round-trip beats N getProperty calls
    for large pinned sets.
  • Opt-in withSchemas ships JSON-Schema fragments alongside each type's
    CustomTypeSpec, so clients shaping values for setProperty / invokeMethod
    don't need an extra getType round-trip per type.

Correctness commitments:

  • wirePropertyGuard and wireEventGuard lambdas hold weak_ptr
    and lock-and-test before dereferencing; the kernel-side Callback
    invalidation is a race-stop, not a guarantee.
  • RequestContext::respond is noexcept + cross-thread safe via
    std::atomic_flag; the async-invoke callback path can fire from any
    thread.
  • BundleRegistry uses a sorted vector + bool return; deduplication
    is over normalised file paths (not dangling string_views).
  • walkVarToJson / walkJsonToVar recursion is depth-bounded.
  • Identity is wired via setNextIdentity after the static_no_config
    switch (the wire shape exposes a [static_no_config] property, not
    a [static] one, so dynamic registration works).
  • Per-call open-timeout and per-call response-budget are explicit.
  • TimeStamp / Duration / i64 / u64 cross the wire as decimal strings;
    the per-format codec lives in floor-divide TimeStamp formatters
    (with negative-timestamp arithmetic correct).
  • propertyChanged envelopes are hand-built; interest-name escaping is
    unit-tested.

Architectural choices:

  • STL stubs vs dispatcher hand-routing chosen per-method: set / invoke /
    subscribe go through the STL surface for clean typing; read / state /
    topology hand-routed for snapshot semantics.
  • One thread of control on the server side (uWS loop); dispatcher runs
    on the kernel-scheduled run() thread.
  • Connection-churn snapshot test pins the wire shape for the dispatcher;
    PUBLIC_SYMBOLS package flag keeps server internals out of consumers.

Interest creation semantics:

  • Kernel getSource is get-or-create and cannot fail for a well-formed
    address, so the defensive "unknown bus" rejection was unreachable --
    removed in favor of a comment stating the real contract.
  • An interest on a not-yet-existing bus is valid and resolves when a
    publisher joins the address (reconnecting clients that re-declare
    before the domain rebuilds depend on this; unit-pinned so a future
    "validate the bus" refactor fails loudly).
  • In exchange, the one remote-controlled resource nothing bounded is
    now capped: at most 256 live interests per connection, with an
    actionable error.

Documentation:

  • Non-expert rewrite of the user-facing doc + architecture overview
    • per-mode wire example walkthroughs.

@EnriqueParodi
EnriqueParodi force-pushed the feat/jsonrpc branch 3 times, most recently from 430e8cf to 905cb76 Compare August 16, 2026 20:05
@EnriqueParodi
EnriqueParodi force-pushed the feat/libs-gen branch 3 times, most recently from f5bded8 to a3e8f32 Compare August 19, 2026 14:11
@EnriqueParodi
EnriqueParodi marked this pull request as ready for review August 19, 2026 15:08
@EnriqueParodi
EnriqueParodi force-pushed the feat/jsonrpc branch 2 times, most recently from 1c8c4c6 to 8de4983 Compare August 19, 2026 16:12
@EnriqueParodi EnriqueParodi reopened this Aug 19, 2026
Sen's external API: every object's properties, methods and events reachable
over one WebSocket per process, typed end-to-end through STL. Clients open
named interests, which are live SQL queries, and each connection is capped at
256 of them so a remote peer cannot grow that resource without bound.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant