diff --git a/frontend.js b/frontend.js index d75bb90..cb4d347 100644 --- a/frontend.js +++ b/frontend.js @@ -1,6 +1,17 @@ export class Frontend { + constructor({apiBaseUrl, appBaseUrl}) { + this.apiBaseUrl = apiBaseUrl + this.appBaseUrl = appBaseUrl + this.files = {} + this.tasks = [] + } + repoUrl(user, repo) { - + return ( + this.apiBaseUrl + + '/' + encodeURIComponent(user) + + '/' + encodeURIComponent(repo) + ) } rawUrl(user, repo, commit, path) { @@ -12,10 +23,86 @@ export class Frontend { ) } + async loadFile(user, repo, commit, src, dest) { + const url = this.rawUrl(user, repo) + const resp = await fetch(url) + const body = await resp.arrayBuffer() + this.files[dest] = { + user, + repo, + commit, + body, + contentType: ( + dest.endsWith('.js') ? + 'text/javascript' : + resp.headers.get('content-type') + ) + } + } + + contentsUrl(user, repo, path, ref) { + const url = new URL( + this.repoUrl(user, repo) + + '/contents' + + path.map(s => ( + '/' + encodeURIComponent(s) + )).join('') + ) + if (ref !== undefined) { + const search = new URLSearchParams() + search.set('ref', ref) + url.search = search.toString() + } + return url.toString() + } + + async loadRepo(user, repo, opts) { + const { + srcPath = [], destPath = [], ref + } = opts + const url = this.contentsUrl( + user, repo, srcPath, ref + ) + const resp = await fetch(url) + const contents = await resp.json() + for (const item of contents) { + if (item.type === 'dir') { + this.tasks.push(this.loadRepo(user, repo, { + ...opts, + srcPath: [...srcPath, item.name], + destPath: [...destPath, item.name], + })) + } else { + this.tasks.push(this.loadFile( + user, + repo, + last_commit_sha, + [...srcPath, item.name], + [...destPath, item.name], + )) + } + } + let prevCount = 0 + while (this.tasks.count > prevCount) { + prevCount = this.tasks.count + await Promise.allSettled(this.tasks) + } + } + async serve(event) { - // TODO: load files from different mounted repos - event.respondWith(new Response( - 'Not Found', {status: 404} - )) + const {pathname} = new URL(event.request.url) + if (pathname in this.files) { + const file = this.files[pathname] + event.respondWith(new Response(file.body, { + status: 404, + headers: { + 'Content-Type': file.contentType, + }, + })) + } else { + event.respondWith(new Response( + 'Not Found', {status: 404} + )) + } } } \ No newline at end of file diff --git a/server.js b/server.js index 7debcfe..5fba0c7 100644 --- a/server.js +++ b/server.js @@ -2,11 +2,6 @@ import { Auth } from "./auth" import { Frontend } from "./frontend" export class Server { - constructor() { - this.auth = new Auth() - this.frontend = new Frontend() - } - async getEnv(variables) { return Object.fromEntries( await Promise.all( @@ -26,10 +21,27 @@ export class Server { async configure() { const env = await this.getEnv([ - 'PORT', 'BASE_URL' + 'PORT', + 'BASE_URL', + 'GITEA_APP_BASE_URL', + 'GITEA_API_BASE_URL', ]) this.port = env.PORT ?? 3000 this.baseUrl = env.BASE_URL ?? '/macchiato' + this.giteaAppBaseUrl = ( + env.GITEA_APP_BASE_URL ?? 'http://gitea:3000' + ) + this.giteaApiBaseUrl = ( + env.GITEA_API_BASE_URL ?? 'http://gitea:3000/api/v1' + ) + } + + async init() { + this.auth = new Auth() + this.frontend = new Frontend({ + appBaseUrl: this.giteaAppBaseUrl, + apiBaseUrl: this.giteaApiBaseUrl, + }) } async serveRequest(event) { @@ -50,6 +62,7 @@ export class Server { async serve() { await this.configure() + await this.init() this.server = Deno.listen({ port: this.port, })