the collaborative update https://beans.flashii.net/test.html
Find a file
2025-09-01 18:07:47 +00:00
public Attempt at a Docker setup. 2025-09-01 04:34:47 +00:00
source Attempt at a Docker setup. 2025-09-01 04:34:47 +00:00
.editorconfig Added everything. 2025-03-29 04:58:01 +01:00
.gitattributes Added everything. 2025-03-29 04:58:01 +01:00
.gitignore Added everything. 2025-03-29 04:58:01 +01:00
beans.service systemd service 2025-09-01 05:01:13 +00:00
docker-compose.yml and a docker compose file 2025-09-01 04:50:21 +00:00
Dockerfile Attempt at a Docker setup. 2025-09-01 04:34:47 +00:00
dub.json Attempt at a Docker setup. 2025-09-01 04:34:47 +00:00
dub.selections.json Added everything. 2025-03-29 04:58:01 +01:00
LICENSE Added everything. 2025-03-29 04:58:01 +01:00
README.md I was in the mood to draw ASCII tables, so here's some shoddy protocol documentation. 2025-09-01 18:07:47 +00:00

april-fools-2025

stinky server thats probably really easy to break that shows peoples cursors in places this will surely not get annoying

Running

for development just running dub should do the trick with a dlang build environment, although script.js is hardcoded for beans.flashii.net

the following commands are how things are set up in prod, all run by root:

mkdir -p /opt/beans
curl -fsSL https://patchii.net/flashii/april-fools-2025/raw/branch/trunk/docker-compose.yml -o /opt/beans/docker-compose.yml
curl -fsSL https://patchii.net/flashii/april-fools-2025/raw/branch/trunk/beans.service -o /etc/systemd/system/beans.service
systemctl enable beans --now

and that ought to do it, dubiousness and all

Protocol

the protocol is also slightly documented in app.d, but here's a more thorough overview. also worth noting is that that all of this is going through an rfc6455 websocket transport using binary data frames.

it is an extremely rudimentary stateful protocol with a primary focus on being compact, seeing as a packet is sent on every mouse movement event.

in this protocol, the server takes the initiative to acknowledge that a client has connected. a client should not sent any packet until it has been assigned an connection id by the server.

Server to Client

S2C packets will always consist out of at least five bytes:

  • the first bit of the first byte is used to inform the client of the connection id it has been assigned by the server, this cannot be changed.
  • the rest of the first byte and the subsequent three bytes contain an unsigned 31-bit integer.
  • the fifth byte contains a flagset.
    • if 0x01 is set, the subsequent four bytes will contain the displayed user id for the pointer as an unsigned 32-bit integer. this differs from the connection id and can be set at will.
    • if 0x02 is set, the subsequent two bytes will contain the X position of the pointer as an unsigned 16-bit integer, starting from the left of the viewport.
    • if 0x04 is set, the subsequent two bytes will contain the Y position of the pointer as an unsigned 16-bit integer, starting from the top of the viewport.
    • if 0x08 is set, the subsequent three bytes will contain an RGB colour, with each byte representing each colour in that order.
    • if 0x10 is set, the pointer should be visible.
    • if 0x20 is set, the pointer is in a clicking state.
    • 0x40 and 0x80 are unused but the server will send broadcast their values if set.

a little visualisation table thingy inspired by the websocket RFC in case that made no sense:

   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-------------------------------------------------------------+
  |S|                                                             |
  |E|                     Unique Connection ID                    |
  |L|                             (4)                             |
  |F|                                                             |
  +-+-+-+-+-+-+-+-+-----------------------------------------------+
  |?|?|C|V|C|Y|X|U|                                               |
  |?|?|L|I|O| | |S|         User ID, if USRID flag is set         |
  |?|?|I|S|L|P|P|R|                       (4)                     |
  |?|?|C|I|O|O|O|I|                                               |
  |?|?|K|B|R|S|S|D|                                               |
  +-+-+-+-+-+-+-+-+-------------------------------+---------------+
  |    User ID    |     Pointer X Position, (2)   | Y Position,(2)|
  | continued ... |      if X POS flag is set     | if Y POS set  |
  +---------------+---------------+---------------+---------------+
  | Y Position    |    Red (1)    |   Green (1)   |    Blue (1)   |
  | continued ... |             if COLOR flag is set              |
  +---------------+---------------+---------------+---------------+

hopefully the combination of the two will make some sense!

Client to Server

C2S packets have an entirely variable size, technically an empty binary data frame is still considered a valid packet. empty packets will be treated the same as if a single 0x00 byte was sent.

  • the first byte contains a flagset that determines the layout of the rest of the packet.
    • if any of the upper four bits (0xF0) are set, they will be used as a mask for the subsequent byte. if this area is non-zero, the byte MUST be present.
    • if 0x01 is set, the subsequent four bytes will contain the desired display user id as an unsigned 32-bit integer.
    • if 0x02 is set, the subsequent two bytes will contain the X position of the pointer as an unsigned 16-bit integer, starting from the left of the viewport.
    • if 0x04 is set, the subsequent two bytes will contain the Y position of the pointer as an unsigned 16-bit integer, starting from the top of the viewport.
    • if 0x08 is set, the subsequent three bytes will contain an RGB colour, with each byte representing each colour in that order.
  • the second byte, present if any of the upper four bits (0xF0) are set of the previous byte are set, contains new values for the connection state such as visibility and click state.
    • the lower four bits (0x0F) cannot be overwritten by the client.
    • if 0x10 is set, the pointer should be visible.
    • if 0x20 is set, the pointer is in a clicking state.
    • 0x40 and 0x80 are unused but the server will send broadcast their values if set.

another little visualisation table thingy:

   0                   1                   2                   3
   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------------------------+
  |U|X|Y|C|?|?|C|V|?|?|C|V|0|0|0|0|                               |
  |S| | |O|?|?|L|S|?|?|O|I|0|0|0|0| User ID, if USRID flag is set |
  |R|P|P|L|M|M|M|M|?|?|L|S|0|0|0|0|              (4)              |
  |I|O|O|O|S|S|S|S|?|?|O|I|0|0|0|0|                               |
  |D|S|S|R|K|K|K|K|?|?|R|B|0|0|0|0|                               |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------------------------+
  |            User ID            |     Pointer X Position, (2)   |
  |         continued ...         |      if X POS flag is set     |
  +-------------------------------+---------------+---------------+
  |     Pointer Y Position, (2)   |    Red (1)    |   Green (1)   |
  |      if Y POS flag is set     |      if COLOR flag is set     |
  +---------------+---------------+---------------+---------------+
  |    Blue (1)   |
  | if COLOR set  |
  +---------------+

unfortunately that one doesn't have a number of bytes that's a multiple of four. sadness.