Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Try] HTTP based PHP signaling server for colaborative editing #53922

Merged
merged 32 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2afc4b1
in progress (+9 squashed commits)
jorgefilipecosta Jul 25, 2023
c5acd3a
Update lib/sync/endpoint.php
jorgefilipecosta Sep 8, 2023
d0ef30b
Update lib/sync/endpoint.php
jorgefilipecosta Sep 8, 2023
a41b962
Update lib/sync/endpoint.php
jorgefilipecosta Sep 8, 2023
758c3a8
Refactor to a class.
jorgefilipecosta Sep 8, 2023
baa1f26
Use fetch instead of XMLHttpRequest.
jorgefilipecosta Sep 11, 2023
b6bdf0e
Fixed possible race condition and added file access error handling.
jorgefilipecosta Sep 13, 2023
d20d38b
Refactor to createWebRTCConnection.
jorgefilipecosta Sep 15, 2023
fc44534
Rename unique to subscriber_id. And improve code sending messages.
jorgefilipecosta Sep 15, 2023
592fb91
Remove use of an hack for multiple messages.
jorgefilipecosta Sep 15, 2023
fe55494
Use fetch instead of XMLHttpRequest
jorgefilipecosta Sep 15, 2023
f48cfef
Add documentation for the signalling server
jorgefilipecosta Sep 15, 2023
5be6528
Add signalling server loading back
jorgefilipecosta Sep 18, 2023
762abd6
Remove hardcoded url from the docs.
jorgefilipecosta Sep 18, 2023
11669ed
Updated sync readme.
jorgefilipecosta Sep 21, 2023
584fe0e
Fix undefined error on test.
jorgefilipecosta Sep 21, 2023
8eb88f7
Update package lock.
jorgefilipecosta Sep 27, 2023
0efb27e
Document the Event stream format
oandregal Sep 29, 2023
724b0e7
Update docs for signaling server
oandregal Sep 29, 2023
f9a639a
Update lib/experimental/sync/class-gutenberg-http-signaling-server.php
jorgefilipecosta Oct 6, 2023
8cc4344
refactor in progress
jorgefilipecosta Oct 6, 2023
3e2e03b
tmp
jorgefilipecosta Oct 9, 2023
08390df
fix some bugs after refactoring
jorgefilipecosta Oct 10, 2023
e3ff7b1
Added retry mechanism with error events.
jorgefilipecosta Oct 10, 2023
53070ba
Document clean_up_old_connections.
jorgefilipecosta Oct 11, 2023
5cb0bf2
Make parameter order consistent.
jorgefilipecosta Oct 11, 2023
ac3e8ba
Document remaining parameters.
jorgefilipecosta Oct 11, 2023
f179c0e
Follow y-webrtc room name convention
jorgefilipecosta Oct 11, 2023
a56a392
Conditionally enable endpoint depending if setting is set or not.
jorgefilipecosta Oct 11, 2023
7dbd59f
Remove debug code.
jorgefilipecosta Oct 11, 2023
33ee833
Fix rebase: remove no longer existing file
oandregal Oct 19, 2023
b42e5f1
Update docs
oandregal Oct 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 183 additions & 0 deletions lib/experimental/sync/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# Signaling Server Documentation

The signaling server allows multiple clients to exchange messages with each other through various communication topics.

Topics are not defined upfront, but clients define them by subscribing to them. By subscribing to a given topic, the client tells the server to keep track of its unread messages in the given topic. By unsubscribing from a topic, the client tells the server to free the bookeeping it maintains for the given client and topic.

Every client communicates with the server via `GET` or `POST`. Clients must have a unique identifier, which can be randomly generated. This identifier should be included as a parameter named `subscriber_id` in every request.

Available operations:

- Subscribe to topics
- Unsubscribe from topics
- Publish a message
- Read pending messages
- Ping the server

## Subscribe to topics

To subscribe to a set of topics, a client must send a `POST` request with the following parameters:

- `subscriber_id`: Subscriber ID of the client.
- `action`: should be set to `gutenberg_signaling_server`.
- `message`:
- `type`: should be set to `subscribe`.
- `topics`: array of topics that the client is interested in reading messages from, e.g., `[ 'WordPress', 'Drupal' ]`.

If the action is executed successfully by the server, the server will respond with `{"result":"ok"}`.

### Sample request

