chore(pockethost): improve CLI launching and logging

This commit is contained in:
Ben Allfree 2025-07-22 08:13:27 -07:00
parent 630e4ec8f8
commit 7946c8344e
12 changed files with 70 additions and 72 deletions

View File

@ -1,6 +1,6 @@
import {
DOCKER_INSTANCE_IMAGE_NAME,
LoggerService,
Logger,
MOTHERSHIP_ADMIN_PASSWORD,
MOTHERSHIP_ADMIN_USERNAME,
MOTHERSHIP_URL,
@ -8,18 +8,21 @@ import {
PocketbaseService,
discordAlert,
instanceService,
neverendingPromise,
proxyService,
realtimeLog,
tryFetch,
} from '@'
import Dockerode from 'dockerode'
import { ErrorRequestHandler } from 'express'
import { CronService } from 'src/services/CronService'
import { MothershipMirrorService } from 'src/services/MothershipMirrorService'
export async function daemon() {
const logger = LoggerService().create(`cli:daemon`)
const { info, warn } = logger
export type DaemonOptions = {
logger: Logger
}
export async function daemon({ logger }: DaemonOptions) {
const { info, warn } = logger.create(`daemon`)
info(`Starting`)
const docker = new Dockerode()
@ -58,6 +61,8 @@ export async function daemon() {
await MothershipMirrorService({ client: (await MothershipAdminClientService()).client.client, logger })
await CronService({ logger })
await proxyService({
coreInternalUrl: MOTHERSHIP_URL(),
logger,
@ -74,6 +79,4 @@ export async function daemon() {
res.status(500).send(err.toString())
}
;(await proxyService()).use(errorHandler)
await neverendingPromise(logger)
}

View File

@ -1,4 +1,4 @@
import { logger } from '@'
import { LoggerService, neverendingPromise } from '@'
import { Command } from 'commander'
import { daemon } from './daemon'
@ -8,8 +8,12 @@ type Options = {
export const ServeCommand = () => {
const cmd = new Command(`serve`).description(`Run an edge daemon server`).action(async (options: Options) => {
logger().context({ cli: 'edge:daemon:serve' })
await daemon()
const logger = LoggerService().create(`cli:edge:daemon:serve`)
const { info, warn } = logger
info(`Starting`)
await daemon({ logger })
await neverendingPromise(logger)
})
return cmd
}

View File

@ -1,5 +1,5 @@
import { LoggerService } from '@'
import { MOTHERSHIP_URL, neverendingPromise, tryFetch } from '../../../../..'
import { MOTHERSHIP_URL, tryFetch } from '../../../../..'
import { ftpService } from '../FtpService'
export async function ftp() {
@ -13,6 +13,4 @@ export async function ftp() {
mothershipUrl: MOTHERSHIP_URL(),
logger,
})
await neverendingPromise(logger)
}

View File

@ -1,4 +1,4 @@
import { logger } from '@'
import { LoggerService, neverendingPromise } from '@'
import { Command } from 'commander'
import { ftp } from './ftp'
@ -8,8 +8,11 @@ type Options = {
export const ServeCommand = () => {
const cmd = new Command(`serve`).description(`Run an edge FTP server`).action(async (options: Options) => {
logger().context({ cli: 'edge:ftp:serve' })
const logger = LoggerService().create(`cli:edge:ftp:serve`)
const { info } = logger
info(`Starting`)
await ftp()
await neverendingPromise(logger)
})
return cmd
}

View File

@ -1,10 +1,10 @@
import { logger } from '@'
import { Logger } from '@'
import { Handler, Request } from 'express'
import { createProxyMiddleware } from 'http-proxy-middleware'
import vhost from 'vhost'
export function createVhostProxyMiddleware(host: string, target: string, ws = false): Handler {
const { dbg } = logger()
export function createVhostProxyMiddleware(host: string, target: string, ws = false, logger: Logger): Handler {
const { dbg } = logger
dbg(`Creating ${host}->${target}`)
const handler = createProxyMiddleware({ target, ws, changeOrigin: ws })
return vhost(host, (_req, res, next) => {

View File

@ -3,10 +3,9 @@ import {
DAEMON_PORT,
IPCIDR_LIST,
IS_DEV,
LoggerService,
Logger,
MOTHERSHIP_NAME,
MOTHERSHIP_PORT,
neverendingPromise,
SSL_CERT,
SSL_KEY,
} from '@'
@ -22,9 +21,12 @@ import https from 'https'
import { createIpWhitelistMiddleware } from './cidr'
import { createVhostProxyMiddleware } from './createVhostProxyMiddleware'
export const firewall = async () => {
const logger = LoggerService().create(`cli:firewall:serve`)
const { dbg, error } = logger
export type FirewallOptions = {
logger: Logger
}
export const firewall = async ({ logger }: FirewallOptions) => {
const { dbg, error } = logger.create(`firewall`)
const PROD_ROUTES = {
[`${MOTHERSHIP_NAME()}.${APEX_DOMAIN()}`]: `http://localhost:${MOTHERSHIP_PORT()}`,
@ -53,7 +55,7 @@ export const firewall = async () => {
app.use(createIpWhitelistMiddleware(IPCIDR_LIST()))
forEach(hostnameRoutes, (target, host) => {
app.use(createVhostProxyMiddleware(host, target, IS_DEV()))
app.use(createVhostProxyMiddleware(host, target, IS_DEV(), logger))
})
// Fall-through
@ -98,6 +100,4 @@ export const firewall = async () => {
httpsServer.listen(443, () => {
dbg('HTTPS server running on port 443')
})
await neverendingPromise(logger)
}

View File

@ -1,4 +1,4 @@
import { logger } from '@'
import { LoggerService, neverendingPromise } from '@'
import { Command } from 'commander'
import { firewall } from './firewall/server'
@ -8,8 +8,11 @@ type Options = {
export const ServeCommand = () => {
const cmd = new Command(`serve`).description(`Serve the root firewall`).action(async (options: Options) => {
logger().context({ cli: 'firewall:serve' })
await firewall()
const logger = LoggerService().create(`cli:firewall:serve`)
const { info, warn } = logger
info(`Starting`)
await firewall({ logger })
await neverendingPromise(logger)
})
return cmd
}

View File

@ -1,4 +1,4 @@
import { logger } from '@'
import { LoggerService } from '@'
import { Command } from 'commander'
import { schema } from './schema'
@ -6,8 +6,8 @@ export const SchemaCommand = () => {
const cmd = new Command(`schema`)
.description(`Create snapshot of the current PocketHost mothership schema`)
.action(async (options) => {
logger().context({ cli: 'mothership:schema' })
await schema()
const logger = LoggerService().create(`cli:mothership:schema`)
await schema({ logger })
})
return cmd
}

View File

@ -1,16 +1,12 @@
import {
GobotService,
IS_DEV,
LoggerService,
MOTHERSHIP_DATA_ROOT,
MOTHERSHIP_MIGRATIONS_DIR,
MOTHERSHIP_SEMVER,
} from '@'
import { GobotService, IS_DEV, Logger, MOTHERSHIP_DATA_ROOT, MOTHERSHIP_MIGRATIONS_DIR, MOTHERSHIP_SEMVER } from '@'
import { GobotOptions } from 'gobot'
export async function schema() {
const logger = LoggerService().create(`MothershipSchema`)
const { dbg, error, info, warn } = logger
export type SchemaOptions = {
logger: Logger
}
export async function schema({ logger }: SchemaOptions) {
const { dbg, error, info, warn } = logger.create(`schema`)
info(`Starting`)
const options: Partial<GobotOptions> = {

View File

@ -2,20 +2,12 @@ import { LoggerService, neverendingPromise } from '@'
import { Command } from 'commander'
import { mothership } from './mothership'
type Options = {
isolate: boolean
}
export const ServeCommand = () => {
const cmd = new Command(`serve`)
.description(`Run the PocketHost mothership`)
.option(`--isolate`, `Use Docker for process isolation.`, false)
.action(async (options: Options) => {
const logger = LoggerService().create(`cli:mothership:serve`)
const { dbg } = logger
dbg({ options })
await mothership(options)
await neverendingPromise(logger)
})
const cmd = new Command(`serve`).description(`Run the PocketHost mothership`).action(async () => {
const logger = LoggerService().create(`cli:mothership:serve`)
const { dbg } = logger
await mothership({ logger })
await neverendingPromise(logger)
})
return cmd
}

View File

@ -8,7 +8,7 @@ import {
exitHook,
GobotService,
IS_DEV,
LoggerService,
Logger,
LS_WEBHOOK_SECRET,
mkContainerHomePath,
MOTHERSHIP_CLOUDFLARE_ACCOUNT_ID,
@ -25,11 +25,12 @@ import {
} from '@'
import { GobotOptions } from 'gobot'
export type MothershipConfig = {}
export type MothershipConfig = {
logger: Logger
}
export async function mothership(cfg: MothershipConfig) {
const logger = LoggerService().create(`cli:mothership`)
const { dbg, error, info, warn } = logger
export async function mothership({ logger }: MothershipConfig) {
const { dbg, error, info, warn } = logger.create(`mothership`)
info(`Starting`)
/** Launch central database */
@ -77,10 +78,12 @@ export async function mothership(cfg: MothershipConfig) {
bot.run(args, { env, cwd: _MOTHERSHIP_APP_ROOT() }, (proc) => {
proc.stdout.on('data', (data) => {
info(data.toString())
const lines = data.toString().split(`\n`) as string[]
lines.forEach((line) => info(line))
})
proc.stderr.on('data', (data) => {
error(data.toString())
const lines = data.toString().split(`\n`) as string[]
lines.forEach((line) => error(line))
})
proc.on('close', (code, signal) => {
error(`Pocketbase exited with code ${code} and signal ${signal}`)

View File

@ -4,21 +4,17 @@ import { daemon } from '../EdgeCommand/DaemonCommand/ServeCommand/daemon'
import { firewall } from '../FirewallCommand/ServeCommand/firewall/server'
import { mothership } from '../MothershipCommand/ServeCommand/mothership'
type Options = {
isolate: boolean
}
export const ServeCommand = () => {
const cmd = new Command(`serve`).description(`Run the entire PocketHost stack`).action(async (options: Options) => {
const cmd = new Command(`serve`).description(`Run the entire PocketHost stack`).action(async () => {
const logger = LoggerService().create(`cli:serve`)
const { dbg, error, info, warn } = logger
info(`Starting`)
await mothership(options)
await mothership({ logger })
dbg(`Mothership ready`)
await daemon()
await daemon({ logger })
dbg(`Daemon ready`)
await firewall()
await firewall({ logger })
dbg(`Firewall ready`)
await neverendingPromise(logger)
})