ff-operation-server/src/websocket/endpoints/missionManagement.ts

144 lines
4.6 KiB
TypeScript
Raw Normal View History

2025-02-26 16:26:56 +01:00
import { Server, Socket } from "socket.io";
import { handleEvent } from "../handleEvent";
2025-02-28 14:02:21 +01:00
import { MissionMap, missionStoreModel } from "../../storage/missionMap";
2025-02-26 16:26:56 +01:00
import * as Y from "yjs";
2025-02-28 14:02:21 +01:00
import MissionDocHelper from "../../helpers/missionDocHelper";
2025-02-26 16:26:56 +01:00
export default (io: Server, socket: Socket) => {
socket.on(
"mission:join",
handleEvent(
{ type: "read", section: "operation", module: "mission" },
2025-02-28 14:02:21 +01:00
async (missionId: string, clientLastUpdate: missionStoreModel) => {
2025-02-26 16:26:56 +01:00
socket.rooms.forEach((room) => {
if (room !== socket.id && room != "home") {
socket.leave(room);
}
});
try {
2025-02-28 14:02:21 +01:00
socket.join(missionId);
2025-02-26 16:26:56 +01:00
2025-02-28 14:02:21 +01:00
await MissionDocHelper.populateDoc(missionId);
const mission = MissionMap.read(missionId);
2025-02-26 16:26:56 +01:00
2025-02-28 14:02:21 +01:00
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",
});
2025-02-27 15:08:51 +01:00
}
2025-02-26 16:26:56 +01:00
return {
2025-02-27 15:08:51 +01:00
type: "status-mission:join",
answer: { status: "success" },
2025-02-26 16:26:56 +01:00
};
} catch (error) {
return { type: "status-join:join", answer: { status: "failed", msg: error.message } };
}
},
socket
)
);
socket.on(
2025-02-28 14:02:21 +01:00
"mission:sync-client-updates",
2025-02-26 16:26:56 +01:00
handleEvent(
2025-02-28 14:02:21 +01:00
{ 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" },
2025-02-26 16:26:56 +01:00
async (data: any) => {
const socketRooms = Array.from(socket.rooms).filter((room) => room !== socket.id && room !== "home");
try {
const mission = MissionMap.read(socketRooms[0]);
2025-02-28 14:02:21 +01:00
const missingUpdates = Y.encodeStateAsUpdate(mission.doc, data.stateVector);
2025-02-26 16:26:56 +01:00
return {
type: "package-sync",
2025-02-28 14:02:21 +01:00
answer: {
update: missingUpdates,
timestamp: mission.timestamp,
source: "server",
},
2025-02-26 16:26:56 +01:00
};
} catch (error) {
2025-02-28 14:02:21 +01:00
return { type: "status-mission:sync-get-missing-updates", answer: { status: "failed", msg: error.message } };
2025-02-26 16:26:56 +01:00
}
},
socket
)
);
socket.on(
"mission:leave",
handleEvent(
{ type: "read", section: "operation", module: "mission" },
async (data: any) => {
const socketRooms = Array.from(socket.rooms).filter((room) => room !== socket.id && room !== "home");
socket.leave(socketRooms[0]);
const clients = io.sockets.adapter.rooms.get(socketRooms[0]);
if (!clients || clients.size == 0) {
MissionMap.delete(socketRooms[0]);
}
return {
type: "deleted",
answer: "leave instance",
};
},
socket
)
);
};