Skip to content

Commit

Permalink
feat: add support for vercel
Browse files Browse the repository at this point in the history
  • Loading branch information
Zxilly committed Sep 24, 2023
1 parent 32c8bca commit d447579
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 43 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,8 @@ dist
temp
docs
.idea/

.vercel
.env.local

.env*.local
2 changes: 2 additions & 0 deletions api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import server from "../dist/server";
export = server;
13 changes: 8 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,22 @@
"main": "./dist/index.js",
"bin": {
"lsct": "./dist/cli.js",
"lsct-s": "./dist/server.js"
"lsct-s": "./dist/server-cli.js"
},
"files": [
"dist"
"dist",
"public"
],
"scripts": {
"prebuild": "rimraf ./dist/",
"postbuild": "cpy --flat src/server.html dist",
"prebuild": "rimraf ./dist",
"build": "tsc -p src",
"clean": "rimraf ./dist ./docs ./node_modules",
"docs": "typedoc",
"lint": "eslint . && markdownlint .",
"lint:fix": "eslint . --fix && markdownlint . --fix",
"start": "tsx src/cli.ts",
"start-s": "tsx src/server.ts"
"start-s": "tsx src/server.ts",
"vercel-dev": "vercel dev"
},
"dependencies": {
"await-lock": "^2.2.2",
Expand All @@ -43,6 +44,7 @@
"express": "^4.18.2",
"html-entities": "^2.4.0",
"ics": "^3.5.0",
"ioredis": "^5.3.2",
"lodash": "^4.17.21",
"pangu": "^4.0.7",
"winston": "^3.10.0"
Expand All @@ -54,6 +56,7 @@
"@types/pangu": "^4.0.0",
"@typescript-eslint/eslint-plugin": "^6.7.2",
"@typescript-eslint/parser": "^6.7.2",
"@vercel/ncc": "^0.38.0",
"cpy-cli": "^5.0.0",
"cz-conventional-changelog": "3.3.0",
"eslint": "^8.50.0",
Expand Down
15 changes: 6 additions & 9 deletions src/server.html → public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,10 @@ <h2>语言</h2>
</div>
</div>
</main>
<script src="https://cdnjs.loli.net/ajax/libs/mdb-ui-kit/4.1.0/mdb.min.js" crossorigin="anonymous"
referrerpolicy="no-referrer"
<script src="https://cdnjs.loli.net/ajax/libs/mdb-ui-kit/6.4.1/mdb.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"
></script>
<script src="https://cdnjs.loli.net/ajax/libs/jquery/3.6.0/jquery.min.js" crossorigin="anonymous"
referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.loli.net/ajax/libs/clipboard.js/2.0.10/clipboard.min.js"
crossorigin="anonymous"
referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.loli.net/ajax/libs/jquery/3.7.1/jquery.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.loli.net/ajax/libs/clipboard.js/2.0.11/clipboard.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
function updateURL()
{
Expand All @@ -125,7 +121,9 @@ <h2>语言</h2>
if(lc) ojs.push("lc");
if(lg) ojs.push("lg");
if(nc) ojs.push("nc");
args.append("o", ojs.join(","));
if(ojs.length > 0) {
args.append("o", ojs.join(","));
}
}

//process lang
Expand Down Expand Up @@ -166,7 +164,6 @@ <h2>语言</h2>
{
copy.tooltip("hide");
}, 1000);
fetch(url);
}
});
}
Expand Down
24 changes: 24 additions & 0 deletions src/server-cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env node
import { Command } from "commander";
import { bin, version } from "../package.json";
import app from "./server";
import express from "express";

const command = new Command()
.name(Object.keys(bin)[1])
.version(version)
.option("-h, --host, <host>", "Host to listen on", "0.0.0.0")
.option("-p, --port, <port>", "Port to listen on", "8080");
command.parse();

const host = command.opts().host as string;
let port: number | string = command.opts().port as string;
port = parseInt(port, 10);

app.use(express.static(`${__dirname}/../public`));

app.listen(port, host, () =>
{
const logURL = `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}/`;
console.log(`LSCT server v${version} listening on ${logURL}`);
});
64 changes: 37 additions & 27 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
#!/usr/bin/env node
import express from "express";
import Lscontests, { Contest } from ".";
import { alloj } from "./lib/oj";
import { getLangDict } from "./locale";
import { convertTimestampToArray, createEvents, EventAttributes } from "ics";
import pangu from "pangu";
import { randomUUID } from "crypto";
import { Command } from "commander";
import { bin, version } from "../package.json";
import { readFileSync } from "fs";
import AwaitLock from "await-lock";
import Redis from "ioredis";

const app = express();

Expand All @@ -35,17 +32,9 @@ const logger = () =>
};
};

const web = readFileSync(`${__dirname}/server.html`).toString();

app.set("trust proxy", true);
app.use(logger());

app.get("/", (req, res) =>
{
res.set("Content-Type", "text/html");
res.send(web);
});

