summaryrefslogtreecommitdiff
path: root/server.js
diff options
context:
space:
mode:
authorTom Smeding <tom@tomsmeding.com>2022-08-22 15:28:10 +0200
committerTom Smeding <tom@tomsmeding.com>2022-08-22 15:28:10 +0200
commitd1c02019db9a6fb2ab053091c9a4a32dc00b8b50 (patch)
treedbe9b8846f14d0aa65bb34cdcb0cc8c4d7031d1f /server.js
Initial
Diffstat (limited to 'server.js')
-rwxr-xr-xserver.js180
1 files changed, 180 insertions, 0 deletions
diff --git a/server.js b/server.js
new file mode 100755
index 0000000..21d9094
--- /dev/null
+++ b/server.js
@@ -0,0 +1,180 @@
+#!/usr/bin/env node
+const express = require("express");
+const http = require("http");
+const socketio = require("socket.io");
+const fs = require("fs");
+
+const [DBFILE, PORT] = (() => {
+ if (process.argv.length == 3) {
+ return [process.argv[2], 8000];
+ } else if (process.argv.length == 4) {
+ return [process.argv[2], +process.argv[3]];
+ } else {
+ console.log("Usage: ./server.js <dbfile.txt> [port]");
+ process.exit(1);
+ }
+})();
+
+const app = express();
+const httpServer = http.Server(app);
+const io = socketio(httpServer);
+
+const STATIC = __dirname + "/static";
+
+
+// ------------------------------
+// "database"
+// ------------------------------
+
+class Database {
+ #filename;
+ #list;
+ #lastbackup;
+
+ constructor(filename) {
+ this.#filename = filename;
+ this.#list = JSON.parse(fs.readFileSync(this.#filename));
+ this.#lastbackup = new Date();
+ }
+
+ add_new(string) {
+ for (let i = 0; i < this.#list.length; i++) {
+ if (this.#list[i][1] == string) {
+ return "already existed";
+ }
+ }
+
+ this.#list.push([0, string]);
+ this.#sort();
+ this.#persist();
+
+ return null;
+ }
+
+ set_votes(string, votes) {
+ for (let i = 0; i < this.#list.length; i++) {
+ if (this.#list[i][1] == string) {
+ this.#list[i][0] = votes;
+ this.#sort();
+ this.#persist();
+ return null;
+ }
+ }
+
+ return `'${string}' does not exist`;
+ }
+
+ remove(string) {
+ for (let i = 0; i < this.#list.length; i++) {
+ if (this.#list[i][1] == string) {
+ this.#list.splice(i, 1);
+ this.#persist();
+ return null;
+ }
+ }
+
+ return "does not exist";
+ }
+
+ get() {
+ return this.#list;
+ }
+
+ #sort() {
+ this.#list.sort((a, b) => {
+ if (a[0] != b[0]) return b[0] - a[0];
+ if (a[1] < b[1]) return -1;
+ if (a[1] > b[1]) return 1;
+ return 0;
+ });
+ }
+
+ #persist() {
+ fs.writeFile(this.#filename, JSON.stringify(this.#list), err => {
+ if (err != null) {
+ console.error("Error writing to file:", err);
+ console.log(JSON.stringify(this.#list));
+ }
+ });
+
+ const now = new Date();
+ if (now - this.#lastbackup > 60 * 1000) {
+ const dotidx = this.#filename.lastIndexOf(".");
+ const bakfname =
+ dotidx == -1
+ ? this.#filename + now.getTime()
+ : this.#filename.slice(0, dotidx) + "." + now.getTime() + this.#filename.slice(dotidx);
+ fs.writeFile(bakfname, JSON.stringify(this.#list), err => {
+ if (err != null) {
+ console.error("Error copying to backup file:", err);
+ } else {
+ console.log(`Copied to ${bakfname}`);
+ }
+ });
+
+ this.#lastbackup = now;
+ }
+ }
+};
+
+const database = new Database(DBFILE);
+
+
+// ------------------------------
+// Express routes
+// ------------------------------
+
+app.use(express.static(STATIC));
+
+app.get("/", (req, res) => {
+ res.sendFile(STATIC + "/index.html");
+});
+
+
+// ------------------------------
+// socket.io bindings
+// ------------------------------
+
+let next_socket_id = 1;
+let num_connected = 0;
+
+io.on("connection", socket => {
+ const socket_id = next_socket_id++;
+ if (++num_connected >= 2) {
+ socket.emit("alert", `You're user number ${num_connected}, multi-user settings will mess up!`);
+ }
+ console.log(`new socket connection id=${socket_id} (nc=${num_connected})`);
+
+ socket.on("disconnect", () => {
+ num_connected--;
+ console.log(`disconnect id=${socket_id} (nc=${num_connected})`);
+ });
+
+ socket.on("new", string => {
+ const res = database.add_new(string);
+ if (res != null) socket.emit("error", res);
+ });
+
+ socket.on("set_votes", (string, votes) => {
+ const res = database.set_votes(string, votes);
+ if (res != null) socket.emit("error", res);
+ });
+
+ socket.on("delete", string =>{
+ const res = database.remove(string);
+ if (res != null) socket.emit("error", res);
+ });
+
+ socket.emit("init", database.get());
+});
+
+
+// ------------------------------
+// setup
+// ------------------------------
+
+const server = httpServer.listen(PORT, () => {
+ const host = server.address().address;
+ const port = server.address().port;
+ console.log("Server listening at http://" + host + ":" + port);
+});