Some callback interface
may be registered via a new
EventRegister()
method - similar to ServiceRegister()
- on both TSQLRestClient
and TSQLRestServer
sides.
In fact, a callback / event can be seen as a service, but in the reverse order:
from server to client.
Those interface
shall have methods with no result, i.e.
defined only as procedure
, never as function
: they
are meant to define events (or messages), not actual request-response
calls.
Due to this stateless implementation design, events will be
executed on the server side asynchronously: in the server code,
interface
method calls will be added to an internal FIFO, and
return immediately, without waiting for the client to be notified.
Then the clients will retrieve and handle notifications, at their own pace.
Clients needing to receive those messages will call an overloaded
EventRegister()
method, with an implementation class
corresponding to one of the server-side registered interface
: this
will implement a strong and KISS publish / subscribe pattern. The
interface
will define the so-called "topics" to be published.
Over HTTP, two client-side implementation modes are possible:
- Polling from client using a
WM_TIMER
to maintain an user-friendly heart-beat (e.g. 500 ms), and retrieve all pending events (as JSON messages); - Lock-and-wait request, similar to the Comet implementations.
In fact, both implementation modes may coexist: IMHO the lock-and-wait request may trigger a dedicated polling request. It is up to the client to add a lock-and-wait channel if its reaction time does matter, or if the heart-beat period is problematic.
TSQLRest
callback internal methods will be abstract,
knowing nothing about polling or the underneath communication used.
We will try to code the most generic implementation, allowing polling and
lock-and-wait for HTTP, but certainly some dedicated mechanism for other
protocols (in-process, GDI, named pipes).
The mORMot architecture was designed to be truly RESTful,
without the necessity to mimic HTTP, e.g. using its headers to transmit data,
cookies for session handling or WebSockets for push emulation. The
framework also implements direct in-process, GDI messages and named pipes
communications. In fact, since GDI messages are two-way communications, we may
implement a direct callback feature (via a simple PostMessage
API
call), with no polling; and maybe change the named pipe mode to
duplex, or allow direct callback event for in-process/stand alone
access.
So we should never be stuck to one implementation, but open to alternatives,
and able to use the fastest mean of communication, depending on the
transmission protocol involved. In the future, the HTTP part may use
WebSockets, but it is currently not
compatible with the http.sys kernel-mode server provided by Windows, and
blocked by some packet inspectors / antivirus, since its content is not valid
HTTP.
Since calls are added in a server-side FIFO, it could be the root of proper
off-line synchronization of multiple clients: if a client is disconnected from
the server, all future events will be stacked on the server side, and sent on
the next available connection, to be replayed on the client side.
We may therefore consider using not only memory, but also an ACID database to
handle the message queue - e.g. via a dedicated TSQLRecord
-based
virtual table.
As we already stated in the beginning of this article, such a publish /
subscribe pattern would also benefit on the server side.
At data persistence level, we may, for instance, add a dedicated
IORMEvent interface
to the
TSQLRestServer
instance, publishing all CRUD operations of
the ORM, directly from its core (for both internal and external DB engines), so
that Event Sourcing features would be available to any number of
subscribers, even with on-the-fly registration. Generic per-table consolidation
or backup/replication features may be therefore be activated on need.
At application level, you may easily add external gateways
(like a SOAP service or some HTML/RSS content), or integrate authenticated
third-party components.
At domain level, it could be used to communicate between
domain objects, in an Event Collaboration pattern, e.g. between
multiple processes or PCs.
Similarly, an integrated scheduler (like cron) could be made available on the
server side, with a dedicated threading model (not to interfere with
the client-server process).
A whole horizon of extensions to the framework... we are open to any proposals!
Our framework has all the needed pieces of code: interface
stubbing and interception, persistence of the messages via ORM, JSON
serialization, security (using regular Deny/Allow
methods), communication over several protocols...
So it would probably be the next feature to come, just after 1.17
release.
Stay tuned! Feedback / ideas are always welcome on our forum!