Skip to content

Commit 01c02bd

Browse files
authored
chore(release): prepare source code for version 3.0.0 (#58)
* refractor: remove unused build script * refractor: change database location * lib(build): add new init script for application * refractor: let rate limit class use sqlite * refractor: let request cache class use sqlite * refractor: implement new classes based on sqlite * refractor: remove unused scripts and dependencies * feat: improve docker build process * fix: resolve timing issues in middleware * refractor: optimize database instance creation * refractor: correct typo in function name * refractor: switch to transaction usage * lib(util): add game date utility * fix: resolve issues with date parsing * refractor: remove obsolete action
1 parent 786ad4a commit 01c02bd

30 files changed

+898
-824
lines changed

.github/workflows/tests.yml

Lines changed: 0 additions & 34 deletions
This file was deleted.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ dist
175175
.DS_Store
176176

177177
# Database
178-
prisma/database
178+
databases
179179

180180
# Sentry Config File
181181
.sentryclirc

Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ENV PATH $NODE_PATH:$PATH
1818

1919
# set environment variables
2020
ENV RATE_LIMIT="200"
21-
ENV DATABASE_URL="file:./database/data.db"
21+
ENV DATABASE_URL="file:../databases/data.db"
2222
ENV HISTORY_API_URL="https://helldivers-b.omnedia.com/api"
2323
ENV API_URL="https://api.live.prod.thehelldiversgame.com/api"
2424
ENV STORAGE_URL="https://vxspqnuarwhjjbxzgauv.supabase.co/storage/v1/object/public"
@@ -41,6 +41,10 @@ FROM base AS prerelease
4141
COPY --from=install /temp/dev/node_modules node_modules
4242
COPY . .
4343

44+
# reset old database and generate new one
45+
RUN bun run reset
46+
RUN bun run init
47+
4448
# synchronize the database schema & generate client
4549
RUN bunx prisma migrate deploy
4650
RUN bunx prisma db push
@@ -55,6 +59,7 @@ RUN bun test
5559
FROM base AS release
5660
COPY --from=prerelease /usr/src/app/src src
5761
COPY --from=prerelease /usr/src/app/prisma prisma
62+
COPY --from=prerelease /usr/src/app/databases databases
5863
COPY --from=prerelease /usr/src/app/node_modules node_modules
5964
COPY --from=prerelease /usr/src/app/package.json package.json
6065
COPY --from=prerelease /usr/src/app/tsconfig.json tsconfig.json

bun.lockb

-6.61 KB
Binary file not shown.

package.json

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@
1919
],
2020
"scripts": {
2121
"lint": "eslint . --ext .ts",
22+
"reset": "rm -rf ./databases",
2223
"format": "prettier --write .",
23-
"output": "bun run scripts/build.ts",
24+
"init": "bun run ./scripts/init.ts",
2425
"dev": "bun run --hot ./src/index.ts",
2526
"refresh": "bun run ./scripts/refresh.ts",
26-
"clean": "rm -rf prisma/database prisma/migrations",
27-
"serve": "pm2 start --name=\"@hellhub/api\" --interpreter ~/.bun/bin/bun build/index.js",
28-
"generate": "bun run ./scripts/generate.ts",
29-
"sentry:sourcemaps": "bun sentry-cli sourcemaps inject --org hellhub --project hellhub-api ./build && bun sentry-cli sourcemaps upload --no-rewrite --org hellhub --project hellhub-api ./build"
27+
"generate": "bun run ./scripts/generate.ts"
3028
},
3129
"devDependencies": {
3230
"@types/bun": "latest",
@@ -48,18 +46,15 @@
4846
"@hono/sentry": "^1.0.1",
4947
"@prisma/client": "^5.13.0",
5048
"@sentry/bun": "^7.110.1",
51-
"@sentry/cli": "^2.31.0",
5249
"chalk": "^5.3.0",
5350
"croner": "^8.0.2",
5451
"hono": "^4.1.0",
55-
"node-cache": "^5.1.2",
5652
"prisma": "^5.13.0",
5753
"qs": "^6.12.0"
5854
},
5955
"trustedDependencies": [
6056
"@prisma/client",
6157
"@prisma/engines",
62-
"@sentry/cli",
6358
"prisma"
6459
]
6560
}

scripts/build.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

scripts/init.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import path from "path";
2+
import fs from "fs/promises";
3+
import Database from "bun:sqlite";
4+
5+
const dir = path.join(process.cwd(), "databases");
6+
const db = path.join(dir, "data.db");
7+
8+
await fs.mkdir(dir, { recursive: true });
9+
new Database(db, { create: true }).close();

