From f718747294db022f936e3fdb863464144c6f0c3b Mon Sep 17 00:00:00 2001 From: bastien ollier Date: Wed, 29 May 2024 14:26:20 +0200 Subject: [PATCH 1/7] add route /live --- package.json | 1 + src/database.ts | 33 ++++++------ src/runner.ts | 4 +- src/server.ts | 134 ++++++++++++++++++++++++++++++------------------ 4 files changed, 106 insertions(+), 66 deletions(-) diff --git a/package.json b/package.json index 44ed1b8..d2e192b 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@fastify/type-provider-typebox": "^4.0.0", "@fastify/websocket": "^10.0.1", "@sinclair/typebox": "^0.32.9", + "dprint": "^0.46.1", "fastify": "^4.27.0", "nanoid": "^5.0.4", "sqlite3": "^5.1.7", diff --git a/src/database.ts b/src/database.ts index c8b3d48..3aa61be 100644 --- a/src/database.ts +++ b/src/database.ts @@ -10,7 +10,7 @@ const dbFilePath = `${dbDirectory}/database.db`; export function runDB( db: sqlite3.Database, query: string, - params: any[] + params: any[], ): Promise { return new Promise((resolve, reject) => { db.run(query, params, (err) => { @@ -26,7 +26,7 @@ export function runDB( /* Fonction pour récupérer plusieurs lignes de la base de données */ export function allDB( db: sqlite3.Database, - query: string + query: string, ): Promise { return new Promise((resolve, reject) => { db.all(query, (err, rows) => { @@ -43,7 +43,7 @@ export function allDB( export function getDB( db: sqlite3.Database, query: string, - params: any[] + params: any[], ): Promise { return new Promise((resolve, reject) => { db.get(query, params, (err, row: any) => { @@ -73,7 +73,7 @@ export function openDatabase() { sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err: Error | null) => { if (err) console.error(err.message); - } + }, ); } @@ -105,7 +105,8 @@ export function createTables(db: sqlite3.Database) { /* Créer la table registered_user dans la base de données */ export function createRegisteredUserTable(db: sqlite3.Database): Promise { - const tableRegisteredUser = `CREATE TABLE IF NOT EXISTS registered_user (id_user INTEGER PRIMARY KEY AUTOINCREMENT, login TEXT NOT NULL, password TEXT NOT NULL, permissions INTEGER NOT NULL, UNIQUE (login))`; + const tableRegisteredUser = + `CREATE TABLE IF NOT EXISTS registered_user (id_user INTEGER PRIMARY KEY AUTOINCREMENT, login TEXT NOT NULL, password TEXT NOT NULL, permissions INTEGER NOT NULL, UNIQUE (login))`; return runDB(db, tableRegisteredUser, []); } @@ -115,7 +116,7 @@ export function insertUser( db: sqlite3.Database, login: string, password: string, - permissions: number + permissions: number, ) { const insertUserQuery = `INSERT INTO registered_user (login, password, permissions) VALUES (?, ?, ?)`; @@ -126,7 +127,7 @@ export function insertUser( export function updateUserLogin( db: sqlite3.Database, id: number, - newLogin: string + newLogin: string, ) { const updateUserLoginQuery = `UPDATE registered_user SET login = ? WHERE id_user = ?`; @@ -137,7 +138,7 @@ export function updateUserLogin( export function updateUserPassword( db: sqlite3.Database, id: number, - newPassword: string + newPassword: string, ) { const updateUserPasswordQuery = `UPDATE registered_user SET password = ? WHERE id_user = ?`; @@ -148,7 +149,7 @@ export function updateUserPassword( export function updateUserPermissions( db: sqlite3.Database, id: number, - newPermissions: number + newPermissions: number, ) { const updateUserPermissionsQuery = `UPDATE registered_user SET permissions = ? WHERE id_user = ?`; @@ -206,7 +207,8 @@ export function selectUserById(db: sqlite3.Database, id: number) { /* Créer la table language dans la base de données */ export function createLanguageTable(db: sqlite3.Database): Promise { - const tableLanguage = `CREATE TABLE IF NOT EXISTS language (id_language INTEGER PRIMARY KEY AUTOINCREMENT, designation TEXT NOT NULL, version INTEGER NOT NULL)`; + const tableLanguage = + `CREATE TABLE IF NOT EXISTS language (id_language INTEGER PRIMARY KEY AUTOINCREMENT, designation TEXT NOT NULL, version INTEGER NOT NULL)`; return runDB(db, tableLanguage, []); } @@ -214,7 +216,7 @@ export function createLanguageTable(db: sqlite3.Database): Promise { export function insertLanguage( db: sqlite3.Database, designation: string, - version: number + version: number, ) { const insertLanguageQuery = `INSERT INTO language (designation, version) VALUES (?, ?)`; @@ -225,7 +227,7 @@ export function insertLanguage( export function updateLanguageDesignation( db: sqlite3.Database, id: number, - newDesignation: string + newDesignation: string, ) { const updateLanguageDesignationQuery = `UPDATE language SET designation = ? WHERE id_language = ?`; @@ -236,7 +238,7 @@ export function updateLanguageDesignation( export function updateLanguageVersion( db: sqlite3.Database, id: number, - newVersion: number + newVersion: number, ) { const updateLanguageVersionQuery = `UPDATE language SET version = ? WHERE id_language = ?`; @@ -282,7 +284,8 @@ export function selectLanguageById(db: sqlite3.Database, id: number) { /* Créer la table work dans la base de données */ export function createWorkTable(db: sqlite3.Database): Promise { - const tableWork = `CREATE TABLE IF NOT EXISTS work (id_work INTEGER PRIMARY KEY AUTOINCREMENT, link CHAR(36) NOT NULL, user_id INTEGER REFERENCES registered_user(id_user), language_id INTEGER NOT NULL REFERENCES language(id_language), content TEXT NOT NULL)`; + const tableWork = + `CREATE TABLE IF NOT EXISTS work (id_work INTEGER PRIMARY KEY AUTOINCREMENT, link CHAR(36) NOT NULL, user_id INTEGER REFERENCES registered_user(id_user), language_id INTEGER NOT NULL REFERENCES language(id_language), content TEXT NOT NULL)`; return runDB(db, tableWork, []); } @@ -292,7 +295,7 @@ export function insertWork( link: string, user_id: number, language_id: number, - content: string + content: string, ) { const insertWorkQuery = `INSERT INTO work (link, user_id, language_id, content) VALUES (?, ?, ?, ?)`; diff --git a/src/runner.ts b/src/runner.ts index 290e8bb..1a8567b 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -19,11 +19,11 @@ export const IMAGES = { export function allocateBuffer( jobId: string, code: string, - image: string + image: string, ): Buffer { let cur = 0; const buffer = Buffer.allocUnsafe( - jobId.length + image.length + code.length + 9 + jobId.length + image.length + code.length + 9, ); cur = buffer.writeUInt8(0, cur); cur += buffer.write(jobId, cur); diff --git a/src/server.ts b/src/server.ts index 8690712..8ed0f84 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,12 +1,12 @@ +import { rebaseUpdates, Update } from "@codemirror/collab"; +import { ChangeSet, Text } from "@codemirror/state"; import cors from "@fastify/cors"; -import websocket, { WebSocket } from '@fastify/websocket'; import { Type, TypeBoxTypeProvider } from "@fastify/type-provider-typebox"; +import websocket, { WebSocket } from "@fastify/websocket"; import Fastify, { FastifyReply } from "fastify"; import { nanoid } from "nanoid"; import { allocateBuffer, getRunner } from "runner"; import { Pull, Push } from "zeromq"; -import { ChangeSet, Text } from "@codemirror/state"; -import { Update, rebaseUpdates } from "@codemirror/collab"; import * as db from "./database"; const sender = new Push(); @@ -18,13 +18,13 @@ const clients: Record = {}; const generateId = () => nanoid(32); let updates: Update[] = []; -let doc = Text.of(['']); -const liveClients: WebSocket[] = []; +let doc = Text.of([""]); +const rooms: Record = {}; function send(socket: WebSocket, requestId: number, payload: unknown) { const response = { _request: requestId, - payload + payload, }; socket.send(JSON.stringify(response)); } @@ -32,39 +32,75 @@ function send(socket: WebSocket, requestId: number, payload: unknown) { const fastify = Fastify({ logger: true, }).withTypeProvider(); +type Fastify = typeof fastify; await fastify.register(cors, { - origin: process.env.ALLOW_ORIGIN || '*', + origin: process.env.ALLOW_ORIGIN || "*", }); fastify.register(websocket); -fastify.get("/live", { websocket: true }, (socket, req) => { - liveClients.push(socket); - socket.on("message", message => { - const data = JSON.parse(message.toString()); - const requestId = data._request; - if (data.type === "pullUpdates") { - send(socket, requestId, updates.slice(data.version)) - } else if (data.type === "pushUpdates") { - let received = data.updates.map((json: any) => ({ - clientID: json.clientID, - changes: ChangeSet.fromJSON(json.changes) - })) - if (data.version != updates.length) { - received = rebaseUpdates(received, updates.slice(data.version)) - } - for (let update of received) { - updates.push(update) - doc = update.changes.apply(doc) + + +fastify.register(async function (fastify: Fastify) { + fastify.get( + "/live/:roomId", + { + schema: { + params: Type.Object({ + roomId: Type.String(), + }) + }, + websocket: true + }, + (socket, request) => { + const { roomId } = request.params; + const liveClients = rooms[roomId]; + console.log(roomId); + if(!liveClients){ + + return; } - send(socket, requestId, received.map((update: any) => ({ - clientID: update.clientID, - changes: update.changes.toJSON() - }))); - } else if (data.type == "getDocument") { - send(socket, requestId, {version: updates.length, doc: doc.toString()}) - } - }) + liveClients.push(socket); + console.log(rooms); + socket.on("message", message => { + const data = JSON.parse(message.toString()); + const requestId = data._request; + if (data.type === "pullUpdates") { + send(socket, requestId, updates.slice(data.version)); + } else if (data.type === "pushUpdates") { + let received = data.updates.map((json: any) => ({ + clientID: json.clientID, + changes: ChangeSet.fromJSON(json.changes), + })); + if (data.version != updates.length) { + received = rebaseUpdates(received, updates.slice(data.version)); + } + for (let update of received) { + updates.push(update); + doc = update.changes.apply(doc); + } + send( + socket, + requestId, + received.map((update: any) => ({ + clientID: update.clientID, + changes: update.changes.toJSON(), + })), + ); + } else if (data.type == "getDocument") { + send(socket, requestId, { version: updates.length, doc: doc.toString() }); + } + }); + }); }) +/* Route pour créer une room */ +fastify.get( + "/live", + async (request, reply) => { + const roomId = generateId(); + reply.redirect(`/live/${roomId}`); + }, +); + fastify.post("/run", { schema: { body: Type.Object({ @@ -122,7 +158,7 @@ fastify.post( const { login, password, permissions } = request.body; db.insertUser(database, login, password, permissions); reply.send({ success: true }); - } + }, ); /* Route pour mettre à jour le login d'un utilisateur */ @@ -145,7 +181,7 @@ fastify.put( const { newLogin } = request.body; db.updateUserLogin(database, id, newLogin); reply.send({ success: true }); - } + }, ); /* Route pour mettre à jour le mot de passe d'un utilisateur */ @@ -168,7 +204,7 @@ fastify.put( const { newPassword } = request.body; db.updateUserPassword(database, id, newPassword); reply.send({ success: true }); - } + }, ); /* Route pour mettre à jour les permissions d'un utilisateur */ @@ -191,7 +227,7 @@ fastify.put( const { newPermissions } = request.body; await db.updateUserPermissions(database, id, newPermissions); reply.send({ success: true }); - } + }, ); /* Route pour supprimer un utilisateur par son ID */ @@ -210,7 +246,7 @@ fastify.delete( const { id } = request.params; await db.deleteUserById(database, id); reply.send({ success: true }); - } + }, ); /* Route pour supprimer un utilisateur par son login */ @@ -227,7 +263,7 @@ fastify.delete( const { login } = request.params; await db.deleteUserByLogin(database, login); reply.send({ success: true }); - } + }, ); /* Route pour supprimer tous les utilisateurs */ @@ -258,7 +294,7 @@ fastify.get( const { id } = request.params; const user = await db.selectUserById(database, id); reply.send(user); - } + }, ); /* Route pour récupérer un utilisateur par son login */ @@ -275,7 +311,7 @@ fastify.get( const { login } = request.params; const user = await db.selectUserByLogin(database, login); reply.send(user); - } + }, ); /* Route pour créer un language */ @@ -293,7 +329,7 @@ fastify.post( const { designation, version } = request.body; db.insertLanguage(database, designation, version); reply.send({ success: true }); - } + }, ); /* Route pour mettre à jour la désignation d'un language */ @@ -316,7 +352,7 @@ fastify.put( const { newDesignation } = request.body; db.updateLanguageDesignation(database, id, newDesignation); reply.send({ success: true }); - } + }, ); /* Route pour mettre à jour la version d'un language */ @@ -339,7 +375,7 @@ fastify.put( const { newVersion } = request.body; db.updateLanguageVersion(database, id, newVersion); reply.send({ success: true }); - } + }, ); /* Route pour supprimer un language */ @@ -358,7 +394,7 @@ fastify.delete( const { id } = request.params; db.deleteLanguage(database, id); reply.send({ success: true }); - } + }, ); /* Route pour supprimer tous les languages */ @@ -383,7 +419,7 @@ fastify.get( const { id } = request.params; const language = await db.selectLanguageById(database, id); reply.send(language); - } + }, ); /* Route pour récupérer tous les languages */ @@ -409,7 +445,7 @@ fastify.post( const { id_user, link, id_language, code } = request.body; db.insertWork(database, link, id_user, id_language, code); reply.send({ success: true }); - } + }, ); /* Route pour récupérer tous les works */ @@ -440,7 +476,7 @@ fastify.delete( const { id } = request.params; db.deleteWork(database, id); reply.send({ success: true }); - } + }, ); /* Route pour récupérer un work par son ID */ @@ -459,7 +495,7 @@ fastify.get( const { id } = request.params; const work = await db.selectWorkById(database, id); reply.send(work); - } + }, ); /* Forward output est une fonction asynchrone qui permet de récupérer les messages envoyés par le container et de les renvoyer au client */ -- 2.36.3 From b0cb3285fbfb3e34545f0880e31b61f561fdba04 Mon Sep 17 00:00:00 2001 From: bastien ollier Date: Mon, 3 Jun 2024 09:16:27 +0200 Subject: [PATCH 2/7] add live --- src/server.ts | 59 ++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/server.ts b/src/server.ts index 8ed0f84..d40894e 100644 --- a/src/server.ts +++ b/src/server.ts @@ -18,7 +18,7 @@ const clients: Record = {}; const generateId = () => nanoid(32); let updates: Update[] = []; -let doc = Text.of([""]); +let doc = Text.of(["foo"]); const rooms: Record = {}; function send(socket: WebSocket, requestId: number, payload: unknown) { @@ -52,41 +52,46 @@ fastify.register(async function (fastify: Fastify) { }, (socket, request) => { const { roomId } = request.params; - const liveClients = rooms[roomId]; - console.log(roomId); + let liveClients = rooms[roomId]; if(!liveClients){ - - return; + liveClients = []; + rooms[roomId] = liveClients; } liveClients.push(socket); - console.log(rooms); socket.on("message", message => { const data = JSON.parse(message.toString()); const requestId = data._request; + console.log(data.type) if (data.type === "pullUpdates") { - send(socket, requestId, updates.slice(data.version)); + send(socket, requestId, updates.slice(data.version)); } else if (data.type === "pushUpdates") { - let received = data.updates.map((json: any) => ({ - clientID: json.clientID, - changes: ChangeSet.fromJSON(json.changes), - })); - if (data.version != updates.length) { - received = rebaseUpdates(received, updates.slice(data.version)); - } - for (let update of received) { - updates.push(update); - doc = update.changes.apply(doc); - } - send( - socket, - requestId, - received.map((update: any) => ({ - clientID: update.clientID, - changes: update.changes.toJSON(), - })), - ); + let received = data.updates.map((json: any) => ({ + clientID: json.clientID, + changes: ChangeSet.fromJSON(json.changes), + })); + console.log(received); + if (data.version != updates.length) { + received = rebaseUpdates(received, updates.slice(data.version)); + } + console.log(received) + for (let update of received) { + console.log(update); + updates.push(update); + console.log(update,doc); + doc = update.changes.apply(doc); + console.log(update); + } + send( + socket, + requestId, + received.map((update: any) => ({ + clientID: update.clientID, + changes: update.changes.toJSON(), + })), + ); } else if (data.type == "getDocument") { - send(socket, requestId, { version: updates.length, doc: doc.toString() }); + console.log("getDoc"); + send(socket, requestId, { version: updates.length, doc: doc.toString() }); } }); }); -- 2.36.3 From e62b74482e6795300dcc262630207ade0cbff2b4 Mon Sep 17 00:00:00 2001 From: bastien ollier Date: Mon, 3 Jun 2024 13:44:58 +0200 Subject: [PATCH 3/7] delete console.log --- src/server.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/server.ts b/src/server.ts index d40894e..bec39ca 100644 --- a/src/server.ts +++ b/src/server.ts @@ -61,7 +61,7 @@ fastify.register(async function (fastify: Fastify) { socket.on("message", message => { const data = JSON.parse(message.toString()); const requestId = data._request; - console.log(data.type) + if (data.type === "pullUpdates") { send(socket, requestId, updates.slice(data.version)); } else if (data.type === "pushUpdates") { @@ -69,17 +69,14 @@ fastify.register(async function (fastify: Fastify) { clientID: json.clientID, changes: ChangeSet.fromJSON(json.changes), })); - console.log(received); + if (data.version != updates.length) { received = rebaseUpdates(received, updates.slice(data.version)); } - console.log(received) + for (let update of received) { - console.log(update); updates.push(update); - console.log(update,doc); doc = update.changes.apply(doc); - console.log(update); } send( socket, @@ -90,7 +87,6 @@ fastify.register(async function (fastify: Fastify) { })), ); } else if (data.type == "getDocument") { - console.log("getDoc"); send(socket, requestId, { version: updates.length, doc: doc.toString() }); } }); -- 2.36.3 From d60f9c5c66f2c866242433b5abf4fe013c2a5450 Mon Sep 17 00:00:00 2001 From: bastien ollier Date: Mon, 3 Jun 2024 14:20:53 +0200 Subject: [PATCH 4/7] update live path --- src/server.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/server.ts b/src/server.ts index bec39ca..13ef8fd 100644 --- a/src/server.ts +++ b/src/server.ts @@ -97,8 +97,7 @@ fastify.register(async function (fastify: Fastify) { fastify.get( "/live", async (request, reply) => { - const roomId = generateId(); - reply.redirect(`/live/${roomId}`); + return generateId(); }, ); -- 2.36.3 From e8d57a208abdb77f9f61dbfee662d2cfc8fc15f7 Mon Sep 17 00:00:00 2001 From: bastien ollier Date: Mon, 3 Jun 2024 14:40:29 +0200 Subject: [PATCH 5/7] add multiroom --- src/server.ts | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/server.ts b/src/server.ts index 13ef8fd..520ff01 100644 --- a/src/server.ts +++ b/src/server.ts @@ -14,12 +14,20 @@ await sender.bind(`tcp://127.0.0.1:5557`); const receiver = new Pull(); await receiver.bind(`tcp://127.0.0.1:5558`); + const clients: Record = {}; const generateId = () => nanoid(32); -let updates: Update[] = []; -let doc = Text.of(["foo"]); -const rooms: Record = {}; +//let updates: Update[] = []; +//let doc = Text.of(["foo"]); + +type Room = { + sockets: WebSocket[]; + updates: Update[]; + doc: Text; +} + +const rooms: Record = {}; function send(socket: WebSocket, requestId: number, payload: unknown) { const response = { @@ -52,31 +60,35 @@ fastify.register(async function (fastify: Fastify) { }, (socket, request) => { const { roomId } = request.params; - let liveClients = rooms[roomId]; - if(!liveClients){ - liveClients = []; - rooms[roomId] = liveClients; + let room = rooms[roomId]; + if(!room){ + room = { + sockets: [], + updates: [], + doc: Text.of(['']) + }; + rooms[roomId] = room; } - liveClients.push(socket); + room.sockets.push(socket); socket.on("message", message => { const data = JSON.parse(message.toString()); const requestId = data._request; if (data.type === "pullUpdates") { - send(socket, requestId, updates.slice(data.version)); + send(socket, requestId, room.updates.slice(data.version)); } else if (data.type === "pushUpdates") { let received = data.updates.map((json: any) => ({ clientID: json.clientID, changes: ChangeSet.fromJSON(json.changes), })); - if (data.version != updates.length) { - received = rebaseUpdates(received, updates.slice(data.version)); + if (data.version != room.updates.length) { + received = rebaseUpdates(received, room.updates.slice(data.version)); } for (let update of received) { - updates.push(update); - doc = update.changes.apply(doc); + room.updates.push(update); + room.doc = update.changes.apply(room.doc); } send( socket, @@ -87,7 +99,7 @@ fastify.register(async function (fastify: Fastify) { })), ); } else if (data.type == "getDocument") { - send(socket, requestId, { version: updates.length, doc: doc.toString() }); + send(socket, requestId, { version: room.updates.length, doc: room.doc.toString() }); } }); }); -- 2.36.3 From ea4160cb6d32fe2c7c569cd03c6fcb475c0f157f Mon Sep 17 00:00:00 2001 From: bastien ollier Date: Mon, 3 Jun 2024 14:43:40 +0200 Subject: [PATCH 6/7] add multiroom --- src/server.ts | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/server.ts b/src/server.ts index 520ff01..e1955f4 100644 --- a/src/server.ts +++ b/src/server.ts @@ -75,31 +75,31 @@ fastify.register(async function (fastify: Fastify) { const requestId = data._request; if (data.type === "pullUpdates") { - send(socket, requestId, room.updates.slice(data.version)); + send(socket, requestId, room.updates.slice(data.version)); } else if (data.type === "pushUpdates") { - let received = data.updates.map((json: any) => ({ - clientID: json.clientID, - changes: ChangeSet.fromJSON(json.changes), - })); - - if (data.version != room.updates.length) { - received = rebaseUpdates(received, room.updates.slice(data.version)); - } - - for (let update of received) { - room.updates.push(update); - room.doc = update.changes.apply(room.doc); - } - send( - socket, - requestId, - received.map((update: any) => ({ - clientID: update.clientID, - changes: update.changes.toJSON(), - })), - ); - } else if (data.type == "getDocument") { - send(socket, requestId, { version: room.updates.length, doc: room.doc.toString() }); + let received = data.updates.map((json: any) => ({ + clientID: json.clientID, + changes: ChangeSet.fromJSON(json.changes), + })); + + if (data.version != room.updates.length) { + received = rebaseUpdates(received, room.updates.slice(data.version)); + } + + for (let update of received) { + room.updates.push(update); + room.doc = update.changes.apply(room.doc); + } + send( + socket, + requestId, + received.map((update: any) => ({ + clientID: update.clientID, + changes: update.changes.toJSON(), + })), + ); + } else if (data.type === "getDocument") { + send(socket, requestId, { version: room.updates.length, doc: room.doc.toString() }); } }); }); -- 2.36.3 From fc6cbadebba72b557fc2af3ed12eca01ae8d9c71 Mon Sep 17 00:00:00 2001 From: bastien ollier Date: Mon, 3 Jun 2024 14:47:44 +0200 Subject: [PATCH 7/7] add multiroom --- src/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.ts b/src/server.ts index e1955f4..51d8de6 100644 --- a/src/server.ts +++ b/src/server.ts @@ -106,7 +106,7 @@ fastify.register(async function (fastify: Fastify) { }) /* Route pour créer une room */ -fastify.get( +fastify.post( "/live", async (request, reply) => { return generateId(); -- 2.36.3