From 4794bcc2f15952c3d7805cc0e8f6a900efa852e5 Mon Sep 17 00:00:00 2001 From: Leandro Facchinetti Date: Mon, 7 Nov 2022 19:40:58 +0000 Subject: [PATCH] --- server/index.mts | 288 +++++++++++++++++++++-------------------------- 1 file changed, 128 insertions(+), 160 deletions(-) diff --git a/server/index.mts b/server/index.mts index bc27eef..88fdeac 100644 --- a/server/index.mts +++ b/server/index.mts @@ -212,7 +212,7 @@ await commander.program processType, processNumber, }: { - processType: "main" | "server" | "worker"; + processType: "main" | "web" | "email"; processNumber: string; } ) => { @@ -241,18 +241,26 @@ await commander.program }); const application = { - name: "courselore", + name: "kill-the-newsletter", version, process: { id: Math.random().toString(36).slice(2), type: processType, - number: - typeof processNumber === "string" - ? Number(processNumber) - : undefined, + number: (typeof processNumber === "string" + ? Number(processNumber) + : undefined) as number, }, configuration: (await import(url.pathToFileURL(configuration).href)) - .default, + .default as { + hostname: string; + dataDirectory: string; + administratorEmail: string; + environment: "production" | "development" | "other"; + tunnel: boolean; + alternativeHostnames: string[]; + hstsPreload: boolean; + caddy: string; + }, static: JSON.parse( await fs.readFile( new URL("../static/paths.json", import.meta.url), @@ -260,37 +268,25 @@ await commander.program ) ), ports: { - server: lodash.times( + web: lodash.times( os.cpus().length, (processNumber) => 6000 + processNumber ), - serverEvents: lodash.times( - os.cpus().length, - (processNumber) => 7000 + processNumber - ), - workerEvents: lodash.times( - os.cpus().length, - (processNumber) => 8000 + processNumber - ), }, - addresses: { - canonicalHostname: "courselore.org", - metaCourseloreInvitation: "https://meta.courselore.org", - tryHostname: "try.courselore.org", - }, - server: express() as any, - serverEvents: express() as any, - workerEvents: express() as any, - } as Application; + web: express(), + email: "TODO", + }; application.configuration.environment ??= "production"; - application.configuration.demonstration ??= - application.configuration.environment !== "production"; application.configuration.tunnel ??= false; application.configuration.alternativeHostnames ??= []; application.configuration.hstsPreload ??= false; application.configuration.caddy ??= caddyfile``; + application.web.get("/", (request, response) => { + response.send("TODO"); + }); + // #!/usr/bin/env node // import path from "path"; @@ -814,25 +810,26 @@ await commander.program const childProcesses = new Set(); let restartChildProcesses = true; for (const execaArguments of [ - ...["server", "worker"].flatMap((processType) => - lodash.times(os.cpus().length, (processNumber) => ({ - file: process.argv[0], - arguments: [ - process.argv[1], - "--process-type", - processType, - "--process-number", - processNumber, - configuration, - ], - options: { - preferLocal: true, - stdio: "inherit", - ...(application.configuration.environment === "production" - ? { env: { NODE_ENV: "production" } } - : {}), - }, - })) + ...Object.entries({ web: os.cpus().length, email: 1 }).flatMap( + ([processType, processCount]) => + lodash.times(processCount, (processNumber) => ({ + file: process.argv[0], + arguments: [ + process.argv[1], + "--process-type", + processType, + "--process-number", + processNumber, + configuration, + ], + options: { + preferLocal: true, + stdio: "inherit", + ...(application.configuration.environment === "production" + ? { env: { NODE_ENV: "production" } } + : {}), + }, + })) ), { file: "caddy", @@ -842,114 +839,100 @@ await commander.program stdout: "ignore", stderr: "ignore", input: caddyfile` - { - admin off - ${ - application.configuration.environment === "production" - ? `email ${application.configuration.administratorEmail}` - : `local_certs` + { + admin off + ${ + application.configuration.environment === "production" + ? `email ${application.configuration.administratorEmail}` + : `local_certs` + } } - } - (common) { - header Cache-Control no-store - header Content-Security-Policy "default-src https://${ - application.configuration.hostname - }/ 'unsafe-inline' 'unsafe-eval'; frame-ancestors 'none'; object-src 'none'" - header Cross-Origin-Embedder-Policy require-corp - header Cross-Origin-Opener-Policy same-origin - header Cross-Origin-Resource-Policy same-origin - header Referrer-Policy no-referrer - header Strict-Transport-Security "max-age=31536000; includeSubDomains${ - application.configuration.hstsPreload ? `; preload` : `` - }" - header X-Content-Type-Options nosniff - header Origin-Agent-Cluster "?1" - header X-DNS-Prefetch-Control off - header X-Frame-Options DENY - header X-Permitted-Cross-Domain-Policies none - header -Server - header -X-Powered-By - header X-XSS-Protection 0 - header Permissions-Policy "interest-cohort=()" - encode zstd gzip - } + (common) { + header Cache-Control no-store + header Content-Security-Policy "default-src https://${ + application.configuration.hostname + }/ 'unsafe-inline' 'unsafe-eval'; frame-ancestors 'none'; object-src 'none'" + header Cross-Origin-Embedder-Policy require-corp + header Cross-Origin-Opener-Policy same-origin + header Cross-Origin-Resource-Policy same-origin + header Referrer-Policy no-referrer + header Strict-Transport-Security "max-age=31536000; includeSubDomains${ + application.configuration.hstsPreload ? `; preload` : `` + }" + header X-Content-Type-Options nosniff + header Origin-Agent-Cluster "?1" + header X-DNS-Prefetch-Control off + header X-Frame-Options DENY + header X-Permitted-Cross-Domain-Policies none + header -Server + header -X-Powered-By + header X-XSS-Protection 0 + header Permissions-Policy "interest-cohort=()" + encode zstd gzip + } - ${[ - application.configuration.tunnel - ? [] - : [application.configuration.hostname], - ...application.configuration.alternativeHostnames, - ] - .map((hostname) => `http://${hostname}`) - .join(", ")} { - import common - redir https://{host}{uri} 308 - handle_errors { + ${[ + ...(application.configuration.tunnel + ? [] + : [application.configuration.hostname]), + ...application.configuration.alternativeHostnames, + ] + .map((hostname) => `http://${hostname}`) + .join(", ")} { import common + redir https://{host}{uri} 308 + handle_errors { + import common + } } - } - ${ - application.configuration.alternativeHostnames.length > 0 - ? caddyfile` - ${application.configuration.alternativeHostnames - .map((hostname) => `https://${hostname}`) - .join(", ")} { - import common - redir https://${ - application.configuration.hostname - }{uri} 307 - handle_errors { + ${ + application.configuration.alternativeHostnames.length > 0 + ? caddyfile` + ${application.configuration.alternativeHostnames + .map((hostname) => `https://${hostname}`) + .join(", ")} { import common + redir https://${ + application.configuration.hostname + }{uri} 307 + handle_errors { + import common + } } - } - ` - : `` - } + ` + : `` + } - http${application.configuration.tunnel ? `` : `s`}://${ + http${application.configuration.tunnel ? `` : `s`}://${ application.configuration.hostname } { - route { - import common route { - root * ${JSON.stringify( - url.fileURLToPath( - new URL("../static/", import.meta.url) - ) - )} - @file_exists file - route @file_exists { - header Cache-Control "public, max-age=31536000, immutable" - file_server + import common + route { + root * ${JSON.stringify( + url.fileURLToPath( + new URL("../static/", import.meta.url) + ) + )} + @file_exists file + route @file_exists { + header Cache-Control "public, max-age=31536000, immutable" + file_server + } } + reverse_proxy ${application.ports.web + .map((port) => `127.0.0.1:${port}`) + .join(" ")} } - route /files/* { - root * ${JSON.stringify( - path.resolve(application.configuration.dataDirectory) - )} - @file_exists file - route @file_exists { - header Cache-Control "private, max-age=31536000, immutable" - @must_be_downloaded not path *.png *.jpg *.jpeg *.gif *.mp3 *.mp4 *.m4v *.ogg *.mov *.mpeg *.avi *.pdf *.txt - header @must_be_downloaded Content-Disposition attachment - @may_be_embedded_in_other_sites path *.png *.jpg *.jpeg *.gif *.mp3 *.mp4 *.m4v *.ogg *.mov *.mpeg *.avi *.pdf - header @may_be_embedded_in_other_sites Cross-Origin-Resource-Policy cross-origin - file_server - } + handle_errors { + import common } - reverse_proxy ${application.ports.server - .map((port) => `127.0.0.1:${port}`) - .join(" ")} } - handle_errors { - import common - } - } - ${application.configuration.caddy} - `, + ${application.configuration.caddy} + `, }, }, ]) @@ -979,37 +962,22 @@ await commander.program break; } - case "server": { - const serverApplication = application.server; - const eventsApplication = application.serverEvents; - serverApplication.emit("start"); - eventsApplication.emit("start"); - const server = serverApplication.listen( - application.ports.server[application.process.number], - "127.0.0.1" - ); - const events = eventsApplication.listen( - application.ports.serverEvents[application.process.number], + case "web": { + const webApplication = application.web; + webApplication.emit("start"); + const server = webApplication.listen( + application.ports.web[application.process.number], "127.0.0.1" ); await stop; server.close(); - events.close(); - serverApplication.emit("stop"); - eventsApplication.emit("stop"); + webApplication.emit("stop"); break; } - case "worker": { - const eventsApplication = application.workerEvents; - eventsApplication.emit("start"); - const events = eventsApplication.listen( - application.ports.workerEvents[application.process.number], - "127.0.0.1" - ); + case "email": { + // TODO await stop; - events.close(); - eventsApplication.emit("stop"); break; } }