mission management by timestamp
This commit is contained in:
parent
1646d0d6ca
commit
8aaeaa7e0f
5 changed files with 136 additions and 34 deletions
21
package-lock.json
generated
21
package-lock.json
generated
|
@ -37,6 +37,7 @@
|
|||
"sqlite3": "^5.1.7",
|
||||
"typeorm": "^0.3.20",
|
||||
"uuid": "^10.0.0",
|
||||
"y-protocols": "^1.0.6",
|
||||
"yjs": "^13.6.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -4831,6 +4832,26 @@
|
|||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/y-protocols": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.6.tgz",
|
||||
"integrity": "sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lib0": "^0.2.85"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "GitHub Sponsors ❤",
|
||||
"url": "https://github.com/sponsors/dmonad"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"yjs": "^13.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
"sqlite3": "^5.1.7",
|
||||
"typeorm": "^0.3.20",
|
||||
"uuid": "^10.0.0",
|
||||
"y-protocols": "^1.0.6",
|
||||
"yjs": "^13.6.23"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
29
src/helpers/missionDocHelper.ts
Normal file
29
src/helpers/missionDocHelper.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
import * as Y from "yjs";
|
||||
import { MissionMap } from "../storage/missionMap";
|
||||
|
||||
export default abstract class MissionDocHelper {
|
||||
public static async populateDoc(missionId: string) {
|
||||
// get Data from database
|
||||
const doc = new Y.Doc();
|
||||
doc.getMap("form");
|
||||
doc.getText("editor");
|
||||
|
||||
// const ymap = ydoc.getMap('myMap');
|
||||
// ymap.set('titel', 'Mein Dokument');
|
||||
// ymap.set('inhalt', 'Hier ist der initiale Inhalt');
|
||||
// ymap.set('erstelltAm', new Date().toISOString());
|
||||
|
||||
// const yarray = ydoc.getArray('meineArray');
|
||||
// yarray.push(['Element 1', 'Element 2', 'Element 3']);
|
||||
|
||||
// const ytext = ydoc.getText('meinText');
|
||||
// ytext.insert(0, 'Hier ist ein initialer Text');
|
||||
|
||||
MissionMap.write(missionId, { missionId, doc, timestamp: 0 }, true);
|
||||
}
|
||||
|
||||
public static async saveDoc(missionId: string) {
|
||||
// store Data to database
|
||||
const mission = MissionMap.read(missionId);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ import * as Y from "yjs";
|
|||
export interface missionStoreModel {
|
||||
missionId: string;
|
||||
doc: Y.Doc;
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,6 +16,18 @@ export abstract class MissionMap {
|
|||
if (!this.exists(identifier) || overwrite) this.store.set(identifier, data);
|
||||
}
|
||||
|
||||
public static updateState(identifier: string, data: Uint8Array): void {
|
||||
let mission = this.read(identifier);
|
||||
Y.applyUpdate(mission.doc, data);
|
||||
this.write(identifier, mission, true);
|
||||
}
|
||||
|
||||
public static updateTimestamp(identifier: string, data: number): void {
|
||||
let mission = this.read(identifier);
|
||||
mission.timestamp = data;
|
||||
this.write(identifier, mission, true);
|
||||
}
|
||||
|
||||
public static read(identifier: string): missionStoreModel {
|
||||
return this.store.get(identifier);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import { Server, Socket } from "socket.io";
|
||||
import { handleEvent } from "../handleEvent";
|
||||
import { MissionMap } from "../../storage/missionMap";
|
||||
import { MissionMap, missionStoreModel } from "../../storage/missionMap";
|
||||
import * as Y from "yjs";
|
||||
import MissionDocHelper from "../../helpers/missionDocHelper";
|
||||
|
||||
export default (io: Server, socket: Socket) => {
|
||||
socket.on(
|
||||
"mission:join",
|
||||
handleEvent(
|
||||
{ type: "read", section: "operation", module: "mission" },
|
||||
async (data: string, initialized: boolean) => {
|
||||
async (missionId: string, clientLastUpdate: missionStoreModel) => {
|
||||
socket.rooms.forEach((room) => {
|
||||
if (room !== socket.id && room != "home") {
|
||||
socket.leave(room);
|
||||
|
@ -16,33 +17,35 @@ export default (io: Server, socket: Socket) => {
|
|||
});
|
||||
|
||||
try {
|
||||
const doc = new Y.Doc();
|
||||
doc.getMap("form");
|
||||
doc.getText("editor");
|
||||
socket.join(missionId);
|
||||
|
||||
// const ymap = ydoc.getMap('myMap');
|
||||
// ymap.set('titel', 'Mein Dokument');
|
||||
// ymap.set('inhalt', 'Hier ist der initiale Inhalt');
|
||||
// ymap.set('erstelltAm', new Date().toISOString());
|
||||
await MissionDocHelper.populateDoc(missionId);
|
||||
const mission = MissionMap.read(missionId);
|
||||
|
||||
// const yarray = ydoc.getArray('meineArray');
|
||||
// yarray.push(['Element 1', 'Element 2', 'Element 3']);
|
||||
|
||||
// const ytext = ydoc.getText('meinText');
|
||||
// ytext.insert(0, 'Hier ist ein initialer Text');
|
||||
|
||||
// get mission data
|
||||
MissionMap.write(data, {
|
||||
missionId: data,
|
||||
doc,
|
||||
});
|
||||
|
||||
const mission = MissionMap.read(data);
|
||||
|
||||
socket.join(data);
|
||||
|
||||
if (!initialized) {
|
||||
socket.emit("package-mission", Y.encodeStateAsUpdate(mission.doc));
|
||||
if (clientLastUpdate && clientLastUpdate.timestamp) {
|
||||
// Prüfe, ob der Client aktuell ist oder nicht
|
||||
if (mission.timestamp > clientLastUpdate.timestamp) {
|
||||
// Server hat neuere Daten, sende vollständigen State
|
||||
socket.emit("package-sync", {
|
||||
update: Y.encodeStateAsUpdate(mission.doc),
|
||||
timestamp: mission.timestamp,
|
||||
source: "server",
|
||||
});
|
||||
} else {
|
||||
// Client hat aktuellere oder gleich aktuelle Daten
|
||||
socket.emit("sync-get-missing-updates", {
|
||||
stateVector: Y.encodeStateVector(mission.doc),
|
||||
timestamp: mission.timestamp,
|
||||
source: "server",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Client hat keine Zeitstempel-Info, sende vollständigen State
|
||||
socket.emit("package-sync", {
|
||||
update: Y.encodeStateAsUpdate(mission.doc),
|
||||
timestamp: mission.timestamp,
|
||||
source: "server",
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -58,23 +61,58 @@ export default (io: Server, socket: Socket) => {
|
|||
);
|
||||
|
||||
socket.on(
|
||||
"mission:sync",
|
||||
"mission:sync-client-updates",
|
||||
handleEvent(
|
||||
{ type: "read", section: "operation", module: "mission" },
|
||||
{ type: "create", section: "operation", module: "mission" },
|
||||
async (data: { update: Array<number>; timestamp: number }) => {
|
||||
const socketRooms = Array.from(socket.rooms).filter((room) => room !== socket.id && room !== "home");
|
||||
try {
|
||||
MissionMap.updateState(socketRooms[0], new Uint8Array(data.update));
|
||||
|
||||
return {
|
||||
type: "package-sync",
|
||||
answer: {
|
||||
update: data.update,
|
||||
timestamp: data.timestamp,
|
||||
source: "client",
|
||||
},
|
||||
room: socketRooms[0],
|
||||
};
|
||||
} catch (error) {
|
||||
const mission = MissionMap.read(socketRooms[0]);
|
||||
socket.emit("package-sync", {
|
||||
update: Y.encodeStateAsUpdate(mission.doc),
|
||||
timestamp: mission.timestamp,
|
||||
source: "server",
|
||||
error: true,
|
||||
});
|
||||
return { type: "status-mission:sync-client-updates", answer: { status: "failed", msg: error.message } };
|
||||
}
|
||||
},
|
||||
socket
|
||||
)
|
||||
);
|
||||
|
||||
socket.on(
|
||||
"mission:sync-get-missing-updates",
|
||||
handleEvent(
|
||||
{ type: "create", section: "operation", module: "mission" },
|
||||
async (data: any) => {
|
||||
const socketRooms = Array.from(socket.rooms).filter((room) => room !== socket.id && room !== "home");
|
||||
try {
|
||||
const mission = MissionMap.read(socketRooms[0]);
|
||||
Y.applyUpdate(mission.doc, new Uint8Array(data));
|
||||
const missingUpdates = Y.encodeStateAsUpdate(mission.doc, data.stateVector);
|
||||
|
||||
socket.emit("status-mission:sync", { status: "success" });
|
||||
return {
|
||||
type: "package-sync",
|
||||
answer: data,
|
||||
room: socketRooms[0],
|
||||
answer: {
|
||||
update: missingUpdates,
|
||||
timestamp: mission.timestamp,
|
||||
source: "server",
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
return { type: "status-mission:sync", answer: { status: "failed", msg: error.message } };
|
||||
return { type: "status-mission:sync-get-missing-updates", answer: { status: "failed", msg: error.message } };
|
||||
}
|
||||
},
|
||||
socket
|
||||
|
|
Loading…
Add table
Reference in a new issue