import { Auth } from "./auth.js" import { Frontend } from "./frontend.js" export class Server { async getEnv(variables) { return Object.fromEntries( await Promise.all( variables.map(async variable => { const {state} = await Deno.permissions.query({ name: 'env', variable }) if (state === 'granted') { return [variable, Deno.env.get(variable)] } else { return [variable, undefined] } }) ) ) } async configure() { const env = await this.getEnv([ 'PORT', 'BASE_URL', 'REMOTE_BASE_URL', 'GITEA_APP_BASE_URL', 'GITEA_API_BASE_URL', 'GITEA_WEB_BASE_URL', 'GITEA_CLIENT_ID', 'GITEA_CLIENT_SECRET', ]) this.port = env.PORT ?? 3000 this.baseUrl = env.BASE_URL ?? '/macchiato' this.remoteBaseUrl = env.REMOTE_BASE_URL this.giteaAppBaseUrl = ( env.GITEA_APP_BASE_URL ?? 'http://gitea:3000' ) this.giteaApiBaseUrl = ( env.GITEA_API_BASE_URL ?? 'http://gitea:3000/api/v1' ) this.giteaWebBaseUrl = env.GITEA_WEB_BASE_URL this.giteaClientId = env.GITEA_CLIENT_ID this.giteaClientSecret = env.GITEA_CLIENT_SECRET } async init() { if (this.port === undefined) { await this.configure() } this.auth = new Auth({ baseUrl: this.baseUrl, remoteBaseUrl: this.remoteBaseUrl, giteaAppBaseUrl: this.giteaAppBaseUrl, giteaApiBaseUrl: this.giteaApiBaseUrl, giteaWebBaseUrl: this.giteaWebBaseUrl, giteaClientId: this.giteaClientId, giteaClientSecret: this.giteaClientSecret, }) this.frontend = new Frontend({ appBaseUrl: this.giteaAppBaseUrl, apiBaseUrl: this.giteaApiBaseUrl, }) await Promise.all([ ...([ 'loader', 'editor', 'forms', 'menu', 'settings', 'dialog', 'storage', 'editor-lib-codemirror', ].map(repo => ( server.frontend.loadRepo( 'macchiato', repo, {srcPath: [], destPath: [repo]} ) ))), server.frontend.loadRepo( 'macchiato', 'pages', {srcPath: [], destPath: []} ), server.frontend.loadRepo( 'macchiato', 'server', { srcPath: [], destPath: ['server'], ref: 'shared-server' } ), ]) this.frontend.files['/app.js'] = ( this.frontend.files['/server/app.js'] ) this.frontend.files['/'] = ( this.frontend.files['/index.html'] ) const sw = this.frontend.files['/sw.js'] const commit = ( this.frontend.files['/server/app.js'].commit ) sw.body = ( new TextEncoder().encode( new TextDecoder().decode(sw.body) + `\n// ${commit}\n` ) ) } async serveRequest(event) { const {pathname} = new URL(event.request.url) if (pathname.startsWith(`${this.baseUrl}/api/auth`)) { await this.auth.serve(event) } else { await this.frontend.serve(event) } } async serveConn(conn) { const httpConn = Deno.serveHttp(conn) for await (const event of httpConn) { this.serveRequest(event) } } async serve() { if (!this.server) { await this.init() } this.server = Deno.listen({ port: this.port, }) for await (const conn of this.server) { this.serveConn(conn) } } }