riju/backend/server.js

130 lines
3.3 KiB
JavaScript

import http from "http";
import https from "https";
import path from "path";
import express from "express";
import ws from "express-ws";
import _ from "lodash";
import * as api from "./api.js";
import { aliases, langs } from "./langs.js";
import { log } from "./util.js";
const host = process.env.HOST || "localhost";
const port = parseInt(process.env.PORT || "") || 6119;
const tlsPort = parseInt(process.env.TLS_PORT || "") || 6120;
const useTLS = process.env.TLS ? true : false;
const analyticsEnabled = process.env.ANALYTICS ? true : false;
const app = express();
app.set("query parser", (qs) => new URLSearchParams(qs));
app.set("view engine", "ejs");
app.get("/", (_, res) => {
if (Object.keys(langs).length > 0) {
res.render(path.resolve("frontend/pages/index"), {
langs,
analyticsEnabled,
});
} else {
res
.status(503)
.send("Encountered unexpected error while loading languages\n");
}
});
for (const [lang, { aliases }] of Object.entries(langs)) {
if (aliases) {
for (const alias of aliases) {
app.get(`/${_.escapeRegExp(alias)}`, (_, res) => {
res.redirect(301, `/${lang}`);
});
}
}
}
app.get("/:lang", (req, res) => {
const lang = req.params.lang;
const lowered = lang.toLowerCase();
if (lowered !== lang) {
res.redirect(301, `/${lowered}`);
return;
}
const canonical = aliases[lang];
if (!canonical) {
res.status(404).send(`No such language: ${lang}\n`);
} else if (canonical !== lang) {
res.redirect(301, `/${canonical}`);
return;
}
res.render(path.resolve("frontend/pages/app"), {
config: langs[lang],
analyticsEnabled,
});
});
app.use("/css", express.static("frontend/styles"));
app.use("/js", express.static("frontend/out"));
function addWebsocket(baseApp, httpsServer) {
const app = ws(baseApp, httpsServer).app;
app.ws("/api/v1/ws", (ws, req) => {
try {
const lang = req.query.get("lang");
if (!lang) {
ws.send(
JSON.stringify({
event: "error",
errorMessage: "No language specified",
})
);
ws.close();
} else if (!langs[lang]) {
ws.send(
JSON.stringify({
event: "error",
errorMessage: `No such language: ${lang}`,
})
);
ws.close();
} else {
new api.Session(ws, lang, console.log).setup();
}
} catch (err) {
log.error("Unexpected error while handling websocket:", err);
}
});
return app;
}
if (useTLS) {
const httpsServer = https.createServer(
{
key: Buffer.from(process.env.TLS_PRIVATE_KEY || "", "base64").toString(
"ascii"
),
cert: Buffer.from(process.env.TLS_CERTIFICATE || "", "base64").toString(
"ascii"
),
},
app
);
addWebsocket(app, httpsServer);
httpsServer.listen(tlsPort, host, () =>
console.log(`Listening on https://${host}:${tlsPort}`)
);
const server = http
.createServer((req, res) => {
res.writeHead(301, {
Location: "https://" + req.headers["host"] + req.url,
});
res.end();
})
.listen(port, host, () =>
console.log(`Listening on http://${host}:${port}`)
);
} else {
addWebsocket(app, undefined);
const server = app.listen(port, host, () =>
console.log(`Listening on http://${host}:${port}`)
);
}