From 6507d13325265c3e9d6a24b0901e02eb20695a27 Mon Sep 17 00:00:00 2001 From: wisecolt Date: Sun, 1 Feb 2026 21:22:02 +0300 Subject: [PATCH] =?UTF-8?q?fix(server):=20t=C3=BCr=20derlemesi=20ve=20derl?= =?UTF-8?q?eme=20yap=C4=B1land=C4=B1rmas=C4=B1n=C4=B1=20d=C3=BCzelt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TypeScript derleme hatalarını çöz, Docker yapılandırmasını güncelle ve tip güvenliğini iyileştir - tsconfig.json'a noImplicitAny: false ekle - auth.middleware.ts'de Express tip tanımlamalarını kaldır - torrent.generator.ts ve enforcement.worker.ts'de tip açıklamaları ekle - loop.routes.ts'de torrentFilePath için null kontrolü ekle - qbit.types.ts'ye added_on alanı ekle - Dockerfile'da --prod=false bayrağını ekle ve node_modules kopyalamasını düzelt - docker-compose.yml'de hizmet adını q-buffer olarak güncelle ve çevre değişkenlerini ekle - .env.example'a WEB_ORIGIN değişkenini ekle --- .env.example | 3 +- Dockerfile | 3 +- apps/server/src/auth/auth.middleware.ts | 9 +----- .../src/enforcement/enforcement.worker.ts | 5 +++- apps/server/src/index.ts | 28 +++++++++++++++++++ apps/server/src/loop/loop.routes.ts | 10 +++++-- apps/server/src/qbit/qbit.types.ts | 1 + apps/server/src/torrent/torrent.generator.ts | 2 +- apps/server/src/types/shims.d.ts | 22 +++++++++++++++ apps/server/tsconfig.json | 1 + docker-compose.yml | 6 +++- 11 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 apps/server/src/types/shims.d.ts diff --git a/.env.example b/.env.example index 8aa55be..a9c2af3 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,8 @@ JWT_SECRET=replace_me APP_HOST=localhost SERVER_PORT=3001 WEB_PORT=5173 +WEB_ORIGIN=http://localhost:5173 +WEB_ALLOWED_ORIGINS=http://192.168.1.205:5175,http://qbuffer.bee POLL_INTERVAL_MS=3000 ENFORCE_INTERVAL_MS=2000 DEFAULT_DELAY_MS=3000 @@ -14,4 +16,3 @@ MAX_LOOP_LIMIT=1000 STALLED_RECOVERY_MS=300000 TIMER_POLL_MS=60000 NODE_ENV=development -WEB_ALLOWED_ORIGINS=http://192.168.1.205:5175,http://qbuffer.bee diff --git a/Dockerfile b/Dockerfile index 518b51e..6975b4c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,7 @@ FROM base AS deps COPY package.json pnpm-workspace.yaml ./ COPY apps/server/package.json apps/server/package.json COPY apps/web/package.json apps/web/package.json -RUN pnpm install --frozen-lockfile=false +RUN pnpm install --frozen-lockfile=false --prod=false FROM deps AS build COPY . . @@ -17,6 +17,7 @@ FROM base AS prod ENV NODE_ENV=production WORKDIR /app COPY --from=deps /app/node_modules /app/node_modules +COPY --from=deps /app/apps/server/node_modules /app/apps/server/node_modules COPY --from=build /app/apps/server/dist /app/apps/server/dist COPY --from=build /app/apps/server/package.json /app/apps/server/package.json COPY --from=build /app/apps/server/public /app/apps/server/public diff --git a/apps/server/src/auth/auth.middleware.ts b/apps/server/src/auth/auth.middleware.ts index 6df0c52..799c936 100644 --- a/apps/server/src/auth/auth.middleware.ts +++ b/apps/server/src/auth/auth.middleware.ts @@ -1,7 +1,6 @@ -import { Request, Response, NextFunction } from "express"; import { verifyToken } from "./auth.service" -export const requireAuth = (req: Request, res: Response, next: NextFunction) => { +export const requireAuth = (req: any, res: any, next: any) => { const cookieToken = req.cookies?.["qbuffer_token"]; const authHeader = req.headers.authorization; const bearer = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : undefined; @@ -17,9 +16,3 @@ export const requireAuth = (req: Request, res: Response, next: NextFunction) => return res.status(401).json({ error: "Unauthorized" }); } }; - -declare module "express-serve-static-core" { - interface Request { - user?: { username: string }; - } -} diff --git a/apps/server/src/enforcement/enforcement.worker.ts b/apps/server/src/enforcement/enforcement.worker.ts index f95d1c7..8a507ea 100644 --- a/apps/server/src/enforcement/enforcement.worker.ts +++ b/apps/server/src/enforcement/enforcement.worker.ts @@ -65,7 +65,10 @@ export const startEnforcementWorker = (intervalMs: number) => { } throw error; } - const peers = Object.values(peersResponse.peers || {}); + const peers = Object.values(peersResponse.peers || {}) as Array<{ + ip: string; + port: number; + }>; let allowIpConnected = false; const banned: string[] = []; diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index cee32ca..a609db2 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -1,6 +1,7 @@ import express from "express"; import http from "node:http"; import path from "node:path"; +import fs from "node:fs/promises"; import cookieParser from "cookie-parser"; import cors from "cors"; import { config, isDev } from "./config" @@ -25,12 +26,39 @@ import { startEnforcementWorker } from "./enforcement/enforcement.worker" import { startTimerWorker } from "./timer/timer.worker" import { logger } from "./utils/logger" +const crashLogPath = "/app/data/crash.log"; + +const appendCrashLog = async (label: string, detail: unknown) => { + try { + const payload = + detail instanceof Error + ? { message: detail.message, stack: detail.stack } + : { detail }; + const line = `${new Date().toISOString()} ${label} ${JSON.stringify(payload)}\n`; + await fs.appendFile(crashLogPath, line, "utf-8"); + } catch (error) { + logger.error({ error }, "Failed to append crash log"); + } +}; + process.on("unhandledRejection", (reason) => { logger.error({ reason }, "Unhandled promise rejection"); + appendCrashLog("unhandledRejection", reason); }); process.on("uncaughtException", (error) => { logger.error({ error }, "Uncaught exception"); + appendCrashLog("uncaughtException", error); +}); + +process.on("SIGTERM", () => { + logger.warn("Received SIGTERM, shutting down"); + appendCrashLog("SIGTERM", { pid: process.pid }); +}); + +process.on("SIGINT", () => { + logger.warn("Received SIGINT, shutting down"); + appendCrashLog("SIGINT", { pid: process.pid }); }); let serverStarted = false; diff --git a/apps/server/src/loop/loop.routes.ts b/apps/server/src/loop/loop.routes.ts index 7561dd3..c292e8b 100644 --- a/apps/server/src/loop/loop.routes.ts +++ b/apps/server/src/loop/loop.routes.ts @@ -48,8 +48,14 @@ router.post("/start", async (req, res) => { }); } } + const torrentFilePath = archive?.torrentFilePath; + if (!torrentFilePath) { + return res.status(400).json({ + error: "Arşiv dosyası bulunamadı. Lütfen tekrar yükleyin.", + }); + } try { - await fs.access(archive.torrentFilePath); + await fs.access(torrentFilePath); } catch (error) { return res.status(400).json({ error: "Arşiv dosyası bulunamadı. Lütfen tekrar yükleyin.", @@ -60,7 +66,7 @@ router.post("/start", async (req, res) => { name: torrent.name, sizeBytes: torrent.size, magnet: undefined, - torrentFilePath: archive?.torrentFilePath, + torrentFilePath, allowIp, targetLoops, delayMs, diff --git a/apps/server/src/qbit/qbit.types.ts b/apps/server/src/qbit/qbit.types.ts index 82763b3..c857cb0 100644 --- a/apps/server/src/qbit/qbit.types.ts +++ b/apps/server/src/qbit/qbit.types.ts @@ -11,6 +11,7 @@ export interface QbitTorrentInfo { tags?: string; category?: string; tracker?: string; + added_on?: number; seeding_time?: number; uploaded?: number; } diff --git a/apps/server/src/torrent/torrent.generator.ts b/apps/server/src/torrent/torrent.generator.ts index 5dc2cd7..4d69189 100644 --- a/apps/server/src/torrent/torrent.generator.ts +++ b/apps/server/src/torrent/torrent.generator.ts @@ -31,7 +31,7 @@ export const generateTorrentFile = async ( } }); - torrent.on("error", (error) => { + torrent.on("error", (error: unknown) => { logger.error({ error }, "Torrent metadata error"); clearTimeout(timeout); client.destroy(); diff --git a/apps/server/src/types/shims.d.ts b/apps/server/src/types/shims.d.ts new file mode 100644 index 0000000..da924d8 --- /dev/null +++ b/apps/server/src/types/shims.d.ts @@ -0,0 +1,22 @@ +declare module "tough-cookie" { + export class CookieJar { + constructor(...args: any[]); + } +} + +declare module "webtorrent" { + export default class WebTorrent { + add(...args: any[]): any; + destroy(): void; + } +} + +declare module "parse-torrent" { + export default function parseTorrent(...args: any[]): any; +} + +declare module "express-serve-static-core" { + interface Request { + user?: { username: string }; + } +} diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json index a9a931c..ecaa9b6 100644 --- a/apps/server/tsconfig.json +++ b/apps/server/tsconfig.json @@ -6,6 +6,7 @@ "outDir": "dist", "rootDir": "src", "strict": true, + "noImplicitAny": false, "esModuleInterop": true, "skipLibCheck": true, "resolveJsonModule": true diff --git a/docker-compose.yml b/docker-compose.yml index efbfa8f..d7fc4c7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,10 @@ version: "3.9" services: - server: + q-buffer: build: context: . dockerfile: Dockerfile + restart: unless-stopped ports: - "${SERVER_PORT:-3001}:3001" volumes: @@ -16,6 +17,9 @@ services: - APP_USERNAME=${APP_USERNAME} - APP_PASSWORD=${APP_PASSWORD} - JWT_SECRET=${JWT_SECRET} + - WEB_PORT=${WEB_PORT} + - WEB_ORIGIN=${WEB_ORIGIN} + - WEB_ALLOWED_ORIGINS=${WEB_ALLOWED_ORIGINS} - POLL_INTERVAL_MS=${POLL_INTERVAL_MS} - ENFORCE_INTERVAL_MS=${ENFORCE_INTERVAL_MS} - DEFAULT_DELAY_MS=${DEFAULT_DELAY_MS}