Dwelling/files.js

119 lines
3.1 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 config = require("./config");
const util = require("./util");
const { ENOENT, ECONNRESET } = require("constants");
const SIZE_UNITS = [ "B", "KiB", "MiB", "GiB" ];
function makeCurrentPathField(path) {
let current = `<a href="/">root</a>`;
if (path.endsWith("/"))
path = path.slice(1, path.length-1);
const path_parts = path.split("/");
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, SIZE_UNITS[i]];
}
function sortByNameField(a, b) {
if (a.name > b.name)
return 1;
else if (a.name < b.name)
return -1;
return 0;
}
async function getDirectoryList(dir_path, orig_url) {
let dirs = [];
let files = [];
let total_files_size = 0;
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: `${encodeURIComponent(dirent.name)}/`,
datetime: util.datetime(stat.mtime, util.formats.file_date),
size: "DIR",
size_unit: '' });
else {
total_files_size += stat.size;
files.push({
name: dirent.name,
link: `/files${orig_url}${encodeURIComponent(dirent.name)}`,
datetime: util.datetime(stat.mtime, util.formats.file_date),
size: +s,
size_unit: u });
}
}
dirs.sort(sortByNameField);
files.sort(sortByNameField);
return [dirs.concat(files), dirs.length, files.length,
convertSize(total_files_size).join(' ')];
}
function setRoutes(router) {
router.get('/(.*)?', async ctx => {
const file_path = path.join(config.files.file_path, decodeURI(ctx.originalUrl));
let stat = fs.lstatSync(file_path);
if (stat.isDirectory()) {
const [items, total_directories, total_files, total_files_size]
= await getDirectoryList(file_path, decodeURI(ctx.originalUrl));
await ctx.render('index', {
title: "/ Files",
description: "File share.",
main_site: util.getServiceByHost(ctx.header.host),
current_path: makeCurrentPathField(decodeURI(ctx.originalUrl)),
total_files: total_files,
total_files_size: total_files_size,
total_directories: total_directories,
items: items });
}
});
}
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())
.on("error", err => { if (!err.code == ECONNRESET || !err.code == ENOENT) console.log(err.code); })
.listen(config.files.port, config.files.host);
return app;
}