diff --git a/src/config/cache.ts b/src/config/cache.ts index 916047e..584ff69 100644 --- a/src/config/cache.ts +++ b/src/config/cache.ts @@ -1,47 +1,54 @@ -import { config } from "dotenv"; import { Redis } from "ioredis"; - -config(); +import { env } from "./env.js"; export class AniwatchAPICache { - private _client: Redis | null; + private static instance: AniwatchAPICache | null = null; + + private client: Redis | null; public isOptional: boolean = true; static DEFAULT_CACHE_EXPIRY_SECONDS = 60 as const; static CACHE_EXPIRY_HEADER_NAME = "X-ANIWATCH-CACHE-EXPIRY" as const; constructor() { - const redisConnURL = process.env?.ANIWATCH_API_REDIS_CONN_URL; + const redisConnURL = env.ANIWATCH_API_REDIS_CONN_URL; this.isOptional = !Boolean(redisConnURL); - this._client = this.isOptional ? null : new Redis(String(redisConnURL)); + this.client = this.isOptional ? null : new Redis(String(redisConnURL)); } - set(key: string | Buffer, value: string | Buffer | number) { - if (this.isOptional) return; - return this._client?.set(key, value); + static getInstance() { + if (!AniwatchAPICache.instance) { + AniwatchAPICache.instance = new AniwatchAPICache(); + } + return AniwatchAPICache.instance; } - get(key: string | Buffer) { - if (this.isOptional) return; - return this._client?.get(key); - } + // set(key: string | Buffer, value: string | Buffer | number) { + // if (this.isOptional) return; + // return this.client?.set(key, value); + // } + + // get(key: string | Buffer) { + // if (this.isOptional) return; + // return this.client?.get(key); + // } /** * @param expirySeconds set to 60 by default */ async getOrSet( - setCB: () => Promise, + dataGetter: () => Promise, key: string | Buffer, expirySeconds: number = AniwatchAPICache.DEFAULT_CACHE_EXPIRY_SECONDS ) { const cachedData = this.isOptional ? null - : (await this._client?.get(key)) || null; + : (await this.client?.get?.(key)) || null; let data = JSON.parse(String(cachedData)) as T; if (!data) { - data = await setCB(); - await this._client?.set( + data = await dataGetter(); + await this.client?.set?.( key, JSON.stringify(data), "EX", @@ -52,4 +59,4 @@ export class AniwatchAPICache { } } -export const cache = new AniwatchAPICache(); +export const cache = AniwatchAPICache.getInstance(); diff --git a/src/config/cors.ts b/src/config/cors.ts index 6d6e138..f6b5f25 100644 --- a/src/config/cors.ts +++ b/src/config/cors.ts @@ -1,17 +1,15 @@ -import { config } from "dotenv"; import { cors } from "hono/cors"; +import { env } from "./env.js"; -config(); +const DEFAULT_ALLOWED_ORIGINS = ["http://localhost:4000", "*"]; -const allowedOrigins = process.env.ANIWATCH_API_CORS_ALLOWED_ORIGINS - ? process.env.ANIWATCH_API_CORS_ALLOWED_ORIGINS.split(",") - : ["http://localhost:4000", "*"]; +const allowedOrigins = env.ANIWATCH_API_CORS_ALLOWED_ORIGINS + ? env.ANIWATCH_API_CORS_ALLOWED_ORIGINS.split(",") + : DEFAULT_ALLOWED_ORIGINS; -const corsConfig = cors({ - allowMethods: ["GET"], - maxAge: 600, - credentials: true, - origin: allowedOrigins, +export const corsConfig = cors({ + allowMethods: ["GET"], + maxAge: 600, + credentials: true, + origin: allowedOrigins, }); - -export default corsConfig; diff --git a/src/config/errorHandler.ts b/src/config/errorHandler.ts index d6f3193..36f57c3 100644 --- a/src/config/errorHandler.ts +++ b/src/config/errorHandler.ts @@ -1,27 +1,28 @@ import { HiAnimeError } from "aniwatch"; import type { ErrorHandler, NotFoundHandler } from "hono"; import type { ContentfulStatusCode } from "hono/utils/http-status"; +import { logger } from "./logger.js"; const errResp: { status: ContentfulStatusCode; message: string } = { - status: 500, - message: "Internal Server Error", + status: 500, + message: "Internal Server Error", }; export const errorHandler: ErrorHandler = (err, c) => { - console.error(err); + logger.error(JSON.stringify(err)); - if (err instanceof HiAnimeError) { - errResp.status = err.status as ContentfulStatusCode; - errResp.message = err.message; - } + if (err instanceof HiAnimeError) { + errResp.status = err.status as ContentfulStatusCode; + errResp.message = err.message; + } - return c.json(errResp, errResp.status); + return c.json(errResp, errResp.status); }; export const notFoundHandler: NotFoundHandler = (c) => { - errResp.status = 404; - errResp.message = "Not Found"; + errResp.status = 404; + errResp.message = "Not Found"; - console.error(errResp); - return c.json(errResp, errResp.status); + logger.error(JSON.stringify(errResp)); + return c.json(errResp, errResp.status); }; diff --git a/src/config/ratelimit.ts b/src/config/ratelimit.ts index afd6e54..8bfc308 100644 --- a/src/config/ratelimit.ts +++ b/src/config/ratelimit.ts @@ -1,21 +1,22 @@ -import { config } from "dotenv"; import { rateLimiter } from "hono-rate-limiter"; import { getConnInfo } from "@hono/node-server/conninfo"; - -config(); +import { env } from "./env.js"; export const ratelimit = rateLimiter({ - windowMs: Number(process.env.ANIWATCH_API_WINDOW_MS) || 30 * 60 * 1000, - limit: Number(process.env.ANIWATCH_API_MAX_REQS) || 6, - standardHeaders: "draft-7", - keyGenerator(c) { - const { remote } = getConnInfo(c); - const key = - `${String(remote.addressType)}_` + - `${String(remote.address)}:${String(remote.port)}`; + windowMs: env.ANIWATCH_API_WINDOW_MS, + limit: env.ANIWATCH_API_MAX_REQS, + standardHeaders: "draft-7", + keyGenerator(c) { + const { remote } = getConnInfo(c); + const key = + `${String(remote.addressType)}_` + + `${String(remote.address)}:${String(remote.port)}`; - return key; - }, - handler: (c) => - c.json({ status: 429, message: "Too Many Requests 😵" }, { status: 429 }), + return key; + }, + handler: (c) => + c.json( + { status: 429, message: "Too Many Requests 😵" }, + { status: 429 } + ), });