From 3e785dd9cb9212ec396467f39b871501e68dbf6e Mon Sep 17 00:00:00 2001
From: Max Kuznetsov
Date: Thu, 16 May 2024 20:45:32 +0300
Subject: [PATCH 1/3] New: add basic docs and guide
---
README.md | 179 ++++++++++++++++++++++++++++++++++++++++++++++++-
docs/README.md | 159 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 336 insertions(+), 2 deletions(-)
create mode 100644 docs/README.md
diff --git a/README.md b/README.md
index 2c625fc..b902b03 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,177 @@
-# excalidraw-ws-go
-WebSocket Server on Go for managing shared session for Excalidraw
+
+
Excaliroom
+ A simple WebSocket server for collaborative drawing with Excalidraw.
+
+
+---
+
+>[!WARNING]
+> Current project major version is _**0.x.**_ It means that the project is still in development and may have breaking changes in the future.
+
+This is an _**unofficial**_ implementation of the [Excalidraw](https://excalidraw.com/) collaboration server.
+It uses WebSockets to communicate between clients and broadcast the changes to all connected clients.
+
+## Table of Contents
+
+- [Features](#features)
+- [Configuration](#configuration)
+ - [JWT and Board URLs](#jwt-and-board-urls)
+ - [Storage](#storage)
+- [Installation](#installation)
+ - [Configuration](#configuration)
+ - [Docker](#docker)
+ - [Docker Compose](#docker-compose)
+ - [Build Go binary](#build-go-binary)
+- [How to use](#how-to-use)
+- [Contributing](#contributing)
+- [License](#license)
+
+## Features
+
+- Real-time collaboration with multiple users
+- Authentication and validation with JWT
+- Configurable storage (currently only supports **in-memory** storage)
+
+## Configuration
+
+The server uses **_.yaml_** configuration file to set up.
+You can find an example configuration file [here](./config-example.yaml).
+
+```yaml
+apps:
+ log_level: "DEBUG"
+ rest:
+ port: 8080
+ validation:
+ jwt_header_name: ""
+ jwt_validation_url: ""
+ board_validation_url: ""
+
+storage:
+ users:
+ type: "in-memory"
+ rooms:
+ type: "in-memory"
+```
+
+Currently, the `apps` section contains the following configurations:
+- `log_level`: The log level of the server. It can be one of the following: `DEBUG`, `INFO` (More levels will be added in the future).
+- `rest`: The REST API configuration.
+ - `port`: The port of the REST API.
+ - `validation`: The JWT validation configuration.
+ - `jwt_header_name`: The name of the header, in which `Excaliroom` will set the JWT token from client.
+ - `jwt_validation_url`: The URL to validate the JWT token, which will be used to authenticate the user.
+ - `board_validation_url`: The URL to validate the access to the board with the JWT token.
+- `storage`: The storage configuration.
+ - `users`: The user storage configuration.
+ - `type`: The type of the storage. Currently, only `in-memory` is supported.
+ - `rooms`: The room storage configuration.
+ - `type`: The type of the storage. Currently, only `in-memory` is supported.
+
+### JWT and Board URLs
+
+To authenticate the user and validate the access to the board, you need to provide the URLs in the configuration file.
+
+The `Excaliroom` server requires 2 URLs:
+- `jwt_validation_url`: The URL to validate the JWT token. The `Excaliroom` server will send a `GET` request to this URL with the JWT token in the header. The server should return `200 OK` if the token is valid and the following JSON response:
+ ```json
+ {
+ "id": ""
+ }
+ ```
+ The `id` will be used to identify the user.
+
+
+- `board_validation_url`: The URL to validate the access to the board with the JWT token. The `Excaliroom` server will send a `GET` request to this URL with the JWT token in the header. The server should return `200 OK`.
+
+### Storage
+
+Currently, the server only supports `in-memory` storage for users and rooms.
+
+## Installation
+
+### Docker
+
+>[!WARNING]
+> Currently, the Docker image from the Docker Hub is only available for **linux/amd64** platform.
+>
+> If you use another platform (e.g., **linux/arm64**), you can provide `--platform` flag to the `docker pull` command.
+
+1. You can pull the Docker image from the Docker Hub:
+
+ ```bash
+ docker pull icerzack/excaliroom:latest
+ ```
+
+ Then, you can run the Docker container with the following command:
+
+ ```bash
+ docker run -d -p 8080:8080 -v path/to/config.yaml:/config.yaml -e CONFIG_PATH="/config.yaml" icerzack/excaliroom:latest
+ ```
+
+2. You can build the Docker image by yourself with the following command:
+
+ ```bash
+ docker build -f build/Dockerfile -e CONFIG_PATH="path/to/config.yaml" -t excaliroom .
+ ```
+
+ Then, you can run the Docker container with the following command:
+
+ ```bash
+ docker run -d -p 8080:8080 -v path/to/config.yaml:/config.yaml -e CONFIG_PATH="/config.yaml" excaliroom
+ ```
+
+### Docker Compose
+
+You can use Docker Compose to run the server with the following `docker-compose.yml` file:
+
+```yaml
+services:
+ app:
+ image: icerzack/excaliroom:latest
+ environment:
+ - CONFIG_PATH=config.yaml
+ ports:
+ - "8080:8080"
+ volumes:
+ - ./config.yaml:/config.yaml
+```
+
+Then, you can run the server with the following command:
+
+```bash
+docker-compose up -d
+```
+
+### Build Go binary
+
+Set the environment variable `CONFIG_PATH` to the path of the configuration file and build the binary:
+
+```bash
+export CONFIG_PATH="path/to/config.yaml"
+go build -o excaliroom main.go
+```
+
+Then, you can run the binary:
+
+```bash
+./excaliroom
+```
+
+## How to use
+
+Check the [docs](./docs) directory of this repo for the guides on how to use and integrate the `Excaliroom` server with your JavaScript application.
+
+## Contributing
+
+If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
+
+1. Fork the Project
+2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
+3. Commit your Changes (git commit -m 'Add some AmazingFeature')
+4. Push to the Branch (git push origin feature/AmazingFeature)
+5. Open a Pull Request
+
+## License
+
+This project is licensed under the Apache License 2.0 - see the [LICENSE](./LICENSE) file for details.
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..c8ea2de
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,159 @@
+# How to use Excaliroom
+
+This directory contains guidance for using and integrating the `Excaliroom` server with your existing project.
+
+## Table of contents
+
+- [Getting started](#getting-started)
+ - [Pre-requisites](#pre-requisites)
+ - [How Excaliroom works](#how-excaliroom-works)
+- [API reference](#api-reference)
+- [Examples](#examples)
+- [FAQ](#faq)
+
+## Getting started
+
+### Pre-requisites
+
+First of all, it is implied that you have `Backend` and `Frontend` applications:
+- `Backend`: It may contain some of your business logic, and it may be written in any programming language.
+- `Frontend`: It is your JavaScript application that will communicate with the `Excaliroom` server.
+
+The `Excaliroom` WebSocket server is only responsible for handling real-time communication between your clients on the same board.
+It does not store any data (except for the current state of the board and connected clients) and does not have any business logic.
+
+However, `Excaliroom` server requires a `JWT` token to authenticate and authorize users.
+The `JWT` token should be:
+- Validated by your `Backend` application.
+- Provided by your `Frontend` application.
+
+The `Excaliroom` server also requires a URL to validate user access to the board.
+
+The neccessary URLs for `JWT` validation and board validation should be provided in the `Excaliroom` server configuration file.
+See the [Configuration](../README.md#configuration) section for more information.
+
+### How Excaliroom works
+
+The `Excaliroom` server uses WebSockets to communicate between clients and broadcast the changes to all connected clients.
+It is a real-time collaboration server that allows multiple users to draw on the same board.
+
+Currently, the sharing mechanism is simple:
+- When a first user connects to the `Excaliroom`, it sends the current state of the board to the WebSocket server. This happens only if the user is the first one to connect to the board. After receiving the board state, the `Excaliroom` creates a new room and stores the board state and the user in the room.
+- With the next user connecting to the same board, the `Excaliroom` adds the user to the existing room and broadcasts the current room state to all connected users.
+- By default, no one can modify the board state. `Excaliroom` can handle board updates only from the _**Leader**_ of the room. By default, after creating a new room, no one is the _**Leader**_ of the room. The _**Leader**_ is the user who can modify the board state. The _**Leader**_ can be dropped by the _**Leader**_ itself. If the _**Leader**_ leaves the room, the _**Leader**_ role is reset so anyone can become the _**Leader**_.
+- When the _**Leader**_ sends a new board state to the `Excaliroom`, the server broadcasts the new board state to all connected users. In other words, the _**Leader**_ is the only user who can modify the board state, while all other users can only view the board state.
+- When the last user leaves the room, the room is deleted from the `Excaliroom`.
+
+The `Excaliroom` sends and receives messages in JSON format. The message format is described in the [API reference](#api-reference) section.
+
+## API reference
+
+Each JSON message contains `event` field that describes the type of the message. The `event` field can have the following values:
+- `connect`: The message is sent by `Frontend` when the user requests to connect to the board.
+- `userConnected`: The message is sent by `Excaliroom` to all connected users when a new user connects to the board.
+- `userDisconnected`: The message is sent by `Excaliroom` to all connected users when a user disconnects from the board.
+- `setLeader`: The message is sent by `Frontend` when the user requests to become the _**Leader**_ of the room and sent by `Excaliroom` to all connected users when the _**Leader**_ changes.
+- `newData`: The message is sent by `Frontend` when the user sends new board data to the server and sent by `Excaliroom` to all connected users when the _**Leader**_ sends new board data.
+
+The JSON message format is as follows:
+1. `connect` event:
+```json
+{
+ "event": "connect",
+ "board_id": "",
+ "jwt": ""
+}
+```
+- `board_id`: The unique identifier of the board.
+- `jwt`: The JWT token that is used to authenticate and authorize the user. The `Excaliroom` server will use `jwt_validation_url` to validate the JWT token on your `Backend` and `jwt_header_name` to set the JWT to the header. After validating the JWT token, the `Excaliroom` server will use `board_validation_url` to validate the access to the board. See the [Configuration](../README.md#jwt-and-board-urls) section for more information.
+
+2. `userConnected` event:
+```json
+{
+ "event": "userConnected",
+ "user_ids": ["", "", ...],
+ "leader_id": ""
+}
+```
+- `user_ids`: The list of user identifiers that are connected to the board.
+- `leader_id`: The identifier of the _**Leader**_ of the room. If the _**Leader**_ is not set, the `leader_id` will be `0`.
+
+3. `userDisconnected` event:
+```json
+{
+ "event": "userDisconnected",
+ "user_ids": ["", "", ...],
+ "leader_id": ""
+}
+```
+- `user_ids`: The list of user identifiers that are connected to the board.
+- `leader_id`: The identifier of the _**Leader**_ of the room. If the _**Leader**_ is not set, the `leader_id` will be `0`.
+
+4. `setLeader` event (request):
+```json
+{
+ "event": "setLeader",
+ "board_id": "",
+ "jwt": ""
+}
+```
+- `board_id`: The unique identifier of the board.
+- `jwt`: The JWT token that is used to authenticate and authorize the user. The `Excaliroom` server will use `jwt_validation_url` to validate the JWT token on your `Backend` and `jwt_header_name` to set the JWT to the header. After validating the JWT token, the `Excaliroom` server will use `board_validation_url` to validate the access to the board. See the [Configuration](../README.md#jwt-and-board-urls) section for more information.
+
+5. `setLeader` event (response):
+```json
+{
+ "event": "setLeader",
+ "board_id": "",
+ "user_id": ""
+}
+```
+- `board_id`: The unique identifier of the board.
+- `user_id`: The identifier of the _**Leader**_ of the room.
+
+6. `newData` event (request):
+```json
+{
+ "event": "newData",
+ "board_id": "",
+ "jwt": "",
+ "data": {
+ "elements": "EXCALIDRAW_ELEMENTS_JSON",
+ "appState": "EXCALIDRAW_APP_STATE_JSON"
+ }
+}
+```
+- `board_id`: The unique identifier of the board.
+- `jwt`: The JWT token that is used to authenticate and authorize the user. The `Excaliroom` server will use `jwt_validation_url` to validate the JWT token on your `Backend` and `jwt_header_name` to set the JWT to the header. After validating the JWT token, the `Excaliroom` server will use `board_validation_url` to validate the access to the board. See the [Configuration](../README.md#jwt-and-board-urls) section for more information.
+- `data`: The board data that is sent by the _**Leader**_ of the room.
+ - `elements`: The JSON string of the Excalidraw `elements`.
+ - `appState`: The JSON string of the Excalidraw `appState`.
+
+See the [Excalidraw Docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/initialdata) documentation for more information.
+
+7. `newData` event (response):
+```json
+{
+ "event": "newData",
+ "board_id": "",
+ "data": {
+ "elements": "EXCALIDRAW_ELEMENTS_JSON",
+ "appState": "EXCALIDRAW_APP_STATE_JSON"
+ }
+}
+```
+- `board_id`: The unique identifier of the board.
+- `data`: The board data that is sent by the _**Leader**_ of the room.
+ - `elements`: The JSON string of the Excalidraw `elements`.
+ - `appState`: The JSON string of the Excalidraw `appState`.
+
+See the [Excalidraw Docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/initialdata) documentation for more information.
+
+## Examples
+
+_Later_
+
+## FAQ
+
+_Later_
+
From 6255d65baed9300a75fec4209442b9cffb280bfa Mon Sep 17 00:00:00 2001
From: Max Kuznetsov
Date: Thu, 16 May 2024 20:48:23 +0300
Subject: [PATCH 2/3] Fix: fix misprints
---
README.md | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/README.md b/README.md
index b902b03..8337367 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
Excaliroom
- A simple WebSocket server for collaborative drawing with Excalidraw.
+ A simple WebSocket server for collaborative drawing with Excalidraw
---
@@ -18,7 +18,6 @@ It uses WebSockets to communicate between clients and broadcast the changes to a
- [JWT and Board URLs](#jwt-and-board-urls)
- [Storage](#storage)
- [Installation](#installation)
- - [Configuration](#configuration)
- [Docker](#docker)
- [Docker Compose](#docker-compose)
- [Build Go binary](#build-go-binary)
From 3c26e3df2a802fb2074a7d8b7c13c2cbf8273b8e Mon Sep 17 00:00:00 2001
From: Max Kuznetsov
Date: Fri, 17 May 2024 17:04:41 +0300
Subject: [PATCH 3/3] Fix: fix ident for Configuration section
---
README.md | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 8337367..e75e13a 100644
--- a/README.md
+++ b/README.md
@@ -61,11 +61,12 @@ Currently, the `apps` section contains the following configurations:
- `jwt_header_name`: The name of the header, in which `Excaliroom` will set the JWT token from client.
- `jwt_validation_url`: The URL to validate the JWT token, which will be used to authenticate the user.
- `board_validation_url`: The URL to validate the access to the board with the JWT token.
-- `storage`: The storage configuration.
- - `users`: The user storage configuration.
- - `type`: The type of the storage. Currently, only `in-memory` is supported.
- - `rooms`: The room storage configuration.
- - `type`: The type of the storage. Currently, only `in-memory` is supported.
+
+The `storage` section contains the following configurations:
+- `users`: The user storage configuration. It specifies where the server will store the user data.
+ - `type`: The type of the storage. Currently, only `in-memory` is supported.
+- `rooms`: The room storage configuration. It specifies where the server will store the room data.
+ - `type`: The type of the storage. Currently, only `in-memory` is supported.
### JWT and Board URLs