@opengis/fastify-table
Version:
core-plugins
83 lines (82 loc) • 3.29 kB
JavaScript
import path from "node:path";
import { lstat, readdir, readFile } from "node:fs/promises";
import { createReadStream, existsSync } from "node:fs";
import readline from "node:readline";
import checkUserAccess from "../../../plugins/logger/checkUserAccess.js";
import getRootDir from "../../../plugins/logger/getRootDir.js";
const limit = 200000;
const rootDir = getRootDir();
/**
*
* @method GET
* @summary API для перегляду логів
*
*/
export default async function loggerFile(req, reply) {
const { params = {}, user = {}, query = {}, originalUrl } = req;
const access = checkUserAccess({ user, token: query.token });
if (access?.status !== 200)
return reply.status(access.status).send(access.message);
// absolute / relative path
const filepath = path.join(rootDir, params["*"] || "");
if (!existsSync(filepath)) {
return reply.status(404).send("file not exists");
}
const stat = await lstat(filepath);
const isFile = stat.isFile();
if (query.download && isFile) {
const buffer = await readFile(filepath);
return buffer;
}
if (query.full && isFile) {
if (stat.size > 20 * 1000 * 1000) {
return reply.status(400).send({ error: "file size > 20MB", code: 400 });
}
const buffer = await readFile(filepath);
return buffer;
}
if (isFile) {
const ext = path.extname(filepath);
const lines = await new Promise((resolve) => {
const rl = readline.createInterface({
input: createReadStream(filepath, {
start: stat.size > limit ? stat.size - limit : 0,
}),
});
const lines1 = [];
rl.on("close", () => resolve(lines1));
rl.on("line", (line) => lines1.push(line));
});
if (ext === ".html") {
const buffer = await readFile(filepath);
reply.headers({ "Content-type": "text/html; charset=UTF-8" });
return buffer;
}
reply.headers({ "Content-type": "text/plain; charset=UTF-8" });
return stat.size > limit && lines.length > 1
? lines.reverse().slice(0, -1).join("\n")
: lines.reverse().join("\n");
}
// dir
const files = await readdir(filepath);
if (query.dir) {
return files.filter((el) => !["backup", "marker_icon", "error", "migration"].includes(el));
}
const lstatsArr = await Promise.all(files.map(async (file) => [file, await lstat(path.join(filepath, file))]));
const lstats = Object.fromEntries(lstatsArr);
const relpaceable = query.token ? `?token=${query.token}` : "";
const relpath = query.token
? originalUrl.replace(relpaceable, "")
: originalUrl;
const message = (params["*"] ? '<a href="/logger-file/">...</a><br>' : "") +
files
.sort((a, b) => lstats[a].mtimeMs - lstats[b].mtimeMs)
.map((file) => `<a href="${relpath}/${file}${relpaceable}">${file}</a> (${lstats[file].size} bytes)`)
.join("</br>");
reply.headers({
"Content-Type": "text/html; charset=UTF-8",
"Content-Security-Policy": "default-src 'none'",
"X-Content-Type-Options": "nosniff",
});
return message;
}