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

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