Serve static files
This commit is contained in:
parent
b0fd916eb4
commit
d5a9668e17
6 changed files with 1156 additions and 964 deletions
1994
package-lock.json
generated
1994
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,7 @@
|
|||
"main": "src/index.mjs",
|
||||
"scripts": {
|
||||
"test": "echo \"No tests have been implemented yet\"",
|
||||
"build": "node src/static/esbuild.mjs"
|
||||
"build": "node src/static/esbuild.mjs"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -21,15 +21,18 @@
|
|||
"@ltd/j-toml": "^1.29.0",
|
||||
"applause-cli": "^1.8.0",
|
||||
"jpake": "^1.0.1",
|
||||
"mime": "^3.0.0",
|
||||
"nexline": "^1.2.2",
|
||||
"p-queue": "^7.2.0",
|
||||
"p-reflect": "^3.0.0",
|
||||
"p-retry": "^5.0.0",
|
||||
"powahroot": "^1.1.1",
|
||||
"pretty-ms": "^7.0.1",
|
||||
"systeminformation": "^5.11.2",
|
||||
"tweetnacl": "^1.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mime": "^2.0.3",
|
||||
"esbuild": "^0.14.23",
|
||||
"fork-awesome": "^1.2.0"
|
||||
}
|
||||
|
|
|
@ -2,12 +2,31 @@
|
|||
|
||||
import ServerRouter from 'powahroot/Server.mjs';
|
||||
|
||||
import middleware_log from './routes/middleware_log.mjs';
|
||||
import middleware_catch_errors from './routes/middleware_errors.mjs';
|
||||
import route_table from './routes/table.mjs';
|
||||
import route_static from './routes/static.mjs';
|
||||
|
||||
export default function(sys) {
|
||||
const router = new ServerRouter();
|
||||
|
||||
router.on_all(middleware_catch_errors.bind(this, sys.config.verbose));
|
||||
router.on_all(middleware_log);
|
||||
|
||||
|
||||
///
|
||||
// API
|
||||
///
|
||||
router.get(`/api/table/:table_name`, route_table.bind(this, sys));
|
||||
|
||||
///
|
||||
// Web interface
|
||||
///
|
||||
router.get(`/`, async (ctx, next) => {
|
||||
ctx.params.filepath = `index.html`;
|
||||
await route_static(ctx, next);
|
||||
});
|
||||
router.get(`/static/::filepath`, route_static);
|
||||
|
||||
return router;
|
||||
}
|
||||
|
|
37
src/lib/agent/subsystems/http/routes/middleware_errors.mjs
Normal file
37
src/lib/agent/subsystems/http/routes/middleware_errors.mjs
Normal file
|
@ -0,0 +1,37 @@
|
|||
"use strict";
|
||||
|
||||
import pretty_ms from 'pretty-ms';
|
||||
|
||||
import log from '../../../../io/NamespacedLog.mjs'; const l = log("http:request");
|
||||
|
||||
/**
|
||||
* Handles errors thrown by handlers further down the chain.
|
||||
* @param {RequestContext} context The RequestContext object.
|
||||
* @param {Function} next The function to call to invoke the next middleware item
|
||||
*/
|
||||
async function middleware_catch_errors(verbose, context, next) {
|
||||
try {
|
||||
await next();
|
||||
} catch(error) {
|
||||
handle_error(verbose, error, context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a given error thrown by a given RequestContext.
|
||||
* @param {Error} error The error that was thrown.
|
||||
* @param {RequestContext} context The RequestContext from which the error was thrown.
|
||||
*/
|
||||
function handle_error(verbose, error, context) {
|
||||
l.info(`[?ms] [${context.request.method} 503] ${context.request.connection.remoteAddress} -> ${context.request.url}`);
|
||||
console.error(error.stack); // TODO: colourise this?
|
||||
// TODO: Send a better error page - perhaps with an error id that's uploaded to some remote system, or the prettified stack trace & offending code encrypted with a key?
|
||||
|
||||
if(!verbose)
|
||||
context.send.plain(503, "Error caught", "Oops! An error ocurred. Please report this to bugs@starbeamrainbowlabs.com");
|
||||
else
|
||||
context.send.plain(503, `*** Server Error ***\n${error.stack}\n`);
|
||||
|
||||
}
|
||||
|
||||
export default middleware_catch_errors;
|
15
src/lib/agent/subsystems/http/routes/middleware_log.mjs
Normal file
15
src/lib/agent/subsystems/http/routes/middleware_log.mjs
Normal file
|
@ -0,0 +1,15 @@
|
|||
"use strict";
|
||||
|
||||
import pretty_ms from 'pretty-ms';
|
||||
|
||||
import log from '../../../../io/NamespacedLog.mjs'; const l = log("http:request");
|
||||
|
||||
async function middleware_log_request(ctx, next) {
|
||||
let start = new Date();
|
||||
|
||||
await next();
|
||||
|
||||
l.info(`[${pretty_ms(new Date() - start)}] [${ctx.request.method} ${ctx.response.statusCode}] ${ctx.request.connection.remoteAddress} -> ${ctx.request.url}`);
|
||||
}
|
||||
|
||||
export default middleware_log_request;
|
50
src/lib/agent/subsystems/http/routes/static.mjs
Normal file
50
src/lib/agent/subsystems/http/routes/static.mjs
Normal file
|
@ -0,0 +1,50 @@
|
|||
"use strict";
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
import mime from 'mime';
|
||||
|
||||
const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf("/"));
|
||||
|
||||
const root_dir = path.resolve(__dirname, "../../../../../static-dist");
|
||||
|
||||
function make_path_safe(path) {
|
||||
return path.replace(/[^a-zA-Z0-9\-\._\/]/g, "")
|
||||
.replace(/\.+/g, ".");
|
||||
}
|
||||
|
||||
async function route_files(context, _next) {
|
||||
let safe_url = make_path_safe(context.params.filepath);
|
||||
let file_path = path.join(root_dir, safe_url);
|
||||
try {
|
||||
let info = await fs.promises.stat(file_path);
|
||||
if(info && info.isFile()) {
|
||||
context.response.writeHead(200, {
|
||||
"content-type": mime.getType(file_path),
|
||||
"content-length": info.size
|
||||
});
|
||||
fs.createReadStream(file_path)
|
||||
.pipe(context.response);
|
||||
}
|
||||
else {
|
||||
send_404(context, safe_url);
|
||||
return;
|
||||
}
|
||||
} catch(error) {
|
||||
if(error.code == "ENOENT") {
|
||||
send_404(context, safe_url);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function send_404(context, url) {
|
||||
context.send.plain(404, `Error: ${url} couldn't be found.`);
|
||||
}
|
||||
|
||||
export { route_files };
|
||||
export default route_files;
|
Loading…
Reference in a new issue