You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
3.9 KiB
JavaScript
163 lines
3.9 KiB
JavaScript
import { Auth } from "./auth.js"
|
|
import { Frontend } from "./frontend.js"
|
|
import { Storage } from "./storage.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.basePath = env.BASE_PATH ?? '/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({
|
|
basePath: this.basePath,
|
|
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,
|
|
})
|
|
this.storage = new Storage()
|
|
await Promise.all([
|
|
...([
|
|
'loader',
|
|
'editor',
|
|
'forms',
|
|
'menu',
|
|
'settings',
|
|
'dialog',
|
|
'storage',
|
|
'editor-lib-codemirror',
|
|
].map(repo => (
|
|
server.frontend.loadRepo(
|
|
'macchiato',
|
|
repo.split('#')[0],
|
|
{
|
|
srcPath: [],
|
|
destPath: [repo],
|
|
...(
|
|
repo.includes('#') ?
|
|
{ref: repo.split('#')[1]} :
|
|
{}
|
|
),
|
|
}
|
|
)
|
|
))),
|
|
server.frontend.loadRepo(
|
|
'macchiato',
|
|
'pages',
|
|
{
|
|
srcPath: [],
|
|
destPath: [],
|
|
ref: 'shared-server',
|
|
},
|
|
),
|
|
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: p} = new URL(event.request.url)
|
|
const base = this.basePath
|
|
if (p.startsWith(`${base}/api/auth`)) {
|
|
await this.auth.serve(event)
|
|
} else if (p.startsWith(`${base}/api/storage`)) {
|
|
const {allow, headers} = (
|
|
await this.auth.requireAuth(event)
|
|
)
|
|
if (allow) {
|
|
await this.storage.serve(event, headers)
|
|
}
|
|
} 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)
|
|
}
|
|
}
|
|
} |