120 lines
7.8 KiB
TypeScript
120 lines
7.8 KiB
TypeScript
// This file was autogenerated from a .proto file, DO NOT EDIT!
|
|
|
|
import express, { Response, json, urlencoded } from 'express'
|
|
import cors from 'cors'
|
|
import * as Types from './types.js'
|
|
export type Logger = { log: (v: any) => void, error: (v: any) => void }
|
|
export type ServerOptions = {
|
|
allowCors?: true
|
|
staticFiles?: string
|
|
allowNotImplementedMethods?: true
|
|
logger?: Logger
|
|
throwErrors?: true
|
|
logMethod?: true
|
|
logBody?: true
|
|
metricsCallback: (metrics: Types.RequestMetric[]) => void
|
|
GuestAuthGuard: (authorizationHeader?: string) => Promise<Types.GuestContext>
|
|
}
|
|
declare module 'express-serve-static-core' { interface Request { startTime?: bigint, bodySize?: number, startTimeMs: number } }
|
|
const logErrorAndReturnResponse = (error: Error, response: string, res: Response, logger: Logger, metric: Types.RequestMetric, metricsCallback: (metrics: Types.RequestMetric[]) => void) => {
|
|
logger.error(error.message || error); metricsCallback([{ ...metric, error: response }]); res.json({ status: 'ERROR', reason: response })
|
|
}
|
|
export default (methods: Types.ServerMethods, opts: ServerOptions) => {
|
|
const logger = opts.logger || { log: console.log, error: console.error }
|
|
const app = express()
|
|
if (opts.allowCors) {
|
|
app.use(cors())
|
|
}
|
|
app.use((req, _, next) => { req.startTime = process.hrtime.bigint(); req.startTimeMs = Date.now(); next() })
|
|
app.use(json())
|
|
app.use(urlencoded({ extended: true }))
|
|
if (opts.logMethod) app.use((req, _, next) => { console.log(req.method, req.path); if (opts.logBody) console.log(req.body); next() })
|
|
if (!opts.allowNotImplementedMethods && !methods.GetAdminConnectInfo) throw new Error('method: GetAdminConnectInfo is not implemented')
|
|
app.get('/wizard/admin_connect_info', async (req, res) => {
|
|
const info: Types.RequestInfo = { rpcName: 'GetAdminConnectInfo', batch: false, nostr: false, batchSize: 0}
|
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
|
let authCtx: Types.AuthContext = {}
|
|
try {
|
|
if (!methods.GetAdminConnectInfo) throw new Error('method: GetAdminConnectInfo is not implemented')
|
|
const authContext = await opts.GuestAuthGuard(req.headers['authorization'])
|
|
authCtx = authContext
|
|
stats.guard = process.hrtime.bigint()
|
|
stats.validate = stats.guard
|
|
const query = req.query
|
|
const params = req.params
|
|
const response = await methods.GetAdminConnectInfo({rpcName:'GetAdminConnectInfo', ctx:authContext })
|
|
stats.handle = process.hrtime.bigint()
|
|
res.json({status: 'OK', ...response})
|
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
|
})
|
|
if (!opts.allowNotImplementedMethods && !methods.GetServiceState) throw new Error('method: GetServiceState is not implemented')
|
|
app.get('/wizard/service_state', async (req, res) => {
|
|
const info: Types.RequestInfo = { rpcName: 'GetServiceState', batch: false, nostr: false, batchSize: 0}
|
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
|
let authCtx: Types.AuthContext = {}
|
|
try {
|
|
if (!methods.GetServiceState) throw new Error('method: GetServiceState is not implemented')
|
|
const authContext = await opts.GuestAuthGuard(req.headers['authorization'])
|
|
authCtx = authContext
|
|
stats.guard = process.hrtime.bigint()
|
|
stats.validate = stats.guard
|
|
const query = req.query
|
|
const params = req.params
|
|
const response = await methods.GetServiceState({rpcName:'GetServiceState', ctx:authContext })
|
|
stats.handle = process.hrtime.bigint()
|
|
res.json({status: 'OK', ...response})
|
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
|
})
|
|
if (!opts.allowNotImplementedMethods && !methods.WizardConfig) throw new Error('method: WizardConfig is not implemented')
|
|
app.post('/wizard/config', async (req, res) => {
|
|
const info: Types.RequestInfo = { rpcName: 'WizardConfig', batch: false, nostr: false, batchSize: 0}
|
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
|
let authCtx: Types.AuthContext = {}
|
|
try {
|
|
if (!methods.WizardConfig) throw new Error('method: WizardConfig is not implemented')
|
|
const authContext = await opts.GuestAuthGuard(req.headers['authorization'])
|
|
authCtx = authContext
|
|
stats.guard = process.hrtime.bigint()
|
|
const request = req.body
|
|
const error = Types.ConfigRequestValidate(request)
|
|
stats.validate = process.hrtime.bigint()
|
|
if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback)
|
|
const query = req.query
|
|
const params = req.params
|
|
await methods.WizardConfig({rpcName:'WizardConfig', ctx:authContext , req: request})
|
|
stats.handle = process.hrtime.bigint()
|
|
res.json({status: 'OK'})
|
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
|
})
|
|
if (!opts.allowNotImplementedMethods && !methods.WizardState) throw new Error('method: WizardState is not implemented')
|
|
app.get('/wizard/state', async (req, res) => {
|
|
const info: Types.RequestInfo = { rpcName: 'WizardState', batch: false, nostr: false, batchSize: 0}
|
|
const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n }
|
|
let authCtx: Types.AuthContext = {}
|
|
try {
|
|
if (!methods.WizardState) throw new Error('method: WizardState is not implemented')
|
|
const authContext = await opts.GuestAuthGuard(req.headers['authorization'])
|
|
authCtx = authContext
|
|
stats.guard = process.hrtime.bigint()
|
|
stats.validate = stats.guard
|
|
const query = req.query
|
|
const params = req.params
|
|
const response = await methods.WizardState({rpcName:'WizardState', ctx:authContext })
|
|
stats.handle = process.hrtime.bigint()
|
|
res.json({status: 'OK', ...response})
|
|
opts.metricsCallback([{ ...info, ...stats, ...authContext }])
|
|
} catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e }
|
|
})
|
|
if (opts.staticFiles) {
|
|
app.use(express.static(opts.staticFiles))
|
|
app.get('*', function (_, res) { res.sendFile('index.html', { root: opts.staticFiles })})
|
|
}
|
|
var server: { close: () => void } | undefined
|
|
return {
|
|
Close: () => { if (!server) { throw new Error('tried closing server before starting') } else server.close() },
|
|
Listen: (port: number) => { server = app.listen(port, () => logger.log('Wizard listening on port ' + port)) }
|
|
}
|
|
}
|