♻️(y-provider) replace y-webrtc-signaling by server-y-provider
We replace the y-webrtc-signaling app by the server-y-provider server. The server-y-provider server uses @hocuspocus to do collaborative editing on docs.
This commit is contained in:
@@ -1,168 +0,0 @@
|
||||
/**
|
||||
* Based on https://github.com/yjs/y-webrtc/blob/master/bin/server.js
|
||||
*/
|
||||
import http from 'http';
|
||||
|
||||
import * as map from 'lib0/map';
|
||||
import WebSocket, { WebSocketServer } from 'ws';
|
||||
|
||||
type MessageYJSType = {
|
||||
type: string;
|
||||
topics?: string[];
|
||||
topic?: string;
|
||||
clients?: number;
|
||||
};
|
||||
|
||||
type MessageYJSTypes = MessageYJSType | string;
|
||||
|
||||
const wsReadyStateConnecting = 0;
|
||||
const wsReadyStateOpen = 1;
|
||||
const pingTimeout = 30000;
|
||||
const port = process.env.PORT || 4444;
|
||||
|
||||
const wss = new WebSocketServer({ noServer: true });
|
||||
const topics = new Map<string, Set<{ url: string; conn: WebSocket }>>();
|
||||
|
||||
const send = (conn: WebSocket, message: MessageYJSTypes) => {
|
||||
if (
|
||||
conn.readyState !== wsReadyStateConnecting &&
|
||||
conn.readyState !== wsReadyStateOpen
|
||||
) {
|
||||
conn.close();
|
||||
}
|
||||
try {
|
||||
conn.send(JSON.stringify(message));
|
||||
} catch (e) {
|
||||
conn.close();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup a new client
|
||||
*/
|
||||
const onconnection = (conn: WebSocket, url: string) => {
|
||||
const subscribedTopics = new Set<string>();
|
||||
let closed = false;
|
||||
// Check if connection is still alive
|
||||
let pongReceived = true;
|
||||
|
||||
const pingInterval = setInterval(() => {
|
||||
if (!pongReceived) {
|
||||
conn.close();
|
||||
clearInterval(pingInterval);
|
||||
} else {
|
||||
pongReceived = false;
|
||||
try {
|
||||
conn.ping();
|
||||
} catch (e) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}, pingTimeout);
|
||||
|
||||
conn.on('pong', () => {
|
||||
pongReceived = true;
|
||||
});
|
||||
|
||||
conn.on('close', () => {
|
||||
subscribedTopics.forEach((topicName) => {
|
||||
const subs = topics.get(topicName) || new Set();
|
||||
subs.forEach((sub) => {
|
||||
if (sub.url === url && sub.conn === conn) {
|
||||
subs.delete(sub);
|
||||
}
|
||||
});
|
||||
if (subs.size === 0) {
|
||||
topics.delete(topicName);
|
||||
}
|
||||
});
|
||||
subscribedTopics.clear();
|
||||
closed = true;
|
||||
});
|
||||
|
||||
conn.on('message', (message: MessageYJSTypes) => {
|
||||
if (typeof message === 'string' || message instanceof Buffer) {
|
||||
message = JSON.parse(message.toString()) as MessageYJSType;
|
||||
}
|
||||
|
||||
if (message && message.type && !closed) {
|
||||
switch (message.type) {
|
||||
case 'subscribe':
|
||||
(message.topics || []).forEach((topicName) => {
|
||||
if (typeof topicName === 'string') {
|
||||
// add conn to topic
|
||||
const topic = map.setIfUndefined(
|
||||
topics,
|
||||
topicName,
|
||||
() => new Set(),
|
||||
);
|
||||
|
||||
let isAlreadyAdded = false;
|
||||
topic.forEach((sub) => {
|
||||
if (sub.url === url && sub.conn === conn) {
|
||||
isAlreadyAdded = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!isAlreadyAdded) {
|
||||
topic.add({ url, conn });
|
||||
subscribedTopics.add(topicName);
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case 'unsubscribe':
|
||||
(message.topics || []).forEach((topicName) => {
|
||||
const subs = topics.get(topicName);
|
||||
if (subs) {
|
||||
subs.forEach((sub) => {
|
||||
if (sub.conn === conn) {
|
||||
subs.delete(sub);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case 'publish':
|
||||
if (message.topic) {
|
||||
const receivers = topics.get(message.topic);
|
||||
if (receivers) {
|
||||
message.clients = receivers.size;
|
||||
receivers.forEach(({ url: receiverUrl, conn: receiverConn }) => {
|
||||
if (receiverUrl === url) {
|
||||
send(receiverConn, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ping':
|
||||
send(conn, { type: 'pong' });
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
wss.on('connection', (conn, request) => {
|
||||
const url = request.url;
|
||||
onconnection(conn, url || '');
|
||||
});
|
||||
|
||||
const server = http.createServer((request, response) => {
|
||||
response.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
response.end('okay');
|
||||
});
|
||||
|
||||
server.on('upgrade', (request, socket, head) => {
|
||||
const handleAuth = (ws: WebSocket) => {
|
||||
wss.emit('connection', ws, request);
|
||||
};
|
||||
wss.handleUpgrade(request, socket, head, handleAuth);
|
||||
});
|
||||
|
||||
server.listen(port);
|
||||
|
||||
console.log('Signaling server running on port :', port);
|
||||
@@ -5,7 +5,8 @@
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
"packages/*",
|
||||
"servers/*"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "y-webrtc-signaling",
|
||||
"name": "server-y-provider",
|
||||
"version": "1.2.1",
|
||||
"description": "WebRTC server for Yjs",
|
||||
"description": "Y.js provider for docs",
|
||||
"repository": "https://github.com/numerique-gouv/impress",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@@ -15,12 +15,10 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"lib0": "0.2.97",
|
||||
"ws": "8.18.0"
|
||||
"@hocuspocus/server": "2.13.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/ws": "8.5.12",
|
||||
"eslint-config-impress": "*",
|
||||
"nodemon": "3.1.4",
|
||||
"ts-jest": "29.2.5",
|
||||
18
src/frontend/servers/y-provider/src/server.ts
Normal file
18
src/frontend/servers/y-provider/src/server.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Server } from '@hocuspocus/server';
|
||||
|
||||
const port = Number(process.env.PORT || 4444);
|
||||
|
||||
const server = Server.configure({
|
||||
name: 'docs-y-provider',
|
||||
port: port,
|
||||
timeout: 30000,
|
||||
debounce: 2000,
|
||||
maxDebounce: 30000,
|
||||
quiet: true,
|
||||
});
|
||||
|
||||
server.listen().catch((error) => {
|
||||
console.error('Failed to start the server:', error);
|
||||
});
|
||||
|
||||
console.log('Websocket server running on port :', port);
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user