miniai/remote_receiver.ts
2026-08-16 22:56:09 +08:00

87 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 远程日志接收器
// 监听 HTTP 端口接收日志内容推送POST /logJSON 或纯文本),
// 按日期追加存入 received_logs/ 文件夹。日志内容直接传输,不做文件传输。
import { createServer } from "node:http";
import { mkdir, appendFile } from "fs/promises";
import { existsSync } from "fs";
import { resolve } from "path";
const PORT = parseInt(process.env.RECEIVER_PORT || "3200", 10);
const LOG_DIR = resolve("received_logs");
function now(iso: string): string {
return iso ? iso : new Date().toISOString();
}
function fmtEntry(p: { level?: string; category?: string; message?: string; line?: string; ts?: string }): string {
const ts = now(p.ts);
const level = (p.level || "info").toUpperCase().padEnd(5);
const category = p.category || "receiver";
const message = p.message !== undefined ? p.message : "";
return `[${ts}] [${level}] [${category}] ${message}`;
}
const server = createServer(async (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
if (req.method === "OPTIONS") { res.writeHead(204); res.end(); return; }
const url = new URL(req.url || "/", `http://localhost:${PORT}`);
if (req.method === "GET") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ status: "ok", name: "远程日志接收器", receivePath: "POST /log", port: PORT }));
return;
}
if (req.method === "POST" && (url.pathname === "/log" || url.pathname === "/")) {
let body = "";
try {
for await (const c of req) body += c;
} catch {
res.writeHead(400); res.end("bad request"); return;
}
let entry: string;
let level = "info";
let category = "receiver";
try {
const json = JSON.parse(body);
if (typeof json === "string") {
entry = json;
} else if (json.line) {
entry = json.line;
level = json.level || level;
category = json.category || category;
} else {
entry = fmtEntry({ level: json.level, category: json.category, message: json.message, ts: json.ts });
level = json.level || level;
category = json.category || category;
}
} catch {
entry = fmtEntry({ level, category, message: body, ts: new Date().toISOString() });
}
try {
if (!existsSync(LOG_DIR)) await mkdir(LOG_DIR, { recursive: true });
const ts = new Date().toISOString().slice(0, 10);
await appendFile(resolve(LOG_DIR, `received-${ts}.log`), entry + "\n", "utf-8");
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: true }));
} catch (e) {
res.writeHead(500, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: false, error: (e as any).message }));
}
return;
}
res.writeHead(404);
res.end("Not Found");
});
server.listen(PORT, () => {
console.log(`[remote_receiver] 远程日志接收器已启动: http://127.0.0.1:${PORT}/log (存入 ${LOG_DIR}`);
});