Compare commits
1 Commits
967eb2d2a4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 6507d13325 |
@@ -7,6 +7,8 @@ JWT_SECRET=replace_me
|
|||||||
APP_HOST=localhost
|
APP_HOST=localhost
|
||||||
SERVER_PORT=3001
|
SERVER_PORT=3001
|
||||||
WEB_PORT=5173
|
WEB_PORT=5173
|
||||||
|
WEB_ORIGIN=http://localhost:5173
|
||||||
|
WEB_ALLOWED_ORIGINS=http://192.168.1.205:5175,http://qbuffer.bee
|
||||||
POLL_INTERVAL_MS=3000
|
POLL_INTERVAL_MS=3000
|
||||||
ENFORCE_INTERVAL_MS=2000
|
ENFORCE_INTERVAL_MS=2000
|
||||||
DEFAULT_DELAY_MS=3000
|
DEFAULT_DELAY_MS=3000
|
||||||
@@ -14,4 +16,3 @@ MAX_LOOP_LIMIT=1000
|
|||||||
STALLED_RECOVERY_MS=300000
|
STALLED_RECOVERY_MS=300000
|
||||||
TIMER_POLL_MS=60000
|
TIMER_POLL_MS=60000
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
WEB_ALLOWED_ORIGINS=http://192.168.1.205:5175,http://qbuffer.bee
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ FROM base AS deps
|
|||||||
COPY package.json pnpm-workspace.yaml ./
|
COPY package.json pnpm-workspace.yaml ./
|
||||||
COPY apps/server/package.json apps/server/package.json
|
COPY apps/server/package.json apps/server/package.json
|
||||||
COPY apps/web/package.json apps/web/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
|
FROM deps AS build
|
||||||
COPY . .
|
COPY . .
|
||||||
@@ -17,6 +17,7 @@ FROM base AS prod
|
|||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=deps /app/node_modules /app/node_modules
|
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/dist /app/apps/server/dist
|
||||||
COPY --from=build /app/apps/server/package.json /app/apps/server/package.json
|
COPY --from=build /app/apps/server/package.json /app/apps/server/package.json
|
||||||
COPY --from=build /app/apps/server/public /app/apps/server/public
|
COPY --from=build /app/apps/server/public /app/apps/server/public
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
|
||||||
import { verifyToken } from "./auth.service"
|
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 cookieToken = req.cookies?.["qbuffer_token"];
|
||||||
const authHeader = req.headers.authorization;
|
const authHeader = req.headers.authorization;
|
||||||
const bearer = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : undefined;
|
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" });
|
return res.status(401).json({ error: "Unauthorized" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
declare module "express-serve-static-core" {
|
|
||||||
interface Request {
|
|
||||||
user?: { username: string };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -65,7 +65,10 @@ export const startEnforcementWorker = (intervalMs: number) => {
|
|||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
const peers = Object.values(peersResponse.peers || {});
|
const peers = Object.values(peersResponse.peers || {}) as Array<{
|
||||||
|
ip: string;
|
||||||
|
port: number;
|
||||||
|
}>;
|
||||||
let allowIpConnected = false;
|
let allowIpConnected = false;
|
||||||
const banned: string[] = [];
|
const banned: string[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
import fs from "node:fs/promises";
|
||||||
import cookieParser from "cookie-parser";
|
import cookieParser from "cookie-parser";
|
||||||
import cors from "cors";
|
import cors from "cors";
|
||||||
import { config, isDev } from "./config"
|
import { config, isDev } from "./config"
|
||||||
@@ -25,12 +26,39 @@ import { startEnforcementWorker } from "./enforcement/enforcement.worker"
|
|||||||
import { startTimerWorker } from "./timer/timer.worker"
|
import { startTimerWorker } from "./timer/timer.worker"
|
||||||
import { logger } from "./utils/logger"
|
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) => {
|
process.on("unhandledRejection", (reason) => {
|
||||||
logger.error({ reason }, "Unhandled promise rejection");
|
logger.error({ reason }, "Unhandled promise rejection");
|
||||||
|
appendCrashLog("unhandledRejection", reason);
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on("uncaughtException", (error) => {
|
process.on("uncaughtException", (error) => {
|
||||||
logger.error({ error }, "Uncaught exception");
|
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;
|
let serverStarted = false;
|
||||||
|
|||||||
@@ -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 {
|
try {
|
||||||
await fs.access(archive.torrentFilePath);
|
await fs.access(torrentFilePath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
error: "Arşiv dosyası bulunamadı. Lütfen tekrar yükleyin.",
|
error: "Arşiv dosyası bulunamadı. Lütfen tekrar yükleyin.",
|
||||||
@@ -60,7 +66,7 @@ router.post("/start", async (req, res) => {
|
|||||||
name: torrent.name,
|
name: torrent.name,
|
||||||
sizeBytes: torrent.size,
|
sizeBytes: torrent.size,
|
||||||
magnet: undefined,
|
magnet: undefined,
|
||||||
torrentFilePath: archive?.torrentFilePath,
|
torrentFilePath,
|
||||||
allowIp,
|
allowIp,
|
||||||
targetLoops,
|
targetLoops,
|
||||||
delayMs,
|
delayMs,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export interface QbitTorrentInfo {
|
|||||||
tags?: string;
|
tags?: string;
|
||||||
category?: string;
|
category?: string;
|
||||||
tracker?: string;
|
tracker?: string;
|
||||||
|
added_on?: number;
|
||||||
seeding_time?: number;
|
seeding_time?: number;
|
||||||
uploaded?: number;
|
uploaded?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export const generateTorrentFile = async (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
torrent.on("error", (error) => {
|
torrent.on("error", (error: unknown) => {
|
||||||
logger.error({ error }, "Torrent metadata error");
|
logger.error({ error }, "Torrent metadata error");
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
client.destroy();
|
client.destroy();
|
||||||
|
|||||||
22
apps/server/src/types/shims.d.ts
vendored
Normal file
22
apps/server/src/types/shims.d.ts
vendored
Normal file
@@ -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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"resolveJsonModule": true
|
"resolveJsonModule": true
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
version: "3.9"
|
version: "3.9"
|
||||||
services:
|
services:
|
||||||
server:
|
q-buffer:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "${SERVER_PORT:-3001}:3001"
|
- "${SERVER_PORT:-3001}:3001"
|
||||||
volumes:
|
volumes:
|
||||||
@@ -16,6 +17,9 @@ services:
|
|||||||
- APP_USERNAME=${APP_USERNAME}
|
- APP_USERNAME=${APP_USERNAME}
|
||||||
- APP_PASSWORD=${APP_PASSWORD}
|
- APP_PASSWORD=${APP_PASSWORD}
|
||||||
- JWT_SECRET=${JWT_SECRET}
|
- JWT_SECRET=${JWT_SECRET}
|
||||||
|
- WEB_PORT=${WEB_PORT}
|
||||||
|
- WEB_ORIGIN=${WEB_ORIGIN}
|
||||||
|
- WEB_ALLOWED_ORIGINS=${WEB_ALLOWED_ORIGINS}
|
||||||
- POLL_INTERVAL_MS=${POLL_INTERVAL_MS}
|
- POLL_INTERVAL_MS=${POLL_INTERVAL_MS}
|
||||||
- ENFORCE_INTERVAL_MS=${ENFORCE_INTERVAL_MS}
|
- ENFORCE_INTERVAL_MS=${ENFORCE_INTERVAL_MS}
|
||||||
- DEFAULT_DELAY_MS=${DEFAULT_DELAY_MS}
|
- DEFAULT_DELAY_MS=${DEFAULT_DELAY_MS}
|
||||||
|
|||||||
Reference in New Issue
Block a user