const express = require('express'); const fs = require('fs'); const path = require('path'); const crypto = require('crypto'); const port = 8080; const log_disabled = false; var app = express(); const cache = { }; if (log_disabled) { console.prototype._log = console.log; console.prototype.log = function (...args) { } } app.use("/files", express.static("projects")); function get_indexes(project_id) { if (cache[project_id]) { let indexes = ""; for (let path in cache[project_id]) { indexes += `${path} ${cache[project_id][path]}\n`; } return indexes.trim(); } else if (fs.existsSync(path.join(__dirname, "projects", project_id))) { let files = fs.readdirSync(path.join(__dirname, "projects", project_id)); let indexes = ""; cache[project_id] = {}; for (let file of files) { let fileContents = fs.readFileSync(path.join(__dirname, "projects", project_id, file)); let hash = crypto.createHash("md5"); hash.update(fileContents); cache[project_id][file] = hash.digest('hex'); indexes += `${file} ${cache[project_id][file]}\n`; } return indexes.trim(); } else { return undefined; } } app.get("/indexes/:project(\\w+)", (req, res) => { let project_id = req.params['project']; let indexes = get_indexes(project_id); if (indexes != undefined) { res.send(indexes); } else { res.sendStatus(404); } }); app.use(express.urlencoded({ extended: false })); function diff(current, checked) { let lines_current = current.split('\n').map(l => l.trim()).filter(l => l != ""); let lines_checked = checked.split('\n').map(l => l.trim()).filter(l => l != ""); let filenames_checked = lines_checked.map(l => { let split = l.split(" "); console.log(`filename map: ${split}`); return split[0] || l; }); console.log(lines_current, lines_checked); console.log(filenames_checked); let result = ""; for (let line of lines_current) { if (line.length != 0) { let split = line.split(" "); console.log(`split: ${split}`); let index = filenames_checked.indexOf(split[0]); console.log(`index: ${index} filenames: ${filenames_checked}`); if (index == -1 || filenames_checked[index] == undefined) { result += `${split[0]} download\n`; continue; } let filename = filenames_checked[index]; let hash = lines_checked[index].split(" ")[1].trim(); console.log(`expected: ${split[0]} hash ${split[1]} found: ${filename} hash ${hash}`); if (split[0] != filename || split[1] != hash) { result += `${split[0]} download\n`; } console.log(`popping line ${index}, current: ${lines_checked}`); filenames_checked.splice(index, 1); lines_checked.splice(index, 1); console.log(`result: ${lines_checked}`); } } // now take care of the rest. if (Array.isArray(lines_checked)) { for (let line of lines_checked) { console.log(`delete line ${line}`); result += `${line.split(" ")[0]} delete\n`; } } else { // only 1 file left! result += `${lines_checked.split(" ")[0]} delete\n`; } return result; } app.post("/updates/:project(\\w+)", (req, res) => { let project_id = req.params['project']; const body = typeof req.body == "string" ? req.body : (req.body.content || ""); // console.log(req.body); // console.log(`${req.body}, ${typeof req.body}`); // console.log(`${body}`); let adjustedBody = body.replace(/\r/, ""); let indexes = get_indexes(project_id); let difference = diff(indexes, adjustedBody); if (difference.length > 0) { res.send(difference); } else { res.sendStatus(204); } }); app.all("/", (req, res) => { res.send("OK."); }); app.listen(port, () => { console.log(`listening on ${port}`); });