Shopping List v2.0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

server.js 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. let WebSocket = require("ws");
  2. let createFileServer = require("./filesrv");
  3. let fs = require("fs");
  4. let datafile = "db.json";
  5. let scratchfile = ".db.scratch";
  6. let key = process.env.KEY;
  7. if (!key) {
  8. console.log("Environmnt variable 'KEY' not set.");
  9. process.exit(1);
  10. }
  11. console.log("Using key:", key);
  12. let server = createFileServer("../client/public");
  13. let wss = new WebSocket.Server({ server });
  14. function deserialize(defaults) {
  15. try {
  16. let json = fs.readFileSync(datafile);
  17. return JSON.parse(json);
  18. } catch (err) {
  19. return defaults;
  20. }
  21. }
  22. function serialize(data) {
  23. fs.writeFileSync(scratchfile, JSON.stringify(data));
  24. fs.renameSync(scratchfile, datafile);
  25. }
  26. let data = deserialize({
  27. items: { "0": "foo", "2": "bar" },
  28. words: {},
  29. nextIdx: 3,
  30. });
  31. let conns = [];
  32. let connID = 0;
  33. function ack(conn, msg, reply = {}) {
  34. reply.type = "ack";
  35. reply.ackID = msg.ackID;
  36. conn.sock.send(JSON.stringify(reply));
  37. }
  38. function broadcast(from, obj) {
  39. for (let conn of conns) {
  40. if (!conn) continue;
  41. if (conn != from)
  42. conn.sock.send(JSON.stringify(obj));
  43. }
  44. }
  45. function onMessage(conn, msg) {
  46. if (msg.type == "init") {
  47. if (!msg.key || msg.key != key)
  48. return ack(conn, msg, { error: "Invalid key." });
  49. ack(conn, msg, { data });
  50. conn.ready = true;
  51. conns[conn.id] = conn;
  52. return;
  53. }
  54. if (!conn.ready)
  55. return ack(conn, msg, { error: "Not initialized." });
  56. switch (msg.type) {
  57. case "item-add":
  58. if (typeof msg.content != "string")
  59. return ack(conn, msg, { error: "Missing content." });
  60. let content = msg.content.toLowerCase();
  61. let index = data.nextIdx.toString();
  62. data.nextIdx = (data.nextIdx + 1) % 2048;
  63. data.items[index] = content;
  64. if (data.words[content] == null)
  65. data.words[content] = 0;
  66. data.words[content] += 1;
  67. ack(conn, msg, { index });
  68. broadcast(conn, { type: "item-add", content, index });
  69. serialize(data);
  70. break;
  71. case "item-del":
  72. if (typeof msg.index != "string")
  73. return ack(conn, msg, { error: "Missing index." });
  74. delete data.items[msg.index];
  75. ack(conn, msg);
  76. broadcast(conn, { type: "item-del", index: msg.index });
  77. serialize(data);
  78. break;
  79. }
  80. }
  81. wss.on("connection", sock => {
  82. let conn = {
  83. sock,
  84. ready: false,
  85. id: connID,
  86. };
  87. connID = (connID + 1) % 2048;
  88. sock.on("close", () => {
  89. delete conns[conn.id];
  90. });
  91. sock.on("message", msg => {
  92. let obj;
  93. try {
  94. obj = JSON.parse(msg);
  95. } catch (err) {
  96. console.error("Client message has invalid JSON:", err);
  97. console.error(err);
  98. return;
  99. }
  100. onMessage(conn, obj);
  101. });
  102. });
  103. let port = process.env.PORT ? parseInt(process.env.PORT) : 8080;
  104. server.listen(port);
  105. console.log(`Listening on port ${port}.`);