Proof of Concept Minimal backend server & protocol to support collaborative edition of models based on Daga or Essential.
- TypeScript
- NodeJS
- WebSockets
- Model or Document: the model or document under edition.
- User: Any authenticate user connected to the system.
- Client: A program joining the colaborative editing experience serving a user. Provides the tooling for model edition.
- Model Respository. Central point to store models and to manage access permissions.
- Collaborative Session. Also known as Room or Space, a session created by an user (model owner) to invite others to collaborate in a model. A room is uniquely identified by a locator.
- Collaborative Sesion Server. Track changes and provides resources to allow collaboration. (this PoC) This piece serves as a broadcast service to avoid clients knowing each others and as a security checkpoint and model persistance in the long term.
- Alice shares a model on the Collaborative Sesion Server, opening a room for collaboration and provides a first version of the model.
- The tool provides a Room ID (or token/locator) that can be shared with other to innitiate collaboration.
- Alice share the token with friends to start the concurrent editing experience.
- Bob & Cris receives the code and open their editors (or join via URL).
- Now they share a synchronized view of the model.
- They edit concurently and CRDTs and Collaborative Session Server add the magic to distribute changes and keep things synchronized.
- Cris take a plane and goes offline, he keeps adding changes.
- Alice and Bob continues editing in paralel.
- When Cris recover connection, synchronizes work.
- Alice review it all, declares version 1 is good enough and closes the room.
- No more changes are allowed to Cris and Bob over version 1.
The protocol is described by the messages interchaged between the parties with the central Collaborative Sesion Server.
The messages have the following base form:
enum EsgrimaMessageType {
HELLO = 'HELO',
BYE = 'BYE',
CREATE = 'CREA',
CREATE_ACK = 'CACK',
ENROLL = 'ENRO',
ENROLL_ACK = 'EACK',
DELETE = 'DLTE',
ADD = 'ADD',
OK = 'OK'
ERROR = 'ERR',
}
interface EsgrimaMessage {
type: EsgrimaMessageType;
clientId: string;
userId: string;
ts: Date;
}
The types of message have the following meaning:
HELO
Connects a client.BYE
Disconnects a client.CREA
Creation request for a new room for collaboration.CACK
Confirmation of creation of the room providing a locator.ENRO
Enrolls a client into a room using a locator.EACK
Confirmation of enrollment of a client into a room.DLTE
Deletes a collaboration room.ADD
Adds a change to the model in a collaboration space.OK
Acknowledges that a message has been received successfully.ERR
Error returned by the server: AuthN, AuthZ, lack of space, malfunction, etc.
Describes the connection of a new client/user to the server. The version
indicates the version of the protocol supported for content negotiation. An optional token
can be provided to authenticate the userId.
interface HeloMessage extends Message {
type: EsgrimaMessageType.HELLO;
token?: string;
version: string;
}
Example:
{
type: 'HELO',
ts: '2024-03-25T14:06:01.23Z'
clientId: 'sa32jks093',
userId: 'u42',
version: '0.1'
}
Describes the closing of a session between client and server. This message doesn't remove rooms implicitly or explicitly.
export interface EsgrimaByeMessage extends EsgrimaMessage {
type: EsgrimaMessageType.BYE;
}
Example:
{
type: 'BYE',
ts: '2024-03-25T14:06:01.23Z'
clientId: 'sa32jks093',
userId: 'u42'
}
Describes the creation of a room for collaboration. It will be owned by the user creating it. Only owner or admintrators can delete a room.
This message may include an optional initialModel
which indicates the state of the model at the moment of the room's creation.
export interface EsgrimaCreateMessage extends EsgrimaMessage {
type: EsgrimaMessageType.CREATE;
initialModel?: DagaModel;
}
Example:
{
type: 'CREA',
ts: '2024-03-25T14:06:01.23Z',
clientId: 'sa32jks093',
userId: 'u42',
initialModel: {
// ...
}
}
Confirms the successful creation of a room in response to a CREA
message. This message includes the locator
of the room that has been created as well as a responseTo
field which contains the hash of the message it is responding to. The responseTo
field can be calculated in any way as long as it is consistent between client and server and distinctive across messages.
export interface EsgrimaCreateAckMessage extends EsgrimaMessage {
type: EsgrimaMessageType.CREATE_ACK;
responseTo: string;
locator: string;
}
Example:
{
type: 'CACK',
ts: '2024-03-25T14:06:01.23Z',
clientId: 'sa32jks093',
userId: 'u42',
responseTo: '08ada046e213ed9eeab06d0083a1b898f3dbafd390f87d4d1614b5ac88796e4a',
locator: 'ABC3456ZB'
}
Describes the enrollment of an user into a room via a locator.
export interface EsgrimaEnrollMessage extends EsgrimaMessage {
type: EsgrimaMessageType.ENROLL;
locator: string;
}
Example:
{
type: 'ENRO',
ts: '2024-03-25T14:06:01.23Z'
clientId: 'device34',
userId: 'u43',
locator: 'locatorABDC1234'
}
Confirms the successful enrollment of a user into a room in response to a ENRO
message. This message includes the locator
of the room that has been created.
This message can optionally include the initialModel
and a list of changes
so that the enrolled user can reconstruct the current state of the model, as well as a list of userIds
so that the enrolled user can know which other users are present in the room and an ownerId
so that the enrolled user can know which user is the owner of the room.
Similar to CACK
messages, EACK
messages include a responseTo
field which works in the same way.
export interface EsgrimaEnrollAckMessage extends EsgrimaMessage {
type: EsgrimaMessageType.ENROLL_ACK;
responseTo: string;
locator: string;
ownerId?: string;
initialModel?: DagaModel;
changes: ModelChange[];
userIds: string[];
}
Example:
{
type: 'EACK',
ts: '2024-03-25T14:06:01.23Z',
clientId: 'sa32jks093',
userId: 'u42',
responseTo: '08ada046e213ed9eeab06d0083a1b898f3dbafd390f87d4d1614b5ac88796e4a',
locator: 'ABC3456ZB',
ownerId: 'u43',
initialModel: {
// ...
},
changes: [
// ...
],
userIds: [
// ...
]
}
Describes the deletion of a room via a locator
.
export interface EsgrimaDeleteMessage extends EsgrimaMessage {
type: EsgrimaMessageType.DELETE;
locator: string;
}
Example:
{
type: 'DLTE',
ts: '2024-03-25T14:06:01.23Z'
clientId: 'sa32jks093',
userId: 'u42',
locator: 'locatorABDC1234'
}
Describes performing changes to the model in a room.
export interface EsgrimaAddMessage extends EsgrimaMessage {
type: EsgrimaMessageType.ADD;
locator: string;
payload: CollabActionSerialized;
}
Example:
{
type: 'ADD',
ts: '2024-03-25T14:06:01.23Z'
clientId: 'sa32jks093',
userId: 'u42',
locator: 'locatorABDC1234',
payload: {
// ...
}
}
Describes an acknowledgement that a message has been received correctly.
Similar to CACK
and EACK
messages, OK
messages include a responseTo
field which works in the same way.
export interface EsgrimaOkMessage extends EsgrimaMessage {
type: EsgrimaMessageType.OK;
responseTo: string;
}
Example:
{
type: 'OK',
ts: '2024-03-25T14:06:01.23Z'
clientId: 'sa32jks093',
userId: 'u42',
responseTo: '08ada046e213ed9eeab06d0083a1b898f3dbafd390f87d4d1614b5ac88796e4a'
}
Describes an error.
If an error occurs while processing a specific message, ERR
messages can include a responseTo
field which works in the same way as the responseTo
field of CACK
, EACK
and OK
messages.
export interface EsgrimaErrorMessage extends EsgrimaMessage {
type: EsgrimaMessageType.ERROR;
responseTo: string;
locator: string;
status: number;
description: string;
}
Example:
{
type: 'ERR',
ts: '2024-03-25T14:06:01.23Z'
clientId: 'sa32jks093',
userId: 'u42',
responseTo: '',
locator: 'locatorABDC1234',
status: '500',
description: 'Internal Server Error'
}
For connecting a client, a HELO
message is sent from the client to the server, to which the server responds with an OK
.
sequenceDiagram
participant Client
participant Server
Client ->> Server: HELO
Server ->> Client: OK
For disconnecting a client, a BYE
message is sent from the client to the server, which is then broadcast to the clients that share a room with the disconnected client. BYE
messages are responded with an OK
message.
sequenceDiagram
participant Client
participant Server
participant Other clients
Client ->> Server: BYE
Server ->> Client: OK
Server ->> Other clients: BYE
Other clients ->> Server: OK
For connecting a client, a CREA
message is sent from the client to the server, to which the server responds with an CACK
.
sequenceDiagram
participant Client
participant Server
Client ->> Server: CREA
Server ->> Client: CACK
For connecting a client, a ENRO
message is sent from the client to the server, to which the server responds with an EACK
. The ENRO
message is then broadcast to other clients, to which they respond with an OK
.
sequenceDiagram
participant Client
participant Server
participant Other clients
Client ->> Server: ENRO
Server ->> Client: EACK
Server ->> Other clients: ENRO
Other clients ->> Server: OK
For deleting a room, a DLTE
message is sent from the client to the server, which is then broadcast to the other clients in that room. DLTE
messages are responded with an OK
message.
sequenceDiagram
participant Client
participant Server
participant Other clients
Client ->> Server: DLTE
Server ->> Client: OK
Server ->> Other clients: DLTE
Other clients ->> Server: OK
For adding changes to the diagram in a room, an ADD
message is sent from the client to the server, which is then broadcast to the other clients in that room. ADD
messages are responded with an OK
message.
sequenceDiagram
participant Client
participant Server
participant Other clients
Client ->> Server: ADD
Server ->> Client: OK
Server ->> Other clients: ADD
Other clients ->> Server: OK
For informing the client of a server error, an ERR
message is sent. A response is not needed.
sequenceDiagram
participant Client
participant Server
Server ->> Client: ERR
For informing the server of a client error, an ERR
message is sent. A response is not needed.
sequenceDiagram
participant Client
participant Server
Client ->> Server: ERR
- Install dependencies with
npm i
. - Launch the server with
npm start
. - Open two tabs in a browser of
client.html
. - Log as Alice, create a room, send some changes.
- In the other tab, log as Bob, enroll into a room with a locator, see changes comming.
- Collaborate...
- Reconnection pending
- AuthN & AuthZ
- Hibernate space state on innactivity
- Rehidrate on connection
Unlicensed. © 2024 Metadev.