import { parseArgs } from "node:util"; import { Manager } from "./src/manager.js"; import logger from "./src/logger.js"; import { initDB, closePool } from "./src/db.js"; import { startServer } from "./src/server.js"; process.on("uncaughtException", (err) => { logger.fatal(err, "Uncaught exception. Application crashing..."); process.exit(1); }); process.on("unhandledRejection", (reason) => { logger.fatal(reason, "Unhandled promise Rejection"); process.exit(1); }); const options = { pairs: { type: "string", short: "p", default: process.env.PAIRS || "BTC-USD", }, interval: { type: "string", short: "i", default: process.env.INTERVAL || "5000", }, threshold: { type: "string", short: "t", default: process.env.THRESHOLD || "0.01", }, }; const { values } = parseArgs({ options, strict: true, allowPositionals: true, args: process.argv.slice(2), }); const pairs = values.pairs.split(",").map((p) => p.trim()); const interval = parseInt(values.interval, 10); const threshold = parseFloat(values.threshold); if (isNaN(interval) || interval < 100) { logger.error("Interval must be a number larger than 100"); process.exit(1); } if (pairs.length === 0 || pairs.some((p) => !p.match(/^[A-Z]+-?[A-Z]+$/))) { logger.error("Invalid pair format (expected BTC-USD or CNYUSD)"); process.exit(1); } if (threshold <= 0 || threshold > 100) { logger.error("Threshold must be between 0 and 100"); process.exit(1); } async function main() { logger.info("Bot starting..."); logger.info( `[WATCHING] ${pairs.join(", ")} | Every ${interval}ms | Threshold ${threshold}%`, ); await initDB(); const manager = new Manager(); pairs.forEach((pair) => { manager.addBot(pair, { interval, threshold }); }); manager.start(); startServer(); const shutdown = async () => { await manager.shutdown(); // Safe to close DB await closePool(); process.exit(0); }; process.on("SIGINT", shutdown); process.on("SIGTERM", shutdown); } main().catch((err) => { logger.fatal(err, "Fatal error in main loop"); process.exit(1); });