```js
await (
await fetch( window.wp.ajax.settings.url, {
body: new URLSearchParams( {
subscriber_id: '1',
action: 'gutenberg_signaling_server',
message: JSON.stringify( {
type: 'subscribe',
topics: [ 'WordPress', 'Drupal' ],
} ),
} ),
method: 'POST',
} )
).text();
```

## Unsubscribe from topics

To unsubscribe from a set of topics, a client must send a `POST` request with the following parameters:

- `subscriber_id`: subscriber ID of the client.
- `action`: should be set to `gutenberg_signaling_server`.
- `message`:
- `type`: should be set as `unsubscribe`.
- `topics`: an array of topics that the client is no longer interested in reading messages from, e.g., `['WordPress', 'Drupal']`.

If the action is executed successfully by the server, the server will respond with `{"result":"ok"}`.

### Sample request

```js
await (
await fetch( window.wp.ajax.settings.url, {
body: new URLSearchParams( {
subscriber_id: '1',
action: 'gutenberg_signaling_server',
message: JSON.stringify( {
type: 'unsubscribe',
topics: [ 'WordPress', 'Drupal' ],
} ),
} ),
method: 'POST',
} )
).text();
```

## Publish a message

To publish a message in a specific topic, a client must send a `POST` request with the following parameters:

- `subscriber_id`: subscriber ID of the client.
- `action`: should be set to `gutenberg_signaling_server`.
- `message`:
- `type`: should be set as `publish`.
- `topic`: the topic where the message should be published, e.g., `WordPress`.
- `data`: The data to be broadcasted to every client that subscribed to the topic. The data can be any string and may be encrypted to prevent the server from reading the messages.

If the action is executed successfully by the server, the server will respond with `{"result":"ok"}`.

### Sample request

```js
await (
await fetch( window.wp.ajax.settings.url, {
body: new URLSearchParams( {
subscriber_id: '1',
action: 'gutenberg_signaling_server',
message: JSON.stringify( {
type: 'publish',
topic: 'WordPress',
data: 'hello I am client 1!',
} ),
} ),
method: 'POST',
} )
).text();
```

## Read pending messages

To read pending messages, the client should send a `GET` request with the following parameters:

- `subscriber_id`: Subscriber ID of the client.
- `action`: should be set to `gutenberg_signaling_server`.

The server will respond using the [Event stream format](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format), whose content type is set to `text/event-stream;charset=UTF-8`. The Event stream format defines the following fields:

- `retry`: the reconnection time, in ms. The time after which the client should check again for messages.
- `id`: unique identifier for the server response.
- `event`: one of `message` or `error`.
- `data`:
- If `event` is `message`, data is a JSON encoded string containing an array of messages that the given client has not read yet. Each message is similar to the published message object but includes an additional property named `clients`. This property specifies the number of clients for which the message was sent. Note it does not indicate whether they have already received/requested it.
- If `event` is `error`, data is a description of the error.

If there are no pending messages, the server's response only contains the `retry:` field. If there are pending messages, the server will respond including all the fields.

### Sample request

```js
await (
await fetch(
window.wp.url.addQueryArgs( window.wp.ajax.settings.url, {
subscriber_id: '1',
action: 'gutenberg_signaling_server',
} )
)
).text();
```

Sample answer from the server when there are no unread messages:

```
retry: 3000
```

Sample answer from the server when there are unread messages:

```
retry: 3000
id: 1694809781
event: message
data: [{"type":"publish","topic":"WordPress","data":"hello I am client 1!","clients":2},{"type":"publish","topic":"WordPress","data":"Hi client 1 I am client 2","clients":2}]
```

## Ping the server

To ensure that the server is listening and to indicate that a client is still alive, the client can periodically send a ping to the server. When the server receives a ping from a client, it will respond with a message containing `pong`. The client will receive this `pong` message when it asks the server for new messages.

To send a ping, the client should send a `POST` request with the following parameters:

- `subscriber_id`: Subscriber ID of the client.
- `action`: should be set to `gutenberg_signaling_server`.
- `message`:
- `type`: Should be set as `ping`.

If the action is executed successfully by the server, the server will respond with `{"result":"ok"}`.

#### Sample request

```js
await (
await fetch( window.wp.ajax.settings.url, {
body: new URLSearchParams( {
subscriber_id: '1',
action: 'gutenberg_signaling_server',
message: JSON.stringify( {
type: 'ping',
} ),
} ),
method: 'POST',
} )
).text();
```
Loading
Loading