app.get("/ics", async (req, res) =>
{
const { language, l, ojs, o } = req.query;
Expand Down Expand Up @@ -77,6 +66,33 @@ const contestsCache: {
lastUpdate: 0
};

let redis: Redis = undefined as unknown as Redis;

const cacheKey = "lsct:cache";

async function exportContestCache()
{
await redis.set(cacheKey, JSON.stringify(contestsCache));
}

async function importContestCache()
{
redis = new Redis(process.env.REDIS_URL as string);
const payload = await redis.get(cacheKey);
if(payload)
{
const obj = JSON.parse(payload);
contestsCache.lastUpdate = obj.lastUpdate;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
contestsCache.contests = obj.contests.map((c: any) =>
{
c.startTime = new Date(c.startTime);
c.endTime = new Date(c.endTime);
return c;
});
}
}

const lock = new AwaitLock();

function icsPostProcess(value: string)
Expand All @@ -102,6 +118,10 @@ function icsPostProcess(value: string)
async function checkCache()
{
await lock.acquireAsync();
if(process.env.VERCEL)
{
await importContestCache();
}
try
{
if(contestsCache.lastUpdate < Date.now() - 1000 * 60 * 5)
Expand All @@ -112,6 +132,10 @@ async function checkCache()
c => c.endTime.getTime() - c.startTime.getTime() < 1000 * 60 * 60 * 24 * 2
); // ignore too long contests
contestsCache.lastUpdate = Date.now();
if(process.env.VERCEL)
{
await exportContestCache();
}
}
}
finally
Expand Down Expand Up @@ -156,18 +180,4 @@ async function getIcs(lang: string, ojs: string[])
return icsPostProcess(value);
}

const command = new Command()
.name(Object.keys(bin)[1])
.version(version)
.option("-h, --host, <host>", "Host to listen on", "0.0.0.0")
.option("-p, --port, <port>", "Port to listen on", "8080");
command.parse();

const host = command.opts().host as string;
let port: number | string = command.opts().port as string;
port = parseInt(port, 10);
app.listen(port, host, () =>
{
const logURL = `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}/`;
console.log(`LSCT server v${version} listening on ${logURL}`);
});
export = app;
5 changes: 3 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"compilerOptions": {
"resolveJsonModule": true,
"composite": true
"composite": true,
"esModuleInterop": true,
},
"files": [
"package.json"
]
}
}
13 changes: 13 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"functions": {
"api/index.ts": {
"maxDuration": 10
}
},
"rewrites": [
{
"source": "/ics",
"destination": "/api"
}
]
}
62 changes: 62 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,11 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==

"@ioredis/commands@^1.1.1":
version "1.2.0"
resolved "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11"
integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==

"@isaacs/cliui@^8.0.2":
version "8.0.2"
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
Expand Down Expand Up @@ -570,6 +575,11 @@
"@typescript-eslint/types" "6.7.2"
eslint-visitor-keys "^3.4.1"

"@vercel/ncc@^0.38.0":
version "0.38.0"
resolved "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.38.0.tgz#5210def0dcf0c79640bfaf16eecce54beed58fa6"
integrity sha512-B4YKZMm/EqMptKSFyAq4q2SlgJe+VCmEH6Y8gf/E1pTlWbsUJpuH1ymik2Ex3aYO5mCWwV1kaSYHSQOT8+4vHA==

accepts@~1.3.8:
version "1.3.8"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
Expand Down Expand Up @@ -866,6 +876,11 @@ cli-width@^2.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==

cluster-key-slot@^1.1.0:
version "1.1.2"
resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac"
integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==

color-convert@^1.9.0, color-convert@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
Expand Down Expand Up @@ -1120,6 +1135,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==

denque@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1"
integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==

[email protected]:
version "2.0.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
Expand Down Expand Up @@ -2052,6 +2072,21 @@ [email protected]:
strip-ansi "^5.1.0"
through "^2.3.6"

ioredis@^5.3.2:
version "5.3.2"
resolved "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz#9139f596f62fc9c72d873353ac5395bcf05709f7"
integrity sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==
dependencies:
"@ioredis/commands" "^1.1.1"
cluster-key-slot "^1.1.0"
debug "^4.3.4"
denque "^2.1.0"
lodash.defaults "^4.2.0"
lodash.isarguments "^3.1.0"
redis-errors "^1.2.0"
redis-parser "^3.0.0"
standard-as-callback "^2.1.0"

[email protected]:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
Expand Down Expand Up @@ -2209,6 +2244,16 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"

lodash.defaults@^4.2.0:
version "4.2.0"
resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==

lodash.isarguments@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==

lodash.map@^4.5.1:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
Expand Down Expand Up @@ -2716,6 +2761,18 @@ readable-stream@^3.4.0, readable-stream@^3.6.0:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"

redis-errors@^1.0.0, redis-errors@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==

redis-parser@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==
dependencies:
redis-errors "^1.0.0"

regenerator-runtime@^0.13.4:
version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
Expand Down Expand Up @@ -2939,6 +2996,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=

standard-as-callback@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45"
integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==

[email protected]:
version "2.0.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
Expand Down

0 comments on commit d447579

Please sign in to comment.