transmit awareness
This commit is contained in:
parent
5fbc189884
commit
8bcc16f790
7 changed files with 143 additions and 14 deletions
15
package-lock.json
generated
15
package-lock.json
generated
|
@ -30,6 +30,7 @@
|
||||||
"nodemailer": "^6.10.0",
|
"nodemailer": "^6.10.0",
|
||||||
"pg": "^8.13.1",
|
"pg": "^8.13.1",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
|
"randomcolor": "^0.6.2",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rss-parser": "^3.13.0",
|
"rss-parser": "^3.13.0",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1",
|
||||||
|
@ -53,6 +54,7 @@
|
||||||
"@types/node-schedule": "^2.1.6",
|
"@types/node-schedule": "^2.1.6",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@types/qrcode": "~1.5.5",
|
"@types/qrcode": "~1.5.5",
|
||||||
|
"@types/randomcolor": "^0.5.9",
|
||||||
"@types/speakeasy": "^2.0.10",
|
"@types/speakeasy": "^2.0.10",
|
||||||
"@types/uuid": "^9.0.2",
|
"@types/uuid": "^9.0.2",
|
||||||
"ts-node": "10.7.0",
|
"ts-node": "10.7.0",
|
||||||
|
@ -480,6 +482,13 @@
|
||||||
"integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==",
|
"integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/randomcolor": {
|
||||||
|
"version": "0.5.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/randomcolor/-/randomcolor-0.5.9.tgz",
|
||||||
|
"integrity": "sha512-k58cfpkK15AKn1m+oRd9nh5BnuiowhbyvBBdAzcddtARMr3xRzP0VlFaAKovSG6N6Knx08EicjPlOMzDejerrQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/range-parser": {
|
"node_modules/@types/range-parser": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
||||||
|
@ -3471,6 +3480,12 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/randomcolor": {
|
||||||
|
"version": "0.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/randomcolor/-/randomcolor-0.6.2.tgz",
|
||||||
|
"integrity": "sha512-Mn6TbyYpFgwFuQ8KJKqf3bqqY9O1y37/0jgSK/61PUxV4QfIMv0+K2ioq8DfOjkBslcjwSzRfIDEXfzA9aCx7A==",
|
||||||
|
"license": "CC0"
|
||||||
|
},
|
||||||
"node_modules/range-parser": {
|
"node_modules/range-parser": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
"nodemailer": "^6.10.0",
|
"nodemailer": "^6.10.0",
|
||||||
"pg": "^8.13.1",
|
"pg": "^8.13.1",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
|
"randomcolor": "^0.6.2",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rss-parser": "^3.13.0",
|
"rss-parser": "^3.13.0",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1",
|
||||||
|
@ -68,6 +69,7 @@
|
||||||
"@types/node-schedule": "^2.1.6",
|
"@types/node-schedule": "^2.1.6",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@types/qrcode": "~1.5.5",
|
"@types/qrcode": "~1.5.5",
|
||||||
|
"@types/randomcolor": "^0.5.9",
|
||||||
"@types/speakeasy": "^2.0.10",
|
"@types/speakeasy": "^2.0.10",
|
||||||
"@types/uuid": "^9.0.2",
|
"@types/uuid": "^9.0.2",
|
||||||
"ts-node": "10.7.0",
|
"ts-node": "10.7.0",
|
||||||
|
|
|
@ -19,9 +19,13 @@ export default abstract class MissionDocHelper {
|
||||||
// const ytext = ydoc.getText('meinText');
|
// const ytext = ydoc.getText('meinText');
|
||||||
// ytext.insert(0, 'Hier ist ein initialer Text');
|
// ytext.insert(0, 'Hier ist ein initialer Text');
|
||||||
|
|
||||||
const awareness = 0; // TODO Awareness
|
MissionMap.write(missionId, {
|
||||||
|
missionId,
|
||||||
MissionMap.write(missionId, { missionId, doc, awareness, timestamp: 0 });
|
doc,
|
||||||
|
editors: new Map(),
|
||||||
|
editorStates: new Map(),
|
||||||
|
timestamp: 0,
|
||||||
|
});
|
||||||
console.log(`created local doc ${missionId}`);
|
console.log(`created local doc ${missionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +44,16 @@ export default abstract class MissionDocHelper {
|
||||||
return mission.timestamp;
|
return mission.timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static getAwarenessState(missionId: string) {
|
||||||
|
const mission = MissionMap.read(missionId);
|
||||||
|
return Array.from(mission.editorStates.entries());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getAwarenessEditors(missionId: string) {
|
||||||
|
const mission = MissionMap.read(missionId);
|
||||||
|
return Array.from(mission.editors.entries());
|
||||||
|
}
|
||||||
|
|
||||||
public static async saveDoc(missionId: string, update: Uint8Array) {
|
public static async saveDoc(missionId: string, update: Uint8Array) {
|
||||||
MissionMap.updateState(missionId, update);
|
MissionMap.updateState(missionId, update);
|
||||||
const mission = MissionMap.read(missionId);
|
const mission = MissionMap.read(missionId);
|
||||||
|
|
|
@ -4,10 +4,24 @@ import ms from "ms";
|
||||||
export interface missionStoreModel {
|
export interface missionStoreModel {
|
||||||
missionId: string;
|
missionId: string;
|
||||||
doc: Y.Doc;
|
doc: Y.Doc;
|
||||||
awareness: any;
|
editors: Map<string, Editor>;
|
||||||
|
editorStates: Map<string, EditorState>;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Editor {
|
||||||
|
username: string;
|
||||||
|
firstname: string;
|
||||||
|
lastname: string;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EditorState {
|
||||||
|
field: string;
|
||||||
|
cursor: any;
|
||||||
|
range: any;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description store credentials to socket to prevent auth data change while connected
|
* @description store credentials to socket to prevent auth data change while connected
|
||||||
*/
|
*/
|
||||||
|
@ -32,12 +46,30 @@ export abstract class MissionMap {
|
||||||
this.write(identifier, mission, true);
|
this.write(identifier, mission, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static updateAwareness(identifier: string, data: any): void {
|
public static updateAwareness(
|
||||||
|
identifier: string,
|
||||||
|
data: { action: "update" | "remove"; socketId: string } & (
|
||||||
|
| { store: "editors"; update: Editor }
|
||||||
|
| { store: "state"; update: EditorState }
|
||||||
|
)
|
||||||
|
): void {
|
||||||
this.monitorAccess(identifier);
|
this.monitorAccess(identifier);
|
||||||
|
|
||||||
let mission = this.read(identifier);
|
let mission = this.read(identifier);
|
||||||
|
|
||||||
// TODO save awareness
|
if (data.store == "editors") {
|
||||||
|
if (data.action == "update") {
|
||||||
|
mission.editors.set(data.socketId, data.update);
|
||||||
|
} else {
|
||||||
|
mission.editors.delete(data.socketId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (data.action == "update") {
|
||||||
|
mission.editorStates.set(data.socketId, data.update);
|
||||||
|
} else {
|
||||||
|
mission.editorStates.delete(data.socketId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.write(identifier, mission, true);
|
this.write(identifier, mission, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ export interface socketStoreModel {
|
||||||
socketId: string;
|
socketId: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
firstname: string;
|
||||||
|
lastname: string;
|
||||||
isOwner: string;
|
isOwner: string;
|
||||||
permissions: PermissionObject;
|
permissions: PermissionObject;
|
||||||
isWebApiRequest: boolean;
|
isWebApiRequest: boolean;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { Server, Socket } from "socket.io";
|
import { Server, Socket } from "socket.io";
|
||||||
import { handleEvent } from "../handleEvent";
|
import { handleEvent } from "../handleEvent";
|
||||||
import { MissionMap, missionStoreModel } from "../../storage/missionMap";
|
import { EditorState, MissionMap, missionStoreModel } from "../../storage/missionMap";
|
||||||
import * as Y from "yjs";
|
import * as Y from "yjs";
|
||||||
import MissionDocHelper from "../../helpers/missionDocHelper";
|
import MissionDocHelper from "../../helpers/missionDocHelper";
|
||||||
|
import randomColor from "randomcolor";
|
||||||
|
import { SocketMap } from "../../storage/socketMap";
|
||||||
|
|
||||||
export default (io: Server, socket: Socket) => {
|
export default (io: Server, socket: Socket) => {
|
||||||
socket.on(
|
socket.on(
|
||||||
|
@ -45,9 +47,36 @@ export default (io: Server, socket: Socket) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit("package-sync-awareness", {
|
console.log(MissionDocHelper.getAwarenessEditors(missionId));
|
||||||
update: [], // do awareness self
|
socket.emit("package-init-awareness", {
|
||||||
source: "server",
|
update: MissionDocHelper.getAwarenessEditors(missionId),
|
||||||
|
type: "editors",
|
||||||
|
});
|
||||||
|
socket.emit("package-init-awareness", {
|
||||||
|
update: MissionDocHelper.getAwarenessState(missionId),
|
||||||
|
type: "state",
|
||||||
|
});
|
||||||
|
|
||||||
|
let newEditor = {
|
||||||
|
socketId: socket.id,
|
||||||
|
data: {
|
||||||
|
username: SocketMap.read(socket.id).username,
|
||||||
|
firstname: SocketMap.read(socket.id).firstname,
|
||||||
|
lastname: SocketMap.read(socket.id).lastname,
|
||||||
|
color: randomColor({ format: "hex" }),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
MissionMap.updateAwareness(missionId, {
|
||||||
|
action: "update",
|
||||||
|
socketId: newEditor.socketId,
|
||||||
|
store: "editors",
|
||||||
|
update: newEditor.data,
|
||||||
|
});
|
||||||
|
socket.to(missionId).emit("package-sync-awareness", {
|
||||||
|
update: newEditor.data,
|
||||||
|
socketId: socket.id,
|
||||||
|
action: "update",
|
||||||
|
type: "editors",
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -124,16 +153,23 @@ export default (io: Server, socket: Socket) => {
|
||||||
"mission:sync-client-awareness",
|
"mission:sync-client-awareness",
|
||||||
handleEvent(
|
handleEvent(
|
||||||
{ type: "create", section: "operation", module: "mission" },
|
{ type: "create", section: "operation", module: "mission" },
|
||||||
async (data: { update: Array<number>; timestamp: number }) => {
|
async (data: EditorState) => {
|
||||||
const socketRooms = Array.from(socket.rooms).filter((room) => room !== socket.id && room !== "home");
|
const socketRooms = Array.from(socket.rooms).filter((room) => room !== socket.id && room !== "home");
|
||||||
try {
|
try {
|
||||||
MissionMap.updateAwareness(socketRooms[0], new Uint8Array(data.update));
|
MissionMap.updateAwareness(socketRooms[0], {
|
||||||
|
action: "update",
|
||||||
|
store: "state",
|
||||||
|
update: data,
|
||||||
|
socketId: socket.id,
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: "package-sync-awareness",
|
type: "package-sync-awareness",
|
||||||
answer: {
|
answer: {
|
||||||
update: data.update,
|
type: "state",
|
||||||
source: socket.id,
|
action: "update",
|
||||||
|
update: data,
|
||||||
|
socketId: socket.id,
|
||||||
},
|
},
|
||||||
room: socketRooms[0],
|
room: socketRooms[0],
|
||||||
};
|
};
|
||||||
|
@ -163,6 +199,32 @@ export default (io: Server, socket: Socket) => {
|
||||||
MissionMap.delete(socketRooms[0]);
|
MissionMap.delete(socketRooms[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MissionMap.updateAwareness(socketRooms[0], {
|
||||||
|
action: "remove",
|
||||||
|
store: "editors",
|
||||||
|
update: undefined,
|
||||||
|
socketId: socket.id,
|
||||||
|
});
|
||||||
|
io.to(socketRooms[0]).emit("package-sync-awareness", {
|
||||||
|
type: "editors",
|
||||||
|
update: undefined,
|
||||||
|
action: "remove",
|
||||||
|
socketId: socket.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
MissionMap.updateAwareness(socketRooms[0], {
|
||||||
|
action: "remove",
|
||||||
|
store: "state",
|
||||||
|
update: undefined,
|
||||||
|
socketId: socket.id,
|
||||||
|
});
|
||||||
|
io.to(socketRooms[0]).emit("package-sync-awareness", {
|
||||||
|
type: "state",
|
||||||
|
update: undefined,
|
||||||
|
action: "remove",
|
||||||
|
socketId: socket.id,
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: "deleted",
|
type: "deleted",
|
||||||
answer: "leave instance",
|
answer: "leave instance",
|
||||||
|
|
|
@ -39,6 +39,8 @@ export default async function authenticateSocket(socket: Socket, next: Function)
|
||||||
socketId: socket.id,
|
socketId: socket.id,
|
||||||
userId: decoded.userId,
|
userId: decoded.userId,
|
||||||
username: decoded.username,
|
username: decoded.username,
|
||||||
|
firstname: decoded.firstname,
|
||||||
|
lastname: decoded.lastname,
|
||||||
isOwner: decoded.isOwner,
|
isOwner: decoded.isOwner,
|
||||||
permissions: decoded.permissions,
|
permissions: decoded.permissions,
|
||||||
isWebApiRequest: decoded?.sub == "webapi_access_token",
|
isWebApiRequest: decoded?.sub == "webapi_access_token",
|
||||||
|
|
Loading…
Add table
Reference in a new issue