diff options
Diffstat (limited to 'packages/web-util/src/serve.ts')
-rw-r--r-- | packages/web-util/src/serve.ts | 126 |
1 files changed, 74 insertions, 52 deletions
diff --git a/packages/web-util/src/serve.ts b/packages/web-util/src/serve.ts index 736e57430..1daea15bf 100644 --- a/packages/web-util/src/serve.ts +++ b/packages/web-util/src/serve.ts @@ -2,8 +2,9 @@ import { Logger } from "@gnu-taler/taler-util"; import chokidar from "chokidar"; import express from "express"; import https from "https"; +import http from "http"; import { parse } from "url"; -import WebSocket, { Server } from "ws"; +import WebSocket from "ws"; import locahostCrt from "./keys/localhost.crt"; import locahostKey from "./keys/localhost.key"; @@ -20,7 +21,6 @@ const logger = new Logger("serve.ts"); const PATHS = { WS: "/ws", - NOTIFY: "/notify", EXAMPLE: "/examples", APP: "/app", }; @@ -29,29 +29,38 @@ export async function serve(opts: { folder: string; port: number; source?: string; - development?: boolean; + tls?: boolean; examplesLocationJs?: string; examplesLocationCss?: string; - onUpdate?: () => Promise<void>; + onSourceUpdate?: () => Promise<void>; }): Promise<void> { const app = express(); app.use(PATHS.APP, express.static(opts.folder)); - const server = https.createServer(httpServerOptions, app); - server.listen(opts.port); - logger.info(`serving ${opts.folder} on ${opts.port}`); - logger.info(` ${PATHS.APP}: application`); - logger.info(` ${PATHS.EXAMPLE}: examples`); - logger.info(` ${PATHS.WS}: websocket`); - logger.info(` ${PATHS.NOTIFY}: broadcast`); - - if (opts.development) { - const wss = new Server({ noServer: true }); - - wss.on("connection", function connection(ws) { - ws.send("welcome"); - }); + const httpServer = http.createServer(app); + const httpPort = opts.port; + let httpsServer: typeof httpServer | undefined; + let httpsPort: number | undefined; + const servers = [httpServer]; + if (opts.tls) { + httpsServer = https.createServer(httpServerOptions, app); + httpsPort = opts.port + 1; + servers.push(httpsServer) + } + + logger.info(`Dev server. Endpoints:`); + logger.info(` ${PATHS.APP}: where root application can be tested`); + logger.info(` ${PATHS.EXAMPLE}: where examples can be found and browse`); + logger.info(` ${PATHS.WS}: websocket for live reloading`); + + const wss = new WebSocket.Server({ noServer: true }); + + wss.on("connection", function connection(ws) { + ws.send("welcome"); + }); + + servers.forEach(function addWSHandler(server) { server.on("upgrade", function upgrade(request, socket, head) { const { pathname } = parse(request.url || ""); if (pathname === PATHS.WS) { @@ -62,50 +71,63 @@ export async function serve(opts: { socket.destroy(); } }); + }); - const sendToAllClients = function (data: object): void { - wss.clients.forEach(function each(client) { - if (client.readyState === WebSocket.OPEN) { - client.send(JSON.stringify(data)); - } - }); - }; - const watchingFolder = opts.source ?? opts.folder; - logger.info(`watching ${watchingFolder} for change`); + const sendToAllClients = function (data: object): void { + wss.clients.forEach(function each(client) { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify(data)); + } + }); + }; + const watchingFolder = opts.source ?? opts.folder; + logger.info(`watching ${watchingFolder} for changes`); - chokidar.watch(watchingFolder).on("change", (path, stats) => { - logger.trace(`changed ${path}`); + chokidar.watch(watchingFolder).on("change", (path, stats) => { + logger.info(`changed: ${path}`); + if (opts.onSourceUpdate) { sendToAllClients({ type: "file-updated-start", data: { path } }); - if (opts.onUpdate) { - opts.onUpdate().then((result) => { + opts + .onSourceUpdate() + .then((result) => { sendToAllClients({ type: "file-updated-done", data: { path, result }, }); + }) + .catch((error) => { + sendToAllClients({ + type: "file-updated-failed", + data: { path, error: JSON.stringify(error) }, + }); }); - } else { - sendToAllClients({ type: "file-change-done", data: { path } }); - } - }); + } else { + sendToAllClients({ type: "file-change", data: { path } }); + } + }); - app.get(PATHS.EXAMPLE, function (req: any, res: any) { - res.set("Content-Type", "text/html"); - res.send( - storiesHtml - .replace( - "__EXAMPLES_JS_FILE_LOCATION__", - opts.examplesLocationJs ?? `.${PATHS.APP}/stories.js`, - ) - .replace( - "__EXAMPLES_CSS_FILE_LOCATION__", - opts.examplesLocationCss ?? `.${PATHS.APP}/stories.css`, - ), - ); - }); + if (opts.onSourceUpdate) opts.onSourceUpdate(); - app.get(PATHS.NOTIFY, function (req: any, res: any) { - res.send("ok"); - }); + app.get(PATHS.EXAMPLE, function (req: any, res: any) { + res.set("Content-Type", "text/html"); + res.send( + storiesHtml + .replace( + "__EXAMPLES_JS_FILE_LOCATION__", + opts.examplesLocationJs ?? `.${PATHS.APP}/stories.js`, + ) + .replace( + "__EXAMPLES_CSS_FILE_LOCATION__", + opts.examplesLocationCss ?? `.${PATHS.APP}/stories.css`, + ), + ); + }); + + logger.info(`Serving ${opts.folder} on ${httpPort}: plain HTTP`); + httpServer.listen(httpPort); + if (httpsServer !== undefined) { + logger.info(`Serving ${opts.folder} on ${httpsPort}: HTTP + TLS`); + httpsServer.listen(httpsPort); } } |