♻️(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:
Anthony LC
2024-09-04 16:55:13 +02:00
committed by Anthony LC
parent 1139c0abea
commit 9c512fae69
8 changed files with 396 additions and 522 deletions

View File

@@ -1,14 +0,0 @@
module.exports = {
root: true,
extends: ['impress/next'],
parserOptions: {
tsconfigRootDir: __dirname,
project: ['./tsconfig.json'],
},
settings: {
next: {
rootDir: __dirname,
},
},
ignorePatterns: ['node_modules', '.eslintrc.js'],
};

View File

@@ -1,5 +0,0 @@
{
"watch": ["src"],
"ext": "ts",
"exec": "yarn build"
}

View File

@@ -1,30 +0,0 @@
{
"name": "y-webrtc-signaling",
"version": "1.2.1",
"description": "WebRTC server for Yjs",
"repository": "https://github.com/numerique-gouv/impress",
"license": "MIT",
"type": "module",
"scripts": {
"build": "tsc -p .",
"dev": "nodemon --config nodemon.json",
"start": "node ./dist/server.js",
"lint": "eslint . --ext .ts"
},
"engines": {
"node": ">=18"
},
"dependencies": {
"lib0": "0.2.97",
"ws": "8.18.0"
},
"devDependencies": {
"@types/node": "*",
"@types/ws": "8.5.12",
"eslint-config-impress": "*",
"nodemon": "3.1.4",
"ts-jest": "29.2.5",
"ts-node": "10.9.2",
"typescript": "*"
}
}

View File

@@ -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);

View File

@@ -1,19 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": false,
"outDir": "./dist",
},
"include": ["**/*.ts"],
"exclude": ["node_modules"]
}