src/classes/rate-limit.ts

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,78 @@
1-
import NodeCache from "node-cache";
1+
import path from "path";
2+
import Database from "bun:sqlite";
23

3-
class Cache {
4-
private cache: NodeCache = new NodeCache({ checkperiod: 1 });
5-
private static instance: Cache;
6-
private constructor() {}
4+
export interface RateLimit {
5+
ip: string;
6+
count: number;
7+
reset: number;
8+
threshold: number;
9+
remaining: number;
10+
}
11+
12+
class RateLimiter {
13+
private db: Database;
14+
private static instance: RateLimiter;
15+
private databasePath = path.join(process.cwd(), "databases", "cache.db");
16+
17+
private constructor() {
18+
this.db = new Database(this.databasePath, { create: true });
19+
const stmt1 = this.db.prepare("DROP TABLE IF EXISTS rate_limit");
20+
stmt1.run();
721

8-
public static getInstance(): Cache {
9-
if (!Cache.instance) Cache.instance = new Cache();
10-
return Cache.instance;
22+
const stmt2 = this.db.prepare(
23+
`CREATE TABLE IF NOT EXISTS rate_limit (
24+
ip TEXT PRIMARY KEY,
25+
count INTEGER,
26+
reset INTEGER,
27+
threshold INTEGER,
28+
remaining INTEGER,
29+
expiration INTEGER
30+
)`,
31+
);
32+
33+
stmt2.run();
1134
}
1235

13-
get = this.cache.get;
14-
set = this.cache.set;
15-
del = this.cache.del;
16-
flushAll = this.cache.flushAll;
36+
public static getInstance(): RateLimiter {
37+
if (!RateLimiter.instance) RateLimiter.instance = new RateLimiter();
38+
return RateLimiter.instance;
39+
}
40+
41+
get(ip: string): RateLimit | null {
42+
const stmt = this.db.prepare<RateLimit, any>(
43+
`SELECT * FROM rate_limit WHERE ip = ?`,
44+
);
45+
46+
const result = stmt.get(ip);
47+
if (!result) return null;
48+
49+
if (result.reset < Date.now()) {
50+
this.del(ip);
51+
return null;
52+
}
53+
54+
return result;
55+
}
56+
57+
del(ip: string): void {
58+
const stmt = this.db.prepare<RateLimit, any>(
59+
`DELETE FROM rate_limit WHERE ip = ?`,
60+
);
61+
stmt.run(ip);
62+
}
63+
64+
set(data: RateLimit): void {
65+
const stmt = this.db.prepare<RateLimit, any>(
66+
`INSERT OR REPLACE INTO rate_limit (ip, count, reset, threshold, remaining) VALUES (?, ?, ?, ?, ?)`,
67+
);
68+
69+
stmt.run(data.ip, data.count, data.reset, data.threshold, data.remaining);
70+
}
71+
72+
flushAll(): void {
73+
this.db.exec("DELETE FROM rate_limit");
74+
}
1775
}
1876

19-
const RateLimitCache = Cache.getInstance();
77+
const RateLimitCache = RateLimiter.getInstance();
2078
export default RateLimitCache;

src/classes/request-cache.ts

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,72 @@
1-
import NodeCache from "node-cache";
1+
import path from "path";
2+
import Database from "bun:sqlite";
3+
import type { StatusCode } from "hono/utils/http-status";
4+
5+
interface CachedRequest {
6+
key: string;
7+
data: object;
8+
status: StatusCode;
9+
}
210

311
class Cache {
4-
private cache: NodeCache = new NodeCache();
12+
private db: Database;
513
private static instance: Cache;
6-
private constructor() {}
14+
private databasePath = path.join(process.cwd(), "databases", "cache.db");
15+
16+
private constructor() {
17+
this.db = new Database(this.databasePath, { create: true });
18+
const stmt1 = this.db.prepare("DROP TABLE IF EXISTS request_cache");
19+
stmt1.run();
20+
21+
const stmt2 = this.db.prepare(
22+
`CREATE TABLE request_cache (
23+
key TEXT PRIMARY KEY,
24+
status INTEGER,
25+
data STRING,
26+
expiration INTEGER
27+
)`,
28+
);
29+
30+
stmt2.run();
31+
}
732

833
public static getInstance(): Cache {
934
if (!Cache.instance) Cache.instance = new Cache();
1035
return Cache.instance;
1136
}
1237

13-
get = this.cache.get;
14-
set = this.cache.set;
15-
del = this.cache.del;
16-
flushAll = this.cache.flushAll;
38+
get(key: string): CachedRequest | null {
39+
const stmt = this.db.prepare<CachedRequest, any>(
40+
`SELECT * FROM request_cache WHERE key = ?`,
41+
);
42+
43+
const result = stmt.get(key);
44+
if (!result) return null;
45+
46+
if ((result as any).expiration < Date.now()) this.del(key);
47+
return { ...result, data: JSON.parse(result.data as any) };
48+
}
49+
50+
del(key: string): void {
51+
const stmt = this.db.prepare<CachedRequest, any>(
52+
`DELETE FROM request_cache WHERE key = ?`,
53+
);
54+
stmt.run(key);
55+
}
56+
57+
set(data: CachedRequest, ttl: number): void {
58+
const expiration = Date.now() + 1000 * ttl;
59+
60+
const stmt = this.db.prepare<CachedRequest, any>(
61+
`INSERT OR REPLACE INTO request_cache (key, status, data, expiration) VALUES (?, ?, ?, ?)`,
62+
);
63+
64+
stmt.run(data.key, data.status, JSON.stringify(data.data), expiration);
65+
}
66+
67+
flushAll(): void {
68+
this.db.exec("DELETE FROM request_cache");
69+
}
1770
}
1871

1972
const RequestCache = Cache.getInstance();

src/controllers/assignments.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { Context } from "hono";
22

3-
import { db } from "utils/database";
3+
import db from "utils/database";
44
import parseIntParam from "utils/params";
5-
import witCache from "utils/request-cache";
65
import parseQueryParams from "utils/query";
6+
import withCache from "utils/request-cache";
77
import type { Assignment, AssignmentTask } from "@prisma/client";
88

99
function transformAssignment(assignment: Assignment): Assignment {
@@ -23,7 +23,7 @@ function transformAssignment(assignment: Assignment): Assignment {
2323
return assignment;
2424
}
2525

26-
export const getAssignmentById = await witCache(async (ctx: Context) => {
26+
export const getAssignmentById = await withCache(async (ctx: Context) => {
2727
try {
2828
const id = parseIntParam(ctx, "id");
2929
const query = await parseQueryParams(ctx);
@@ -58,7 +58,7 @@ export const getAssignmentById = await witCache(async (ctx: Context) => {
5858
}
5959
});
6060

61-
export const getAllAssignments = await witCache(async (ctx: Context) => {
61+
export const getAllAssignments = await withCache(async (ctx: Context) => {
6262
try {
6363
const query = await parseQueryParams(ctx);
6464

@@ -87,7 +87,7 @@ export const getAllAssignments = await witCache(async (ctx: Context) => {
8787
}
8888
});
8989

90-
export const getAssignmentReward = await witCache(async (ctx: Context) => {
90+
export const getAssignmentReward = await withCache(async (ctx: Context) => {
9191
try {
9292
const id = parseIntParam(ctx, "id");
9393
const query = await parseQueryParams(ctx);

src/controllers/attacks.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type { Context } from "hono";
22

3-
import { db } from "utils/database";
3+
import db from "utils/database";
44
import parseIntParam from "utils/params";
5-
import witCache from "utils/request-cache";
65
import parseQueryParams from "utils/query";
6+
import withCache from "utils/request-cache";
77

8-
export const getAttackById = await witCache(async (ctx: Context) => {
8+
export const getAttackById = await withCache(async (ctx: Context) => {
99
try {
1010
const id = parseIntParam(ctx, "id");
1111
const query = await parseQueryParams(ctx);
@@ -40,7 +40,7 @@ export const getAttackById = await witCache(async (ctx: Context) => {
4040
}
4141
});
4242

43-
export const getAllAttacks = await witCache(async (ctx: Context) => {
43+
export const getAllAttacks = await withCache(async (ctx: Context) => {
4444
try {
4545
const query = await parseQueryParams(ctx);
4646

@@ -69,7 +69,7 @@ export const getAllAttacks = await witCache(async (ctx: Context) => {
6969
}
7070
});
7171

72-
export const getPlanetsByAttack = await witCache(async (ctx: Context) => {
72+
export const getPlanetsByAttack = await withCache(async (ctx: Context) => {
7373
try {
7474
const id = parseIntParam(ctx, "id");
7575
const query = await parseQueryParams(ctx);

0 commit comments

Comments
 (0)