Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(release): prepare source code for version 3.0.0 #58

Merged
merged 15 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions .github/workflows/tests.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ dist
.DS_Store

# Database
prisma/database
databases

# Sentry Config File
.sentryclirc
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ENV PATH $NODE_PATH:$PATH

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

# reset old database and generate new one
RUN bun run reset
RUN bun run init

# synchronize the database schema & generate client
RUN bunx prisma migrate deploy
RUN bunx prisma db push
Expand All @@ -55,6 +59,7 @@ RUN bun test
FROM base AS release
COPY --from=prerelease /usr/src/app/src src
COPY --from=prerelease /usr/src/app/prisma prisma
COPY --from=prerelease /usr/src/app/databases databases
COPY --from=prerelease /usr/src/app/node_modules node_modules
COPY --from=prerelease /usr/src/app/package.json package.json
COPY --from=prerelease /usr/src/app/tsconfig.json tsconfig.json
Expand Down
Binary file modified bun.lockb
Binary file not shown.
11 changes: 3 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,12 @@
],
"scripts": {
"lint": "eslint . --ext .ts",
"reset": "rm -rf ./databases",
"format": "prettier --write .",
"output": "bun run scripts/build.ts",
"init": "bun run ./scripts/init.ts",
"dev": "bun run --hot ./src/index.ts",
"refresh": "bun run ./scripts/refresh.ts",
"clean": "rm -rf prisma/database prisma/migrations",
"serve": "pm2 start --name=\"@hellhub/api\" --interpreter ~/.bun/bin/bun build/index.js",
"generate": "bun run ./scripts/generate.ts",
"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"
"generate": "bun run ./scripts/generate.ts"
},
"devDependencies": {
"@types/bun": "latest",
Expand All @@ -48,18 +46,15 @@
"@hono/sentry": "^1.0.1",
"@prisma/client": "^5.13.0",
"@sentry/bun": "^7.110.1",
"@sentry/cli": "^2.31.0",
"chalk": "^5.3.0",
"croner": "^8.0.2",
"hono": "^4.1.0",
"node-cache": "^5.1.2",
"prisma": "^5.13.0",
"qs": "^6.12.0"
},
"trustedDependencies": [
"@prisma/client",
"@prisma/engines",
"@sentry/cli",
"prisma"
]
}
7 changes: 0 additions & 7 deletions scripts/build.ts

This file was deleted.

9 changes: 9 additions & 0 deletions scripts/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import path from "path";
import fs from "fs/promises";
import Database from "bun:sqlite";

const dir = path.join(process.cwd(), "databases");
const db = path.join(dir, "data.db");

await fs.mkdir(dir, { recursive: true });
new Database(db, { create: true }).close();
84 changes: 71 additions & 13 deletions src/classes/rate-limit.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,78 @@
import NodeCache from "node-cache";
import path from "path";
import Database from "bun:sqlite";

