LightningCreations / LightningLabsServer

1 stars 0 forks source link

WebSocket Support #4

Open kilbouri opened 3 months ago

kilbouri commented 3 months ago

The server should support WebSocket connections. Current requirements for this functionality are limited to broadcasting events to clients.

kilbouri commented 3 months ago

@rdrpenguin04 beyond server->client events, what else does the server need WebSocket support for?

rdrpenguin04 commented 3 months ago

The WebSocket connection should allow client->server sending as well (sending/editing/deleting messages, etc), in my opinion. That way it can reuse the WebSocket instead of needing to spin up a new connection.

Other than that, I think we may have more functionality later, but the kind of functionality I'm thinking of would be on a different WebSocket endpoint.

kilbouri commented 3 months ago

Makes sense. I'm rather inexperienced with WebSocket in general, but especially in Rust. When it comes to Rust, is there a crate/module you'd recommend for the server to use? In terms of events, we obviously need some way to "route" events to the appropriate panel (e.g. text chat). How do we plan to do this in a manner that enables modularity?

rdrpenguin04 commented 3 months ago

We would definitely use rocket_ws; I started figuring out how that would integrate locally. But in general, we'd have a /api/ws endpoint or similar that is the "one true" WebSocket connection.

I know there's a protocol for this kind of logic, but I don't remember what it is. The other option is a simple JSON API that mirrors database shifts. Idempotence is necessary and also trivial in this instance:

// From client:
{
    "id": "whatever-this-uuid-happ-enstoberight", // required
    "parent_id": "something", // required if adding
    "owner_id": "something", // if adding, defaults to the user sending
    "dacl_id": "something", // if adding, defaults to one named in the parent's dacl
    "ty": "message", // required, always
    "op": "create", // the fun one; can be "create", "update", or "delete". Not required unless deleting, but recommended.

    "message": "Stuff stuff." // And now, every field to be added or changed. For "delete", all others are ignored.
}
// From server:
{
    "id": "whatever-this-uuid-happ-enstoberight",
    "parent_id": "something",
    "owner_id": "something",
    "dacl_id": "something",
    "ty": "message",
    "op": "create", // same deal as above, but will always be sent

    "message": "Stuff stuff." // Every added or changed field will be sent; none will be sent for deletion.
}
kilbouri commented 3 months ago

I strongly dislike the names ty and op. We don't need to worry about 9 extra bytes, we're using JSON anyway. The DevEx of having them spelled out far outweighs the cost.

I would prefer a more event-driven style for our WebSocket connection, with payloads looking like

{
    "idempotency_token": "something",
    "event_type": "MESSAGE_SENT",
    "payload": {
        "$comment": "...id, parent_id, owner_id, dacl_id, content, etc."
    }
}

We would then have a definition somewhere for each event_type and its payload format. We could also consider a higher level protocol llike AMQP or MQTT.

kilbouri commented 3 months ago

Upon further discussion I think your example is better, as long as we make the following renames: ty -> type and op -> operation. Also I think op should not be optional, it adds uncertainty for no value.

rdrpenguin04 commented 3 months ago

Alright, I can make that work