@needle-tools/networking
Version:
Networking backend functionality for Needle Engine
157 lines (137 loc) • 5.23 kB
JavaScript
(() => {
const Storage = require("./storage");
module.exports.loadState = async function (roomName) {
const res = await Storage.loadRoomState(roomName);
if ("state" in res) {
return res.state;
}
return {};
};
module.exports.saveState = async function (roomName, state) {
if (!roomName || !state) {
console.warn("Invalid room or state, can not persist data");
return;
}
await Storage.saveRoomState(roomName, state);
return;
};
// notification event that someone joined their room
module.exports.sendUpdate_UserJoinedRoom = function (ws, data) {
if (!ws || ws.readyState !== ws.OPEN) return;
ws.send(JSON.stringify({ key: "user-joined-room", data: data }));
};
// notification event that someone left their room
module.exports.sendUpdate_UserLeftRoom = function (ws, data) {
if (!ws || ws.readyState !== ws.OPEN) return;
ws.send(JSON.stringify({ key: "user-left-room", data: data }));
};
// notification event that current user (you) joined room
module.exports.sendUpdate_JoinedRoom = function (ws, roomName, inRoomIds, viewId, allowEditing) {
if (!ws || ws.readyState !== ws.OPEN) return;
console.log("send joined room", roomName);
ws.send(
JSON.stringify({ key: "joined-room", room: roomName, inRoom: inRoomIds, viewId: viewId, allowEditing: allowEditing })
);
};
// notification event that user (you) left a room
module.exports.sendUpdate_LeftRoom = function (ws, roomName) {
if (!ws || ws.readyState !== ws.OPEN) return;
ws.send(JSON.stringify({ key: "left-room", room: roomName }));
};
module.exports.sendUpdate_RoomStateSent = function (ws, roomName) {
if (!ws || ws.readyState !== ws.OPEN) return;
ws.send(
JSON.stringify({ key: "room-state-sent", room: roomName })
);
};
module.exports.sendUpdate_GainedOwnershipBroadcast = function (
ws,
ownerId,
guid
) {
if (!ws || ws.readyState !== ws.OPEN) return;
ws.send(
JSON.stringify({
key: "gained-ownership-broadcast",
data: { guid: guid, owner: ownerId },
})
);
};
module.exports.sendUpdate_LostOwnershipBroadcast = function (
ws,
prevOwner,
guid
) {
if (!ws || ws.readyState !== ws.OPEN) return;
ws.send(
JSON.stringify({
key: "lost-ownership-broadcast",
data: { guid: guid, owner: prevOwner },
})
);
};
module.exports.sendUpdate_LostOwnership = function (ws, guid) {
if (!ws || ws.readyState !== ws.OPEN) return;
console.log(`User ${ws.id} lost ownership ${guid}`);
ws.send(JSON.stringify({ key: "lost-ownership", data: guid }));
};
module.exports.sendUpdate_GainedOwnership = function (ws, guid) {
if (!ws || ws.readyState !== ws.OPEN) return;
console.log(ws.id + " gained ownership " + guid);
ws.send(JSON.stringify({ key: "gained-ownership", data: guid }));
};
module.exports.sendUpdate_IsOwner = function (ws, guid, bool) {
if (!ws || ws.readyState !== ws.OPEN) return;
ws.send(
JSON.stringify({
key: "response-is-owner",
data: { guid: guid, value: bool },
})
);
};
module.exports.sendUpdate_HasOwner = function (ws, guid, bool) {
if (!ws || ws.readyState !== ws.OPEN) return;
ws.send(
JSON.stringify({
key: "response-has-owner",
data: { guid: guid, value: bool },
})
);
};
module.exports.getUniqueID = function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + "-" + s4();
};
// this is used to generate view-only guid from room id and secret
// we also need to decrypt to get the original room name from the generated id
// this is necessary so a viewer can also open a room and the server knows which room to open/load from this id
const crypto = require("crypto");
// make buffer constant so it doesnt change when server reloads (instead of 16 random bytes)
const iv = Buffer.from([0xe6, 0x4d, 0xf7, 0x25, 0x4d, 0x50, 0xbe, 0x5b, 0xf8, 0x79, 0x0b, 0xf6, 0x16, 0x07, 0x71, 0x82]);
const algorithm = 'aes-256-ctr';
const fallbackKey = "40edb098f15eac40920111a4e50b0d15";
module.exports.getUniqueIDWithSalt = function (key) {
let salt = process.env.VIEW_ONLY_SALT;
if (!salt) {
console.error("Missing VIEW_ONLY_SALT environment variable");
salt = fallbackKey;
}
const cipher = crypto.createCipheriv(algorithm, salt, iv);
const encrypted = Buffer.concat([cipher.update(key), cipher.final()]);
return encrypted.toString("hex");
};
module.exports.decryptID = function (id) {
let salt = process.env.VIEW_ONLY_SALT;
if (!salt) {
console.error("Missing VIEW_ONLY_SALT environment variable");
salt = fallbackKey;
}
const decipher = crypto.createDecipheriv(algorithm, salt, iv);
const decrpyted = Buffer.concat([decipher.update(Buffer.from(id, 'hex')), decipher.final()]);
return decrpyted.toString();
}
})();