class Cache {
private cache: NodeCache = new NodeCache({ checkperiod: 1 });
private static instance: Cache;
private constructor() {}
export interface RateLimit {
ip: string;
count: number;
reset: number;
threshold: number;
remaining: number;
}

class RateLimiter {
private db: Database;
private static instance: RateLimiter;
private databasePath = path.join(process.cwd(), "databases", "cache.db");

private constructor() {
this.db = new Database(this.databasePath, { create: true });
const stmt1 = this.db.prepare("DROP TABLE IF EXISTS rate_limit");
stmt1.run();

public static getInstance(): Cache {
if (!Cache.instance) Cache.instance = new Cache();
return Cache.instance;
const stmt2 = this.db.prepare(
`CREATE TABLE IF NOT EXISTS rate_limit (
ip TEXT PRIMARY KEY,
count INTEGER,
reset INTEGER,
threshold INTEGER,
remaining INTEGER,
expiration INTEGER
)`,
);

stmt2.run();
}

get = this.cache.get;
set = this.cache.set;
del = this.cache.del;
flushAll = this.cache.flushAll;
public static getInstance(): RateLimiter {
if (!RateLimiter.instance) RateLimiter.instance = new RateLimiter();
return RateLimiter.instance;
}

get(ip: string): RateLimit | null {
const stmt = this.db.prepare<RateLimit, any>(
`SELECT * FROM rate_limit WHERE ip = ?`,
);

const result = stmt.get(ip);
if (!result) return null;

if (result.reset < Date.now()) {
this.del(ip);
return null;
}

return result;
}

del(ip: string): void {
const stmt = this.db.prepare<RateLimit, any>(
`DELETE FROM rate_limit WHERE ip = ?`,
);
stmt.run(ip);
}

set(data: RateLimit): void {
const stmt = this.db.prepare<RateLimit, any>(
`INSERT OR REPLACE INTO rate_limit (ip, count, reset, threshold, remaining) VALUES (?, ?, ?, ?, ?)`,
);

stmt.run(data.ip, data.count, data.reset, data.threshold, data.remaining);
}

flushAll(): void {
this.db.exec("DELETE FROM rate_limit");
}
}

const RateLimitCache = Cache.getInstance();
const RateLimitCache = RateLimiter.getInstance();
export default RateLimitCache;
67 changes: 60 additions & 7 deletions src/classes/request-cache.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,72 @@
import NodeCache from "node-cache";
import path from "path";
import Database from "bun:sqlite";
import type { StatusCode } from "hono/utils/http-status";

interface CachedRequest {
key: string;
data: object;
status: StatusCode;
}

class Cache {
private cache: NodeCache = new NodeCache();
private db: Database;
private static instance: Cache;
private constructor() {}
private databasePath = path.join(process.cwd(), "databases", "cache.db");

private constructor() {
this.db = new Database(this.databasePath, { create: true });
const stmt1 = this.db.prepare("DROP TABLE IF EXISTS request_cache");
stmt1.run();

const stmt2 = this.db.prepare(
`CREATE TABLE request_cache (
key TEXT PRIMARY KEY,
status INTEGER,
data STRING,
expiration INTEGER
)`,
);

stmt2.run();
}

public static getInstance(): Cache {
if (!Cache.instance) Cache.instance = new Cache();
return Cache.instance;
}

get = this.cache.get;
set = this.cache.set;
del = this.cache.del;
flushAll = this.cache.flushAll;
get(key: string): CachedRequest | null {
const stmt = this.db.prepare<CachedRequest, any>(
`SELECT * FROM request_cache WHERE key = ?`,
);

const result = stmt.get(key);
if (!result) return null;

if ((result as any).expiration < Date.now()) this.del(key);
return { ...result, data: JSON.parse(result.data as any) };
}

del(key: string): void {
const stmt = this.db.prepare<CachedRequest, any>(
`DELETE FROM request_cache WHERE key = ?`,
);
stmt.run(key);
}

set(data: CachedRequest, ttl: number): void {
const expiration = Date.now() + 1000 * ttl;

const stmt = this.db.prepare<CachedRequest, any>(
`INSERT OR REPLACE INTO request_cache (key, status, data, expiration) VALUES (?, ?, ?, ?)`,
);

stmt.run(data.key, data.status, JSON.stringify(data.data), expiration);
}

flushAll(): void {
this.db.exec("DELETE FROM request_cache");
}
}

const RequestCache = Cache.getInstance();
Expand Down
10 changes: 5 additions & 5 deletions src/controllers/assignments.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { Context } from "hono";

import { db } from "utils/database";
import db from "utils/database";
import parseIntParam from "utils/params";
import witCache from "utils/request-cache";
import parseQueryParams from "utils/query";
import withCache from "utils/request-cache";
import type { Assignment, AssignmentTask } from "@prisma/client";

function transformAssignment(assignment: Assignment): Assignment {
Expand All @@ -23,7 +23,7 @@ function transformAssignment(assignment: Assignment): Assignment {
return assignment;
}

export const getAssignmentById = await witCache(async (ctx: Context) => {
export const getAssignmentById = await withCache(async (ctx: Context) => {
try {
const id = parseIntParam(ctx, "id");
const query = await parseQueryParams(ctx);
Expand Down Expand Up @@ -58,7 +58,7 @@ export const getAssignmentById = await witCache(async (ctx: Context) => {
}
});

export const getAllAssignments = await witCache(async (ctx: Context) => {
export const getAllAssignments = await withCache(async (ctx: Context) => {
try {
const query = await parseQueryParams(ctx);

Expand Down Expand Up @@ -87,7 +87,7 @@ export const getAllAssignments = await witCache(async (ctx: Context) => {
}
});

export const getAssignmentReward = await witCache(async (ctx: Context) => {
export const getAssignmentReward = await withCache(async (ctx: Context) => {
try {
const id = parseIntParam(ctx, "id");
const query = await parseQueryParams(ctx);
Expand Down
10 changes: 5 additions & 5 deletions src/controllers/attacks.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { Context } from "hono";

import { db } from "utils/database";
import db from "utils/database";
import parseIntParam from "utils/params";
import witCache from "utils/request-cache";
import parseQueryParams from "utils/query";
import withCache from "utils/request-cache";

export const getAttackById = await witCache(async (ctx: Context) => {
export const getAttackById = await withCache(async (ctx: Context) => {
try {
const id = parseIntParam(ctx, "id");
const query = await parseQueryParams(ctx);
Expand Down Expand Up @@ -40,7 +40,7 @@ export const getAttackById = await witCache(async (ctx: Context) => {
}
});

export const getAllAttacks = await witCache(async (ctx: Context) => {
export const getAllAttacks = await withCache(async (ctx: Context) => {
try {
const query = await parseQueryParams(ctx);

Expand Down Expand Up @@ -69,7 +69,7 @@ export const getAllAttacks = await witCache(async (ctx: Context) => {
}
});

export const getPlanetsByAttack = await witCache(async (ctx: Context) => {
export const getPlanetsByAttack = await withCache(async (ctx: Context) => {
try {
const id = parseIntParam(ctx, "id");
const query = await parseQueryParams(ctx);
Expand Down
Loading
Loading