Event Driven Communications (EDC) w/ WebSockets
EDC-WS Server/Clients
Is a server-clinet pakage that uses websockets to enable EDC.
Examples:
What is The Event Driven Communications (EDC) Protocol?
Is a JSON based communications protocol that allows for the communication of events while enabling the sharing of common data between a chain of events.
The concept that one event is the cause of a new event is a first class citizen in the EDC protocol. This allows for the logical grouping of events based on the cause-effect chain by tie together UUIDs. In additions, a chain of events logically share data that is common to each event in the chain. This allows the detail of the events to live seperate from the shared chain data.
Note: Acknowledge has a few nuances and controls if the
sendEvent()
resolves instantly or waits for a reply. If"acknowledge": true
then the promise will reslove after a valid reply, or reject after a timeout | Error Event See this for more on Acknowledge
Event Chain
|-----------------------------------------|
| shared data |
| |event-1|-->|event-2|-->|event-3| |
| | |
| |-->|event-N| |
|-----------------------------------------|
Examples
Server initialization
server.onEvent'event-type', server.onAck = server.onError =
Send an Event (Server)
try catch e
Note: if the
cause
Event was set to"acknowledge": false
then noAckedErrorEvent
orTimeoutError
could be thrown.
Client initilization
client.onEvent'event-type', sync cause, reply client.onAck = client.onError =
Send an Event (Client)
try catch e
Note: if the
cause
Event was set to"acknowledge": false
then noAckedErrorEvent
orTimeoutError
could be thrown.
Create a new Event()
from a cause: Event
// event.trigger === cause.id// event.shared === cause.shared
To match any event use '*'
as the event type in the onEvent()
function
// This will match any event. But the server|client will first try to match the event to a named one.server.onEvent'*',
Table of Contents
- Event Driven Communications (EDC) w/ WebSockets
Event Driven Communications (EDC) Components
Event
An Event is a JSON object defined as
Note:
"type":
"error"
and"acknowledgement"
are reserved for Error Event and Acknowledgement Event respectivley
Acknowledgement Event
Error Event
Error Event Details
The "details"
of the error event MUST include
-
"cn"
the common name of the error -
"code"
the number for the error -
"message"
the message to help understand the error -
"failed"
the string form of the failed event -
"data"
this field is allowed for any additional information about the error.
details:
Fields
edc
The version of the EDC protocoll
"edc": "1.0"
type
The type field represent the event type. It can be any string except "error"
and "acknowldegement"
which are reserved.
Examples:
"type": "mouse-moved"
"type": "transcripted"
"type": "request-action"
"type": "initiate-action"
id
The id field is a UUID and MUST be unique for all events
trigger
The trigger is set to the event that triggered the new event. new event.trigger = cause.id
The concept is meant to build a chain of events with events
becoming the cuase
of new events
. An event
is not limited to causing only a linear chain. It is possible for one cause
to trigger multiple events
. cause --> event1 & event2
acknowledge
If an event is sent with the "acknowledge": true
flag then the recieving system MUST reply with an event
, error
, or acknowledgement
with the trigger
field set to the id
of the sent event. Multiple replies of different events is allowed.
Example:
Request
A --> B
Responses
B --> A Ack Event
-- Or --
Error Event
-- Or --
Responding Event
details
The details is any JSON object and would hold the details for the OCCURING event. It is not inteded to be used for shared
properties that relate to the chain of events.
shared
The shared property is any JSON object. It is inteded to be used as a property that a chain of events
share in common.
When an event is triggered
by a cause
then it SHOULD set the trigger
to the cause.id
and copy the cause.shared
data to the new event.shared
. The shared data is not immutable and can evolve.
Examples would include a connection-Id that events share incommon, a call-Id for a phone call, a survey-Id, or a start time for a chain of events
.
A --> B
B --> A// Note the shared data is copied
A --> B// Note that the shared.step was increased
failed
Is only used with the "type": "error"
event. It MUST be a string copy of the event that triggered the error
Acknowledge and Flow
The requirement that "acknowledge": true
event MUST have a reply leads to two thrown errors AckedErrorEvent
and TimeoutError
. In addition, "acknowledge": false
events are asynchronous even if await
is used. This is because the promise will resolve instantly on the sendEvent()
as Promise<undefined>
.
TimeoutError
The TimeoutError
is thrown on "acknowledge": true
if no non-error reply is recived before the after client/server timeout is reached. Since the "acknowledge": true
events expects a reply and it is not possible to wait forever it is logical that there must be a timeout and that it would be a error by the system.
AckedErrorEvent
The AckedErrorEvent
is throw on "acknowledge": true
event if an event of type "error"
is recieved in response to the sent event. The motivation for this is to allow the handling of events that were expected or NEEDED to be successful in order to continue.
Multiple Synchronous Events
Acknowledge is key in sending multiple synchronous events in which the order of recieval matters. If event A
must be before event B
, then event A
should be sent with "acknowledge": true
this would gurantee an acknowledging reply that A
was recieved and that B
could now be sent. This would be true for any length of synchronous dependant events. A
before B
, B
before C
, C
before D
, etc.... [A, B, C, D, ...]
Generic Events
Event<T, K>
The type T
represents the type that details
is. While the type K
represents the type that the shared
property is.
ErrorEvent
The type T
for the ErrorEvent represents the type of error.details.data
Registering Routes
In the hopes of staying organized it is possible to register event-routes in seperate files.
Each route file would have to export an eventType
string and a handler
function
The file sturcture would look something like bellow:
src/|-- main.ts |----routes/ |-- index.ts |-- route-1.ts |-- route-2.ts |-- route-3.ts
index.ts
route-1.ts
main.ts
server.registerroutes
Note:
register()
will add all event routes that are exported in the array that is in thesrc/routes/index.ts
Further Organize
src/|-- main.ts |-----routes/ |-- index.ts |-- route-1.ts |-- route-2.ts |-- route-3.ts |-----sub/ |-- index.ts |-- sub-route-1.ts |-- sub-route-2.ts
src/routes/sub/index.ts
src/routes/index.ts
It is possible to go to extreme depths using this, grouping common events together.