Skip to content

Commit 550fab6

Browse files
authored
New: add basic docs and guide (#3)
1 parent 9b66a29 commit 550fab6

File tree

2 files changed

+336
-2
lines changed

2 files changed

+336
-2
lines changed

README.md

Lines changed: 177 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,177 @@
1-
# excalidraw-ws-go
2-
WebSocket Server on Go for managing shared session for Excalidraw
1+
<p align="center">
2+
<h1 align="center">Excaliroom</h1>
3+
<p align="center">A simple WebSocket server for collaborative drawing with Excalidraw</p>
4+
</p>
5+
6+
---
7+
8+
>[!WARNING]
9+
> Current project major version is _**0.x.**_ It means that the project is still in development and may have breaking changes in the future.
10+
11+
This is an _**unofficial**_ implementation of the [Excalidraw](https://excalidraw.com/) collaboration server.
12+
It uses WebSockets to communicate between clients and broadcast the changes to all connected clients.
13+
14+
## Table of Contents
15+
16+
- [Features](#features)
17+
- [Configuration](#configuration)
18+
- [JWT and Board URLs](#jwt-and-board-urls)
19+
- [Storage](#storage)
20+
- [Installation](#installation)
21+
- [Docker](#docker)
22+
- [Docker Compose](#docker-compose)
23+
- [Build Go binary](#build-go-binary)
24+
- [How to use](#how-to-use)
25+
- [Contributing](#contributing)
26+
- [License](#license)
27+
28+
## Features
29+
30+
- Real-time collaboration with multiple users
31+
- Authentication and validation with JWT
32+
- Configurable storage (currently only supports **in-memory** storage)
33+
34+
## Configuration
35+
36+
The server uses **_.yaml_** configuration file to set up.
37+
You can find an example configuration file [here](./config-example.yaml).
38+
39+
```yaml
40+
apps:
41+
log_level: "DEBUG"
42+
rest:
43+
port: 8080
44+
validation:
45+
jwt_header_name: "<YOUR_JWT_HEADER_NAME>"
46+
jwt_validation_url: "<YOUR_JWT_VALIDATION_URL>"
47+
board_validation_url: "<YOUR_BOARD_VALIDATION_URL>"
48+
49+
storage:
50+
users:
51+
type: "in-memory"
52+
rooms:
53+
type: "in-memory"
54+
```
55+
56+
Currently, the `apps` section contains the following configurations:
57+
- `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).
58+
- `rest`: The REST API configuration.
59+
- `port`: The port of the REST API.
60+
- `validation`: The JWT validation configuration.
61+
- `jwt_header_name`: The name of the header, in which `Excaliroom` will set the JWT token from client.
62+
- `jwt_validation_url`: The URL to validate the JWT token, which will be used to authenticate the user.
63+
- `board_validation_url`: The URL to validate the access to the board with the JWT token.
64+
65+
The `storage` section contains the following configurations:
66+
- `users`: The user storage configuration. It specifies where the server will store the user data.
67+
- `type`: The type of the storage. Currently, only `in-memory` is supported.
68+
- `rooms`: The room storage configuration. It specifies where the server will store the room data.
69+
- `type`: The type of the storage. Currently, only `in-memory` is supported.
70+
71+
### JWT and Board URLs
72+
73+
To authenticate the user and validate the access to the board, you need to provide the URLs in the configuration file.
74+
75+
The `Excaliroom` server requires 2 URLs:
76+
- `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:
77+
```json
78+
{
79+
"id": "<USER_ID>"
80+
}
81+
```
82+
The `id` will be used to identify the user.
83+
84+
85+
- `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`.
86+
87+
### Storage
88+
89+
Currently, the server only supports `in-memory` storage for users and rooms.
90+
91+
## Installation
92+
93+
### Docker
94+
95+
>[!WARNING]
96+
> Currently, the Docker image from the Docker Hub is only available for **linux/amd64** platform.
97+
>
98+
> If you use another platform (e.g., **linux/arm64**), you can provide `--platform` flag to the `docker pull` command.
99+
100+
1. You can pull the Docker image from the Docker Hub:
101+
102+
```bash
103+
docker pull icerzack/excaliroom:latest
104+
```
105+
106+
Then, you can run the Docker container with the following command:
107+
108+
```bash
109+
docker run -d -p 8080:8080 -v path/to/config.yaml:/config.yaml -e CONFIG_PATH="/config.yaml" icerzack/excaliroom:latest
110+
```
111+
112+
2. You can build the Docker image by yourself with the following command:
113+
114+
```bash
115+
docker build -f build/Dockerfile -e CONFIG_PATH="path/to/config.yaml" -t excaliroom .
116+
```
117+
118+
Then, you can run the Docker container with the following command:
119+
120+
```bash
121+
docker run -d -p 8080:8080 -v path/to/config.yaml:/config.yaml -e CONFIG_PATH="/config.yaml" excaliroom
122+
```
123+
124+
### Docker Compose
125+
126+
You can use Docker Compose to run the server with the following `docker-compose.yml` file:
127+
128+
```yaml
129+
services:
130+
app:
131+
image: icerzack/excaliroom:latest
132+
environment:
133+
- CONFIG_PATH=config.yaml
134+
ports:
135+
- "8080:8080"
136+
volumes:
137+
- ./config.yaml:/config.yaml
138+
```
139+
140+
Then, you can run the server with the following command:
141+
142+
```bash
143+
docker-compose up -d
144+
```
145+
146+
### Build Go binary
147+
148+
Set the environment variable `CONFIG_PATH` to the path of the configuration file and build the binary:
149+
150+
```bash
151+
export CONFIG_PATH="path/to/config.yaml"
152+
go build -o excaliroom main.go
153+
```
154+
155+
Then, you can run the binary:
156+
157+
```bash
158+
./excaliroom
159+
```
160+
161+
## How to use
162+
163+
Check the [docs](./docs) directory of this repo for the guides on how to use and integrate the `Excaliroom` server with your JavaScript application.
164+
165+
## Contributing
166+
167+
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!
168+
169+
1. Fork the Project
170+
2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
171+
3. Commit your Changes (git commit -m 'Add some AmazingFeature')
172+
4. Push to the Branch (git push origin feature/AmazingFeature)
173+
5. Open a Pull Request
174+
175+
## License
176+
177+
This project is licensed under the Apache License 2.0 - see the [LICENSE](./LICENSE) file for details.

docs/README.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
# How to use Excaliroom
2+
3+
This directory contains guidance for using and integrating the `Excaliroom` server with your existing project.
4+
5+
## Table of contents
6+
7+
- [Getting started](#getting-started)
8+
- [Pre-requisites](#pre-requisites)
9+
- [How Excaliroom works](#how-excaliroom-works)
10+
- [API reference](#api-reference)
11+
- [Examples](#examples)
12+
- [FAQ](#faq)
13+
14+
## Getting started
15+
16+
### Pre-requisites
17+
18+
First of all, it is implied that you have `Backend` and `Frontend` applications:
19+
- `Backend`: It may contain some of your business logic, and it may be written in any programming language.
20+
- `Frontend`: It is your JavaScript application that will communicate with the `Excaliroom` server.
21+
22+
The `Excaliroom` WebSocket server is only responsible for handling real-time communication between your clients on the same board.
23+
It does not store any data (except for the current state of the board and connected clients) and does not have any business logic.
24+
25+
However, `Excaliroom` server requires a `JWT` token to authenticate and authorize users.
26+
The `JWT` token should be:
27+
- Validated by your `Backend` application.
28+
- Provided by your `Frontend` application.
29+
30+
The `Excaliroom` server also requires a URL to validate user access to the board.
31+
32+
The neccessary URLs for `JWT` validation and board validation should be provided in the `Excaliroom` server configuration file.
33+
See the [Configuration](../README.md#configuration) section for more information.
34+
35+
### How Excaliroom works
36+
37+
The `Excaliroom` server uses WebSockets to communicate between clients and broadcast the changes to all connected clients.
38+
It is a real-time collaboration server that allows multiple users to draw on the same board.
39+
40+
Currently, the sharing mechanism is simple:
41+
- 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.
42+
- 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.
43+
- 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**_.
44+
- 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.
45+
- When the last user leaves the room, the room is deleted from the `Excaliroom`.
46+
47+
The `Excaliroom` sends and receives messages in JSON format. The message format is described in the [API reference](#api-reference) section.
48+
49+
## API reference
50+
51+
Each JSON message contains `event` field that describes the type of the message. The `event` field can have the following values:
52+
- `connect`: The message is sent by `Frontend` when the user requests to connect to the board.
53+
- `userConnected`: The message is sent by `Excaliroom` to all connected users when a new user connects to the board.
54+
- `userDisconnected`: The message is sent by `Excaliroom` to all connected users when a user disconnects from the board.
55+
- `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.
56+
- `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.
57+
58+
The JSON message format is as follows:
59+
1. `connect` event:
60+
```json
61+
{
62+
"event": "connect",
63+
"board_id": "<BOARD_ID>",
64+
"jwt": "<JWT_TOKEN>"
65+
}
66+
```
67+
- `board_id`: The unique identifier of the board.
68+
- `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.
69+
70+
2. `userConnected` event:
71+
```json
72+
{
73+
"event": "userConnected",
74+
"user_ids": ["<USER_ID_1>", "<USER_ID_2>", ...],
75+
"leader_id": "<LEADER_ID>"
76+
}
77+
```
78+
- `user_ids`: The list of user identifiers that are connected to the board.
79+
- `leader_id`: The identifier of the _**Leader**_ of the room. If the _**Leader**_ is not set, the `leader_id` will be `0`.
80+
81+
3. `userDisconnected` event:
82+
```json
83+
{
84+
"event": "userDisconnected",
85+
"user_ids": ["<USER_ID_1>", "<USER_ID_2>", ...],
86+
"leader_id": "<LEADER_ID>"
87+
}
88+
```
89+
- `user_ids`: The list of user identifiers that are connected to the board.
90+
- `leader_id`: The identifier of the _**Leader**_ of the room. If the _**Leader**_ is not set, the `leader_id` will be `0`.
91+
92+
4. `setLeader` event (request):
93+
```json
94+
{
95+
"event": "setLeader",
96+
"board_id": "<BOARD_ID>",
97+
"jwt": "<JWT_TOKEN>"
98+
}
99+
```
100+
- `board_id`: The unique identifier of the board.
101+
- `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.
102+
103+
5. `setLeader` event (response):
104+
```json
105+
{
106+
"event": "setLeader",
107+
"board_id": "<BOARD_ID>",
108+
"user_id": "<USER_ID>"
109+
}
110+
```
111+
- `board_id`: The unique identifier of the board.
112+
- `user_id`: The identifier of the _**Leader**_ of the room.
113+
114+
6. `newData` event (request):
115+
```json
116+
{
117+
"event": "newData",
118+
"board_id": "<BOARD_ID>",
119+
"jwt": "<JWT_TOKEN>",
120+
"data": {
121+
"elements": "EXCALIDRAW_ELEMENTS_JSON",
122+
"appState": "EXCALIDRAW_APP_STATE_JSON"
123+
}
124+
}
125+
```
126+
- `board_id`: The unique identifier of the board.
127+
- `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.
128+
- `data`: The board data that is sent by the _**Leader**_ of the room.
129+
- `elements`: The JSON string of the Excalidraw `elements`.
130+
- `appState`: The JSON string of the Excalidraw `appState`.
131+
132+
See the [Excalidraw Docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/initialdata) documentation for more information.
133+
134+
7. `newData` event (response):
135+
```json
136+
{
137+
"event": "newData",
138+
"board_id": "<BOARD_ID>",
139+
"data": {
140+
"elements": "EXCALIDRAW_ELEMENTS_JSON",
141+
"appState": "EXCALIDRAW_APP_STATE_JSON"
142+
}
143+
}
144+
```
145+
- `board_id`: The unique identifier of the board.
146+
- `data`: The board data that is sent by the _**Leader**_ of the room.
147+
- `elements`: The JSON string of the Excalidraw `elements`.
148+
- `appState`: The JSON string of the Excalidraw `appState`.
149+
150+
See the [Excalidraw Docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/initialdata) documentation for more information.
151+
152+
## Examples
153+
154+
_Later_
155+
156+
## FAQ
157+
158+
_Later_
159+

0 commit comments

Comments
 (0)