summaryrefslogtreecommitdiff
path: root/packages/web-util/src/serve.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/web-util/src/serve.ts')
-rw-r--r--packages/web-util/src/serve.ts126
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);
}
}