Compare commits

...

10 commits

5 changed files with 43 additions and 22 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "@andyburke/serverus", "name": "@andyburke/serverus",
"description": "A flexible HTTP server for mixed content. Throw static files, markdown, Typescript and (hopefully, eventually) more into a directory and serverus can serve it up a bit more like old-school CGI.", "description": "A flexible HTTP server for mixed content. Throw static files, markdown, Typescript and (hopefully, eventually) more into a directory and serverus can serve it up a bit more like old-school CGI.",
"version": "0.0.4", "version": "0.0.12",
"license": "MIT", "license": "MIT",
"exports": { "exports": {
".": "./serverus.ts", ".": "./serverus.ts",

9
handlers/index.ts Normal file
View file

@ -0,0 +1,9 @@
import * as markdown from './markdown.ts';
import * as static_files from './static.ts';
import * as typescript from './typescript.ts';
export default {
markdown,
static: static_files,
typescript
};

View file

@ -4,10 +4,9 @@
*/ */
import * as colors from '@std/fmt/colors'; import * as colors from '@std/fmt/colors';
import * as fs from '@std/fs';
import * as path from '@std/path'; import * as path from '@std/path';
const DEFAULT_HANDLER_DIRECTORIES = [path.resolve(path.join(path.dirname(path.fromFileUrl(import.meta.url)), 'handlers'))]; const DEFAULT_HANDLER_DIRECTORIES = [import.meta.resolve('./handlers')];
/** A `HANDLER` must take a `Request` and return a `Response` if it can handle it. */ /** A `HANDLER` must take a `Request` and return a `Response` if it can handle it. */
type HANDLER = (request: Request) => Promise<Response | null | undefined> | Response | null | undefined; type HANDLER = (request: Request) => Promise<Response | null | undefined> | Response | null | undefined;
@ -103,26 +102,35 @@ export class SERVER {
this.controller = new AbortController(); this.controller = new AbortController();
const { signal } = this.controller; const { signal } = this.controller;
const HANDLERS_DIRECTORIES: string[] = const HANDLERS_DIRECTORIES: string[] = Deno.env.get('SERVERUS_HANDLERS')
Deno.env.get('SERVERUS_HANDLERS')?.split(/[;:]/g)?.filter((dir) => dir.length > 0)?.map((dir) => path.resolve(dir)) ?? ?.split(/[;]/g)
DEFAULT_HANDLER_DIRECTORIES; ?.filter((dir) => dir.length > 0)
?.map((dir) => {
return dir.includes('://') ? dir : path.resolve(dir);
}) ?? DEFAULT_HANDLER_DIRECTORIES;
for (const handler_directory of HANDLERS_DIRECTORIES) { for (const handler_directory of HANDLERS_DIRECTORIES) {
const resolved_handler_directory_glob = path.resolve(path.join(handler_directory, '*.ts')); const index_file = path.join(handler_directory, 'index.ts');
for await (const globbed_record of fs.expandGlob(resolved_handler_directory_glob)) {
if (!globbed_record.isFile) {
continue;
}
const import_path = new URL('file://' + globbed_record.path, import.meta.url).toString(); try {
const handler_module: HANDLER_MODULE = await import(import_path); const handlers_index = await import(index_file);
if (typeof handler_module.default !== 'function') {
console.warn(`Could not load handler, no default exported function: ${globbed_record.path}`); for (const handler_name of Object.keys(handlers_index.default)) {
const handler_module: HANDLER_MODULE = handlers_index.default[handler_name];
if (typeof handler_module?.default !== 'function') {
console.warn(`Could not load handler "${handler_name}" - no default exported function`);
continue; continue;
} }
this.handlers.push(handler_module); this.handlers.push(handler_module);
} }
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
console.warn(`Could not load handler index from: ${index_file}`);
continue;
}
throw error;
}
} }
if (this.handlers.length === 0) { if (this.handlers.length === 0) {

View file

@ -16,13 +16,12 @@ Deno.test({
const old_handlers: string | undefined = Deno.env.get('SERVERUS_HANDLERS'); const old_handlers: string | undefined = Deno.env.get('SERVERUS_HANDLERS');
try { try {
Deno.chdir('./tests/www');
Deno.env.set( Deno.env.set(
'SERVERUS_HANDLERS', 'SERVERUS_HANDLERS',
`${path.join(path.dirname(path.resolve(path.fromFileUrl(import.meta.url))), 'handlers')}${ `${import.meta.resolve('./handlers')}${old_handlers ? (';' + old_handlers) : ''}`
old_handlers ? (';' + old_handlers) : ''
}`
); );
Deno.chdir('./tests/www');
test_server_info = await get_ephemeral_listen_server(); test_server_info = await get_ephemeral_listen_server();
const response = await fetch(`http://${test_server_info.hostname}:${test_server_info.port}/echo/hello_world.foo`, { const response = await fetch(`http://${test_server_info.hostname}:${test_server_info.port}/echo/hello_world.foo`, {

5
tests/handlers/index.ts Normal file
View file

@ -0,0 +1,5 @@
import * as foo from './foo.ts';
export default {
foo
};