|
morph 0.1.0
Asynchronous bridge between GUI thread and business models
|
IBackend adapter that routes all calls through a RemoteServer as wire Envelope messages. More...
#include <remote.hpp>
Public Member Functions | |
| SimulatedRemoteBackend (RemoteServer &server) | |
Constructs the backend targeting server, unscoped. | |
| SimulatedRemoteBackend (RemoteServer &server, ConnectionId cid) | |
Constructs the backend targeting server, scoped to cid. | |
| ~SimulatedRemoteBackend () override | |
| Stops delivering events: the server may still post to the connection, and those envelopes are dropped. | |
| SimulatedRemoteBackend (const SimulatedRemoteBackend &)=delete | |
| SimulatedRemoteBackend & | operator= (const SimulatedRemoteBackend &)=delete |
| SimulatedRemoteBackend (SimulatedRemoteBackend &&)=delete | |
| SimulatedRemoteBackend & | operator= (SimulatedRemoteBackend &&)=delete |
| ::morph::exec::detail::ModelId | registerModel (const std::string &typeId, std::function< std::unique_ptr<::morph::model::detail::IModelHolder >()>) override |
| Registers the model type on the server and returns its assigned id. | |
| ::morph::exec::detail::ModelId | registerModelWithContext (const std::string &typeId, std::function< std::unique_ptr<::morph::model::detail::IModelHolder >()>, std::string_view contextKey) override |
Registers the model type on the server, carrying contextKey across the wire so the server's RemoteServer::LogProvider (if configured) can attach an action log to the instance it creates. | |
| ::morph::async::Completion<::morph::exec::detail::ModelId > | bindModel (detail::BindRequest request, ::morph::exec::IExecutor &cbExec) override |
Acquires an instance on the server for request and settles the returned Completion before returning. | |
| void | setOwner (const ::morph::exec::detail::OwnerAffinity &owner) override |
| Records the owner every verb is called from. | |
| void | assignPrimary (::morph::exec::detail::ModelId mid, const std::string &typeId, std::string_view primary) override |
Files a live server-side instance under primary. | |
| std::vector< std::string > | listInstances (const std::string &typeId) override |
Asks the server for the live shared primary keys of typeId. | |
| void | deregisterModel (::morph::exec::detail::ModelId mid) override |
| Deregisters the model on the server. Processed inline. | |
| ::morph::wire::ProtocolNegotiationResult | negotiateProtocolVersion () |
| Sends a "hello" envelope to the server and classifies its reply. | |
| std::string | fetchActionSchemas (std::string typeId) |
Fetches the server's {actionType: schema} document for typeId. | |
| ::morph::async::Completion< std::shared_ptr< void > > | execute (::morph::exec::detail::ModelId mid, detail::ActionCall call, ::morph::exec::IExecutor *cbExec) override |
| Serialises the action, sends it to the server, and returns a Completion. | |
| void | notifyBackendChanged () override |
| No-op — models live in RemoteServer, not locally. | |
| void | cancelPending (const std::exception_ptr &exc) override |
Resolves every still-pending completion this backend produced with exc. | |
| void | setEventHandler (std::function< void(::morph::wire::EventBody)> handler, ::morph::exec::IExecutor *exec) override |
| Installs the handler each server-initiated event is posted to. See IBackend::setEventHandler. | |
| void | setSession (::morph::session::Context session) override |
| Installs the session stamped onto every control envelope this backend subsequently builds (register, registerShared, attach, assign, deregister). See IBackend::setSession. | |
IBackend adapter that routes all calls through a RemoteServer as wire Envelope messages.
Intended for testing and in-process simulation of remote execution. Control envelopes (bindModel, registerModel, deregisterModel, ...) are processed through RemoteServer::handleInline, which answers before it returns, so a bind settles inside the call. execute() is asynchronous: it sends the message through RemoteServer::handle and resolves the returned Completion when the reply arrives.
Its pending list and session belong to the caller's owner (setOwner) and are touched only there, without a lock; the server's reply callback touches only the completion it settles.
A backend scoped to a connection also receives the server's events for it (setEventHandler): it registers a ConnectionWriter whose write hands each envelope to the handler, in the order the server posted them, with a backlog that always reads 0 – an in-process hand-off holds nothing back, so the server never withholds an event or owes a resync.
Definition at line 2832 of file remote.hpp.
|
inlineexplicit |
Constructs the backend targeting server, unscoped.
Every register/deregister/attach/assign/instances call this backend makes uses ConnectionId{0} — the server's "unscoped" sentinel (backend.md, "Connection scopes"). Use the ConnectionId constructor below to give this backend its own scope instead, so tests can exercise connection-scoped state (rate limiting, connection-drop recovery, shared-instance attach/detach across connections) deterministically without a real socket.
| server | The RemoteServer instance to forward calls to. Borrowed, not owned: it must outlive this backend — a backend holding a RemoteServer& that has been destroyed is a use-after-free on every call (see docs/spec/concurrency_and_lifetimes.md, "Destruction ordering"). |
Definition at line 2849 of file remote.hpp.
|
inline |
Constructs the backend targeting server, scoped to cid.
cid must have been obtained from server.openConnection() — the same connection-scope mechanism QtWebSocketServer/morph::net::SocketServer use for a real transport, made available for in-process simulation. Every register/attach/assign/instances call this backend makes is attributed to cid's scope (via the three-argument RemoteServer::handle/ handleInline overloads), so a deregisterModel/destructor-driven closeConnection reclaims exactly what this backend registered — the same reclamation guarantee a dropped socket gives a real client.
The backend does not call closeConnection itself on destruction: unlike a real transport, there is no single well-defined "this connection is gone" moment to hook here (the caller may want to keep the scope open past this object's lifetime, e.g. to construct a second SimulatedRemoteBackend against the same scope). Call closeConnection(cid) explicitly, or destroy server itself, when the simulated connection should be reclaimed.
| server | The RemoteServer instance to forward calls to. Borrowed, on the same terms as the constructor above. |
The backend also becomes cid's event receiver: it gives the server a ConnectionWriter for cid, replacing any writer the connection had, so a second backend on the same scope takes the events over.
| cid | Connection scope, as returned by server.openConnection(). |
Definition at line 2876 of file remote.hpp.
|
inlineoverride |
Stops delivering events: the server may still post to the connection, and those envelopes are dropped.
Definition at line 2888 of file remote.hpp.
|
inlineoverride |
Registers the model type on the server and returns its assigned id.
Processed through RemoteServer::handleInline, which answers before it returns. The factory argument is ignored — model construction is delegated to the server's ModelRegistryFactory.
| typeId | String type-id sent in the register message. |
| std::runtime_error | if the server replies with an error. |
Definition at line 2908 of file remote.hpp.
|
inlineoverride |
Registers the model type on the server, carrying contextKey across the wire so the server's RemoteServer::LogProvider (if configured) can attach an action log to the instance it creates.
factory is still ignored — model construction is delegated to the server's ModelRegistryFactory, same as registerModel().
| typeId | String type-id sent in the register message. |
| contextKey | Stable identity of the new instance; empty if none. |
| std::runtime_error | if the server replies with an error. |
Definition at line 2924 of file remote.hpp.
|
inlineoverride |
Acquires an instance on the server for request and settles the returned Completion before returning.
Each shape of BindRequest is one envelope, processed through RemoteServer::handleInline on the calling thread: a private register, a shared register (register-or-attach), or an attach that re-points from current in one request, so a re-pointing client cannot lose its slot to LimitPolicy::maxLiveModels between releasing the old instance and acquiring the new one. An empty primary with a live current releases it first and binds a private instance.
| request | Owning bind request; moved from. |
| cbExec | Executor the continuation is delivered on. Borrowed: it must outlive the returned Completion. |
Definition at line 2952 of file remote.hpp.
|
inlineoverride |
Records the owner every verb is called from.
| owner | The caller's owner. |
Definition at line 2967 of file remote.hpp.
|
inlineoverride |
Files a live server-side instance under primary.
| mid | Live instance to promote. |
| typeId | Model type id. |
| primary | Canonical string encoding of the key to file it under. |
Definition at line 2973 of file remote.hpp.
|
inlineoverride |
Asks the server for the live shared primary keys of typeId.
| typeId | String type-id to enumerate. |
| std::runtime_error | if the server replies with an error. |
Definition at line 2988 of file remote.hpp.
|
inlineoverride |
Deregisters the model on the server. Processed inline.
Carries this backend's own ConnectionId, so a shared instance's attach count is decremented against this backend's scope entry — never a different connection's — exactly as a real transport's deregister does (backend.md, "Connection scopes").
| mid | Id of the model to deregister. |
Definition at line 3026 of file remote.hpp.
|
inline |
Sends a "hello" envelope to the server and classifies its reply.
Processed inline on the calling thread via RemoteServer::handleInline, same as registerModel/deregisterModel. Intended to be called once, typically right after construction and before any registerModel/execute call — nothing enforces that ordering.
| std::runtime_error | if the server explicitly rejects the version (e.g. "protocol version unsupported"). |
Definition at line 3045 of file remote.hpp.
|
inlinenodiscard |
Fetches the server's {actionType: schema} document for typeId.
Sends a "schemas" envelope over the same synchronous control path as registerModel/negotiateProtocolVersion (handleInline), carrying the current session so an authorizing server can refuse. Opt-in in the same sense negotiateProtocolVersion() is: nothing calls it for you.
The document is what a client that is not linked against the model's C++ needs — each action's properties, required array, form metadata, and its x-payloadFingerprint/x-payloadShape. A client that is linked against it can compare that fingerprint against its own morph::model::payloadFingerprint<A>() to detect a build skew.
| typeId | Model type id to describe. |
| std::runtime_error | if the server replies err (e.g. "unauthorized", or "unknown envelope kind: schemas" from a server predating this kind). |
Definition at line 3068 of file remote.hpp.
|
inlineoverride |
Serialises the action, sends it to the server, and returns a Completion.
The Completion resolves when the server's reply is received and deserialized. Callbacks are posted via cbExec. The session attached to the call (via Bridge::setDefaultSession() or the per-call API) is serialised into the envelope.
| mid | Target model id on the server. |
| call | Bundled action; serializeAction and deserializeResult are used. |
| cbExec | Executor for delivering the completion callbacks. |
Definition at line 3090 of file remote.hpp.
|
inlineoverride |
No-op — models live in RemoteServer, not locally.
Definition at line 3139 of file remote.hpp.
|
inlineoverride |
Resolves every still-pending completion this backend produced with exc.
| exc | Exception delivered to every pending completion's error sink. |
Definition at line 3143 of file remote.hpp.
|
inlineoverride |
Installs the handler each server-initiated event is posted to. See IBackend::setEventHandler.
Only a backend scoped to a connection (the ConnectionId constructor) receives events; an unscoped one has no connection to post to. Events are posted to exec in the order the server posted them. An event envelope is recognised by its kind, so it never settles a call.
| handler | Callable posted to exec once per event. Pass nullptr to clear. |
| exec | Executor the handler is posted to. Borrowed: it must outlive the installation. May be null only when handler is. |
Definition at line 3165 of file remote.hpp.
|
inlineoverride |
Installs the session stamped onto every control envelope this backend subsequently builds (register, registerShared, attach, assign, deregister). See IBackend::setSession.
| session | Session to stamp; typically pushed by Bridge::setDefaultSession(). |
Definition at line 3176 of file remote.hpp.