morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
morph::backend::SimulatedRemoteBackend Class Reference

IBackend adapter that routes all calls through a RemoteServer as wire Envelope messages. More...

#include <remote.hpp>

Inheritance diagram for morph::backend::SimulatedRemoteBackend:

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.

Detailed Description

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.

Constructor & Destructor Documentation

◆ SimulatedRemoteBackend() [1/2]

morph::backend::SimulatedRemoteBackend::SimulatedRemoteBackend ( RemoteServer & server)
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.

Parameters
serverThe 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.

◆ SimulatedRemoteBackend() [2/2]

morph::backend::SimulatedRemoteBackend::SimulatedRemoteBackend ( RemoteServer & server,
ConnectionId cid )
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.

Parameters
serverThe 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.

Parameters
cidConnection scope, as returned by server.openConnection().

Definition at line 2876 of file remote.hpp.

◆ ~SimulatedRemoteBackend()

morph::backend::SimulatedRemoteBackend::~SimulatedRemoteBackend ( )
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.

Member Function Documentation

◆ registerModel()

::morph::exec::detail::ModelId morph::backend::SimulatedRemoteBackend::registerModel ( const std::string & typeId,
std::function< std::unique_ptr<::morph::model::detail::IModelHolder >()>  )
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.

Parameters
typeIdString type-id sent in the register message.
Returns
ModelId assigned by the server.
Exceptions
std::runtime_errorif the server replies with an error.

Definition at line 2908 of file remote.hpp.

◆ registerModelWithContext()

::morph::exec::detail::ModelId morph::backend::SimulatedRemoteBackend::registerModelWithContext ( const std::string & typeId,
std::function< std::unique_ptr<::morph::model::detail::IModelHolder >()> ,
std::string_view contextKey )
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().

Parameters
typeIdString type-id sent in the register message.
contextKeyStable identity of the new instance; empty if none.
Returns
ModelId assigned by the server.
Exceptions
std::runtime_errorif the server replies with an error.

Definition at line 2924 of file remote.hpp.

◆ bindModel()

::morph::async::Completion<::morph::exec::detail::ModelId > morph::backend::SimulatedRemoteBackend::bindModel ( detail::BindRequest request,
::morph::exec::IExecutor & cbExec )
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.

Parameters
requestOwning bind request; moved from.
cbExecExecutor the continuation is delivered on. Borrowed: it must outlive the returned Completion.
Returns
A settled Completion: the bound id, or the server's refusal as a std::runtime_error.

Definition at line 2952 of file remote.hpp.

◆ setOwner()

void morph::backend::SimulatedRemoteBackend::setOwner ( const ::morph::exec::detail::OwnerAffinity & owner)
inlineoverride

Records the owner every verb is called from.

Parameters
ownerThe caller's owner.

Definition at line 2967 of file remote.hpp.

◆ assignPrimary()

void morph::backend::SimulatedRemoteBackend::assignPrimary ( ::morph::exec::detail::ModelId mid,
const std::string & typeId,
std::string_view primary )
inlineoverride

Files a live server-side instance under primary.

Parameters
midLive instance to promote.
typeIdModel type id.
primaryCanonical string encoding of the key to file it under.

Definition at line 2973 of file remote.hpp.

◆ listInstances()

std::vector< std::string > morph::backend::SimulatedRemoteBackend::listInstances ( const std::string & typeId)
inlineoverride

Asks the server for the live shared primary keys of typeId.

Parameters
typeIdString type-id to enumerate.
Returns
Canonical key strings of the live shared instances.
Exceptions
std::runtime_errorif the server replies with an error.

Definition at line 2988 of file remote.hpp.

◆ deregisterModel()

void morph::backend::SimulatedRemoteBackend::deregisterModel ( ::morph::exec::detail::ModelId mid)
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").

Parameters
midId of the model to deregister.

Definition at line 3026 of file remote.hpp.

◆ negotiateProtocolVersion()

::morph::wire::ProtocolNegotiationResult morph::backend::SimulatedRemoteBackend::negotiateProtocolVersion ( )
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.

Returns
Negotiated if the server accepted kProtocolVersion; LegacyPeer if the server does not understand "hello" (an un-upgraded RemoteServer).
Exceptions
std::runtime_errorif the server explicitly rejects the version (e.g. "protocol version unsupported").

Definition at line 3045 of file remote.hpp.

◆ fetchActionSchemas()

std::string morph::backend::SimulatedRemoteBackend::fetchActionSchemas ( std::string typeId)
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.

Parameters
typeIdModel type id to describe.
Returns
The raw {actionType: schema} JSON document.
Exceptions
std::runtime_errorif 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.

◆ execute()

::morph::async::Completion< std::shared_ptr< void > > morph::backend::SimulatedRemoteBackend::execute ( ::morph::exec::detail::ModelId mid,
detail::ActionCall call,
::morph::exec::IExecutor * cbExec )
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.

Parameters
midTarget model id on the server.
callBundled action; serializeAction and deserializeResult are used.
cbExecExecutor for delivering the completion callbacks.
Returns
Completion that resolves with the deserialized result or an error.

Definition at line 3090 of file remote.hpp.

◆ notifyBackendChanged()

void morph::backend::SimulatedRemoteBackend::notifyBackendChanged ( )
inlineoverride

No-op — models live in RemoteServer, not locally.

Definition at line 3139 of file remote.hpp.

◆ cancelPending()

void morph::backend::SimulatedRemoteBackend::cancelPending ( const std::exception_ptr & exc)
inlineoverride

Resolves every still-pending completion this backend produced with exc.

Parameters
excException delivered to every pending completion's error sink.

Definition at line 3143 of file remote.hpp.

◆ setEventHandler()

void morph::backend::SimulatedRemoteBackend::setEventHandler ( std::function< void(::morph::wire::EventBody)> handler,
::morph::exec::IExecutor * exec )
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.

Parameters
handlerCallable posted to exec once per event. Pass nullptr to clear.
execExecutor 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.

◆ setSession()

void morph::backend::SimulatedRemoteBackend::setSession ( ::morph::session::Context session)
inlineoverride

Installs the session stamped onto every control envelope this backend subsequently builds (register, registerShared, attach, assign, deregister). See IBackend::setSession.

Parameters
sessionSession to stamp; typically pushed by Bridge::setDefaultSession().

Definition at line 3176 of file remote.hpp.


The documentation for this class was generated from the following file: