140 lines
3.6 KiB
JavaScript
140 lines
3.6 KiB
JavaScript
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
const Koa = require("koa");
|
|
const koaPug = require("koa-pug");
|
|
const koaRouter = require("koa-router");
|
|
const koaRange = require("koa-range");
|
|
//const koaServe = require("koa-static");
|
|
const FileType = require("file-type");
|
|
|
|
const config = require("./config");
|
|
const util = require("./util");
|
|
const { type } = require("os");
|
|
const { ENOENT, ECONNRESET } = require("constants");
|
|
|
|
const sizeUnits = [ "B", "KiB", "MiB", "GiB" ];
|
|
|
|
function makeCurrentPathField(path) {
|
|
let current = "";
|
|
if (path.endsWith("/"))
|
|
path = path.slice(1, path.length-1);
|
|
const path_parts = path.split("/");
|
|
|
|
current = `<a href="/">root</a>`;
|
|
|
|
for (i = 0; i < path_parts.length; ++i) {
|
|
let lnk = "";
|
|
for (j = 0; j < i+1; ++j) {
|
|
lnk += `/${path_parts[j]}`;
|
|
}
|
|
current += `/<a href="${encodeURI(lnk)}/">${path_parts[i]}</a>`;
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
function convertSize(size) {
|
|
let i = 0;
|
|
for (; size > 1024; size /= 1024) { ++i; }
|
|
return [i > 0 ? size.toFixed(2) : size, sizeUnits[i]];
|
|
}
|
|
|
|
function fileType(name) {
|
|
if (name.endsWith("txt") || name.endsWith("md"))
|
|
return "text/plain";
|
|
return "octet-stream";
|
|
}
|
|
|
|
async function getDirectoryList(dir_path, base_url) {
|
|
let dirs = [];
|
|
let files = [];
|
|
let d = await fs.promises.opendir(dir_path);
|
|
for await (const dirent of d) {
|
|
const stat = fs.lstatSync(path.join(dir_path, dirent.name));
|
|
const [s, u] = convertSize(stat.size);
|
|
if (stat.isDirectory())
|
|
dirs.push({
|
|
name: dirent.name,
|
|
link: `${base_url}${encodeURIComponent(dirent.name)}/`,
|
|
datetime: util.datetime(stat.mtime, util.formats.file_date),
|
|
size: "DIR",
|
|
size_unit: '' });
|
|
else
|
|
files.push({
|
|
name: dirent.name,
|
|
link: `${base_url}${encodeURIComponent(dirent.name)}`,
|
|
datetime: util.datetime(stat.mtime, util.formats.file_date),
|
|
size: +s,
|
|
size_unit: u });
|
|
}
|
|
|
|
const sort_by_name = (a, b) => {
|
|
if (a.name > b.name)
|
|
return 1;
|
|
else if (a.name < b.name)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
dirs.sort(sort_by_name);
|
|
files.sort(sort_by_name);
|
|
|
|
return dirs.concat(files);
|
|
}
|
|
|
|
function setRoutes(router) {
|
|
router.get('/(.*)?', async (ctx, next) => {
|
|
if (ctx.originalUrl.startsWith("/assets") || ctx.originalUrl.startsWith("/shared")) {
|
|
await next();
|
|
return;
|
|
}
|
|
const file_path = path.join(config.files.file_path, decodeURI(ctx.originalUrl));
|
|
let stat = fs.lstatSync(file_path);
|
|
if (stat.isDirectory()) {
|
|
await ctx.render('index', {
|
|
title: "/ Files",
|
|
description: "File share.",
|
|
host: util.getBaseHost(ctx.header.host),
|
|
current_path: makeCurrentPathField(decodeURI(ctx.originalUrl)),
|
|
items: await getDirectoryList(file_path, ctx.originalUrl) });
|
|
} else {
|
|
let f = await FileType.fromStream(fs.createReadStream(file_path));
|
|
if (f === undefined)
|
|
ctx.type = fileType(file_path);
|
|
else
|
|
ctx.type = f.mime;
|
|
ctx.set("Content-Length", stat.size);
|
|
|
|
const stream = fs.createReadStream(file_path);
|
|
// let ch = 0;
|
|
// stream.on("end", () => { });
|
|
// stream.on("data", (chunk) => { ch += chunk.length; });
|
|
ctx.body = stream;
|
|
}
|
|
});
|
|
}
|
|
|
|
module.exports = () => {
|
|
const app = new Koa();
|
|
const pug = new koaPug({
|
|
viewPath: path.join(__dirname, "views", "files"),
|
|
locals: {
|
|
moment: date => util.datetime(date, util.formats.file_date) },
|
|
app: app
|
|
});
|
|
|
|
const radio_router = koaRouter();
|
|
setRoutes(radio_router);
|
|
|
|
app.proxy = true;
|
|
app
|
|
.use(koaRange)
|
|
.use(radio_router.routes())
|
|
// .use(koaServe(path.join("static", "shared")))
|
|
// .use(koaServe(path.join("static", "files")))
|
|
.on("error", err => { if (!err.code == ECONNRESET || !err.code == ENOENT) console.log(err.code); })
|
|
.listen(config.files.port, config.files.host);
|
|
|
|
return app;
|
|
} |