196 lines
5.6 KiB
JavaScript
196 lines
5.6 KiB
JavaScript
const express = require("express");
|
||
const fs = require("fs");
|
||
const os = require("os");
|
||
const path = require("path");
|
||
const process = require("process");
|
||
const logger = require("./config/logger");
|
||
const compression = require("compression");
|
||
const multer = require("multer");
|
||
const dotenv = require("dotenv");
|
||
const { limiter } = require("./config/init");
|
||
const { performance } = require("perf_hooks");
|
||
performance.eventLoopUtilization();
|
||
dotenv.config();
|
||
const app = express();
|
||
|
||
const UPLOAD_DIR = path.join(__dirname, "uploads");
|
||
if (!fs.existsSync(UPLOAD_DIR)) fs.mkdirSync(UPLOAD_DIR, { recursive: true });
|
||
|
||
const EXPORTS_DIR = path.join(__dirname, "exports");
|
||
if (!fs.existsSync(EXPORTS_DIR)) fs.mkdirSync(EXPORTS_DIR, { recursive: true });
|
||
|
||
const upload_files = multer({
|
||
storage: multer.diskStorage({
|
||
destination: (_, __, cb) => cb(null, UPLOAD_DIR),
|
||
filename: (_, file, cb) => cb(null, `${Date.now()}-${file.originalname}`),
|
||
}),
|
||
});
|
||
const upload_exports = multer({
|
||
storage: multer.diskStorage({
|
||
destination: (_, __, cb) => cb(null, EXPORTS_DIR),
|
||
filename: (_, file, cb) => cb(null, `${Date.now()}-${file.originalname}`),
|
||
}),
|
||
});
|
||
const serviceStartTime = Date.now();
|
||
|
||
app.use(compression());
|
||
// app.use((req, res, next) => {
|
||
// logger.info({
|
||
// method: req.method,
|
||
// url: req.url,
|
||
// timestamp: new Date().toISOString(),
|
||
// });
|
||
// next();
|
||
// });
|
||
app.post("/upload", upload_files.single("file"), (req, res) => {
|
||
// Authorization
|
||
|
||
logger.info({
|
||
method: req.method,
|
||
url: req.url,
|
||
timestamp: new Date().toISOString(),
|
||
});
|
||
const auth = req.headers["authorization"]?.split(" ")[1];
|
||
if (auth !== process.env.CDN_SERVICE_TOKEN) {
|
||
return res.status(401).json({ error: "Unauthorized" });
|
||
}
|
||
|
||
if (!req.file) return res.status(400).json({ error: "No file uploaded" });
|
||
|
||
const publicUrl = `${process.env.CDN_PUBLIC_BASE}/uploads/${req.file.filename}`;
|
||
|
||
return res.json({
|
||
url: publicUrl,
|
||
size: req.file.size,
|
||
mime: req.file.mimetype,
|
||
});
|
||
});
|
||
app.post("/upload-exports", upload_exports.single("exports"), (req, res) => {
|
||
// Authorization
|
||
// console.log(req);
|
||
logger.info({
|
||
method: req.method,
|
||
url: req.url,
|
||
timestamp: new Date().toISOString(),
|
||
});
|
||
const auth = req.headers["authorization"]?.split(" ")[1];
|
||
if (auth !== process.env.CDN_SERVICE_TOKEN) {
|
||
return res.status(401).json({ error: "Unauthorized" });
|
||
}
|
||
|
||
if (!req.file) return res.status(400).json({ error: "No file uploaded" });
|
||
|
||
const publicUrl = `${process.env.CDN_PUBLIC_BASE}/exports/${req.file.filename}`;
|
||
|
||
return res.json({
|
||
url: publicUrl,
|
||
size: req.file.size,
|
||
mime: req.file.mimetype,
|
||
});
|
||
});
|
||
|
||
app.post("/upload/delete", (req, res) => {
|
||
logger.info({
|
||
method: req.method,
|
||
url: req.url,
|
||
timestamp: new Date().toISOString(),
|
||
});
|
||
const auth = req.headers["authorization"];
|
||
const bearer = auth?.split(" ")[1];
|
||
if (bearer !== process.env.CDN_SERVICE_TOKEN) {
|
||
return res.status(401).json({ error: "Unauthorized" });
|
||
}
|
||
console.log(req);
|
||
const { fileKey, fileUrl } = req.body;
|
||
const fileName = fileKey ?? fileUrl?.split("/").pop();
|
||
if (!fileName) return res.status(400).json({ error: "file key/url missing" });
|
||
const savePath = path.join(UPLOAD_DIR, fileName);
|
||
if (!fs.existsSync(savePath))
|
||
return res.status(404).json({ error: "Not found" });
|
||
fs.unlinkSync(savePath);
|
||
return res.json({ success: true, file: fileName });
|
||
});
|
||
|
||
app.use("/uploads", express.static(UPLOAD_DIR, { maxAge: 3600 }));
|
||
app.use("/exports", express.static(EXPORTS_DIR, { maxAge: 3600 }));
|
||
|
||
app.get("/status", (req, res) => {
|
||
try {
|
||
const mem = process.memoryUsage();
|
||
const cpu = process.cpuUsage();
|
||
const elu = performance.eventLoopUtilization();
|
||
res.status(200).json({
|
||
status: "OK",
|
||
system: {
|
||
service: {
|
||
uptime: Math.floor(process.uptime()),
|
||
pid: process.pid,
|
||
nodeVersion: process.version,
|
||
},
|
||
memory: {
|
||
rss: mem.rss,
|
||
heapUsed: mem.heapUsed,
|
||
heapTotal: mem.heapTotal,
|
||
external: mem.external,
|
||
},
|
||
cpu: {
|
||
user: cpu.user,
|
||
system: cpu.system,
|
||
},
|
||
eventLoop: {
|
||
utilization: +elu.utilization.toFixed(4),
|
||
active: elu.active,
|
||
idle: elu.idle,
|
||
},
|
||
system: {
|
||
freeMemory: os.freemem(),
|
||
totalMemory: os.totalmem(),
|
||
loadAvg: os.loadavg(),
|
||
cpuCores: os.cpus().length,
|
||
},
|
||
timestamp: new Date().toISOString(),
|
||
},
|
||
});
|
||
} catch (error) {
|
||
res.status(500).json({
|
||
status: "ERROR",
|
||
message: "خطای داخلی سرویس",
|
||
error: error.message,
|
||
});
|
||
}
|
||
});
|
||
app.get("/logs", (req, res) => {
|
||
|
||
const logFilePath = path.join(__dirname, "logs", "cdn.log");
|
||
|
||
fs.readFile(logFilePath, "utf8", (err, data) => {
|
||
if (err) {
|
||
return res.status(500).json({
|
||
status: "ERROR",
|
||
message: "لاگ خوانده نشد",
|
||
error: err.message,
|
||
});
|
||
}
|
||
|
||
return res.status(200).json({
|
||
status: "OK",
|
||
logs: data.split("\n").filter((line) => line),
|
||
});
|
||
});
|
||
});
|
||
app.delete("/logs/clear", (req, res) => {
|
||
const logFilePath = path.join(__dirname, "logs", "cdn.log");
|
||
|
||
fs.truncate(logFilePath, 0, (err) => {
|
||
if (err) {
|
||
return res
|
||
.status(500)
|
||
.json({ status: "ERROR", message: "خطا در پاکسازی لاگ ها" });
|
||
}
|
||
return res
|
||
.status(200)
|
||
.json({ status: "OK", message: "لاگ ها با موفقیت پاک شدند" });
|
||
});
|
||
});
|
||
app.listen(4000, () => console.log("CDN server listening on 4000"));
|