mirror of
https://github.com/pockethost/pockethost.git
synced 2025-11-24 06:25:48 +00:00
chore(pockethost): remove winston
This commit is contained in:
parent
e1f90aa22b
commit
8ec5d00df4
@ -20,7 +20,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"check:types": "tsc --noEmit ",
|
||||
"dev": "NODE_ENV=development tsx --watch ./src/cli/index.ts",
|
||||
"dev": "NODE_ENV=development tsx ./src/cli/index.ts",
|
||||
"start": "tsx ./src/cli/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -30,6 +30,7 @@
|
||||
"bottleneck": "^2.19.5",
|
||||
"commander": "^13.0.0",
|
||||
"cors": "^2.8.5",
|
||||
"cron": "^4.3.2",
|
||||
"devcert": "^1.2.2",
|
||||
"dockerode": "^4.0.3",
|
||||
"dotenv": "^16.4.7",
|
||||
@ -56,9 +57,7 @@
|
||||
"tail": "^2.2.6",
|
||||
"tsx": "^4.20.3",
|
||||
"type-fest": "^4.32.0",
|
||||
"vhost": "^3.0.2",
|
||||
"winston": "^3.17.0",
|
||||
"winston-transport": "^4.9.0"
|
||||
"vhost": "^3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/better-sqlite3": "^7.6.12",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import {
|
||||
DOCKER_INSTANCE_IMAGE_NAME,
|
||||
LoggerService,
|
||||
MOTHERSHIP_ADMIN_PASSWORD,
|
||||
MOTHERSHIP_ADMIN_USERNAME,
|
||||
MOTHERSHIP_URL,
|
||||
@ -7,7 +8,6 @@ import {
|
||||
PocketbaseService,
|
||||
discordAlert,
|
||||
instanceService,
|
||||
logger,
|
||||
neverendingPromise,
|
||||
proxyService,
|
||||
realtimeLog,
|
||||
@ -18,7 +18,8 @@ import { ErrorRequestHandler } from 'express'
|
||||
import { MothershipMirrorService } from 'src/services/MothershipMirrorService'
|
||||
|
||||
export async function daemon() {
|
||||
const { info, warn } = logger()
|
||||
const logger = LoggerService().create(`cli:daemon`)
|
||||
const { info, warn } = logger
|
||||
info(`Starting`)
|
||||
|
||||
const docker = new Dockerode()
|
||||
@ -41,9 +42,9 @@ export async function daemon() {
|
||||
})
|
||||
)
|
||||
|
||||
await PocketbaseService({})
|
||||
await PocketbaseService({ logger })
|
||||
|
||||
await tryFetch(MOTHERSHIP_URL(`/api/health`), {})
|
||||
await tryFetch(MOTHERSHIP_URL(`/api/health`), { logger })
|
||||
|
||||
info(`Serving`)
|
||||
|
||||
@ -52,17 +53,20 @@ export async function daemon() {
|
||||
url: MOTHERSHIP_URL(),
|
||||
username: MOTHERSHIP_ADMIN_USERNAME(),
|
||||
password: MOTHERSHIP_ADMIN_PASSWORD(),
|
||||
logger,
|
||||
})
|
||||
|
||||
await MothershipMirrorService({ client: (await MothershipAdminClientService()).client.client })
|
||||
await MothershipMirrorService({ client: (await MothershipAdminClientService()).client.client, logger })
|
||||
|
||||
await proxyService({
|
||||
coreInternalUrl: MOTHERSHIP_URL(),
|
||||
logger,
|
||||
})
|
||||
await realtimeLog({})
|
||||
await realtimeLog({ logger })
|
||||
await instanceService({
|
||||
instanceApiCheckIntervalMs: 50,
|
||||
instanceApiTimeoutMs: 5000,
|
||||
logger,
|
||||
})
|
||||
|
||||
const errorHandler: ErrorRequestHandler = (err: Error, req, res, next) => {
|
||||
@ -71,5 +75,5 @@ export async function daemon() {
|
||||
}
|
||||
;(await proxyService()).use(errorHandler)
|
||||
|
||||
await neverendingPromise()
|
||||
await neverendingPromise(logger)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { InstanceFields, InstanceLogWriter, InstanceLogWriterApi, Logger, PocketBase, assert, seqid } from '@'
|
||||
import { InstanceFields, InstanceLogWriterApi, Logger, PocketBase, assert, seqid } from '@'
|
||||
import { compact, forEach, map } from '@s-libs/micro-dash'
|
||||
import Bottleneck from 'bottleneck'
|
||||
import { spawn } from 'child_process'
|
||||
@ -26,7 +26,7 @@ export type PathError = {
|
||||
const UNIX_SEP_REGEX = /\//g
|
||||
const WIN_SEP_REGEX = /\\/g
|
||||
|
||||
const checkBun = (instance: InstanceFields, virtualPath: string, cwd: string) => {
|
||||
const checkBun = (instance: InstanceFields, virtualPath: string, cwd: string, logger: Logger) => {
|
||||
const [subdomain, maybeImportant, ...rest] = virtualPath.split('/').filter((p) => !!p)
|
||||
|
||||
const isImportant =
|
||||
@ -34,9 +34,8 @@ const checkBun = (instance: InstanceFields, virtualPath: string, cwd: string) =>
|
||||
(rest.length === 0 && [`bun.lock`, `bun.lockb`, `package.json`].includes(maybeImportant || ''))
|
||||
|
||||
if (isImportant) {
|
||||
const logger = InstanceLogWriter(instance.id, instance.volume, `exec`)
|
||||
logger.info(`${maybeImportant} changed, running bun install`)
|
||||
launchBunInstall(instance, virtualPath, cwd).catch(logger.error)
|
||||
launchBunInstall(instance, virtualPath, cwd, logger).catch(logger.error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +97,7 @@ const runBun = (() => {
|
||||
|
||||
const launchBunInstall = (() => {
|
||||
const runCache: { [key: string]: { runAgain: boolean } } = {}
|
||||
return async (instance: InstanceFields, virtualPath: string, cwd: string) => {
|
||||
return async (instance: InstanceFields, virtualPath: string, cwd: string, logger: Logger) => {
|
||||
if (cwd in runCache) {
|
||||
runCache[cwd]!.runAgain = true
|
||||
return
|
||||
@ -106,7 +105,6 @@ const launchBunInstall = (() => {
|
||||
runCache[cwd] = { runAgain: true }
|
||||
while (runCache[cwd]!.runAgain) {
|
||||
runCache[cwd]!.runAgain = false
|
||||
const logger = InstanceLogWriter(instance.id, instance.volume, `exec`)
|
||||
logger.info(`Launching 'bun install' in ${virtualPath}`)
|
||||
await prepPackageJson(cwd, logger)
|
||||
await runBun(cwd, logger)
|
||||
@ -229,7 +227,7 @@ export class PhFs implements FileSystem {
|
||||
}
|
||||
|
||||
async list(path = '.') {
|
||||
const { dbg, error } = this.log.create(`list`).breadcrumb({ cwd: this.cwd, path })
|
||||
const { dbg, error } = this.log.create(`list`).breadcrumb(this.cwd).breadcrumb(path)
|
||||
|
||||
const { fsPath, instance } = await this._resolvePath(path)
|
||||
|
||||
@ -278,7 +276,7 @@ export class PhFs implements FileSystem {
|
||||
async get(fileName: string): Promise<FileStat> {
|
||||
const { fsPath, instance, clientPath } = await this._resolvePath(fileName)
|
||||
|
||||
const { dbg, error } = this.log.create(`get`).breadcrumb({ cwd: this.cwd, fileName, fsPath })
|
||||
const { dbg, error } = this.log.create(`get`).breadcrumb(this.cwd).breadcrumb(fileName).breadcrumb(fsPath)
|
||||
dbg(`get`)
|
||||
|
||||
/*
|
||||
@ -319,7 +317,8 @@ export class PhFs implements FileSystem {
|
||||
}
|
||||
|
||||
async write(fileName: string, options?: { append?: boolean | undefined; start?: any } | undefined) {
|
||||
const { dbg, error } = this.log.create(`write`).breadcrumb({ cwd: this.cwd, fileName })
|
||||
const logger = this.log.create(`write`).breadcrumb(this.cwd).breadcrumb(fileName)
|
||||
const { dbg, error } = this.log.create(`write`).breadcrumb(this.cwd).breadcrumb(fileName)
|
||||
dbg(`write`)
|
||||
|
||||
const { fsPath, clientPath, instance } = await this._resolvePath(fileName)
|
||||
@ -341,7 +340,7 @@ export class PhFs implements FileSystem {
|
||||
const virtualPath = join(this.cwd, fileName)
|
||||
dbg(`write(${virtualPath}) closing`)
|
||||
stream.end(() => {
|
||||
checkBun(instance, virtualPath, dirname(fsPath))
|
||||
checkBun(instance, virtualPath, dirname(fsPath), logger)
|
||||
})
|
||||
})
|
||||
return {
|
||||
@ -351,7 +350,7 @@ export class PhFs implements FileSystem {
|
||||
}
|
||||
|
||||
async read(fileName: string, options: { start?: any } | undefined): Promise<any> {
|
||||
const { dbg, error } = this.log.create(`read`).breadcrumb({ cwd: this.cwd, fileName })
|
||||
const { dbg, error } = this.log.create(`read`).breadcrumb(this.cwd).breadcrumb(fileName)
|
||||
dbg(`read`)
|
||||
|
||||
const { fsPath, clientPath } = await this._resolvePath(fileName)
|
||||
@ -373,7 +372,7 @@ export class PhFs implements FileSystem {
|
||||
}
|
||||
|
||||
async delete(path: string) {
|
||||
const { dbg, error } = this.log.create(`delete`).breadcrumb({ cwd: this.cwd, path })
|
||||
const { dbg, error } = this.log.create(`delete`).breadcrumb(this.cwd).breadcrumb(path)
|
||||
dbg(`delete`)
|
||||
|
||||
const { fsPath, instance } = await this._resolvePath(path)
|
||||
@ -388,7 +387,7 @@ export class PhFs implements FileSystem {
|
||||
}
|
||||
|
||||
async mkdir(path: string) {
|
||||
const { dbg, error } = this.log.create(`mkdir`).breadcrumb({ cwd: this.cwd, path })
|
||||
const { dbg, error } = this.log.create(`mkdir`).breadcrumb(this.cwd).breadcrumb(path)
|
||||
dbg(`mkdir`)
|
||||
|
||||
const { fsPath } = await this._resolvePath(path)
|
||||
@ -397,7 +396,7 @@ export class PhFs implements FileSystem {
|
||||
}
|
||||
|
||||
async rename(from: string, to: string) {
|
||||
const { dbg, error } = this.log.create(`rename`).breadcrumb({ cwd: this.cwd, from, to })
|
||||
const { dbg, error } = this.log.create(`rename`).breadcrumb(this.cwd).breadcrumb(from).breadcrumb(to)
|
||||
dbg(`rename`)
|
||||
|
||||
const { fsPath: fromPath, instance } = await this._resolvePath(from)
|
||||
@ -410,7 +409,7 @@ export class PhFs implements FileSystem {
|
||||
}
|
||||
|
||||
async chmod(path: string, mode: Mode) {
|
||||
const { dbg, error } = this.log.create(`chmod`).breadcrumb({ cwd: this.cwd, path, mode })
|
||||
const { dbg, error } = this.log.create(`chmod`).breadcrumb(this.cwd).breadcrumb(path).breadcrumb(`${mode}`)
|
||||
dbg(`chmod`)
|
||||
|
||||
const { fsPath } = await this._resolvePath(path)
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
PocketBase,
|
||||
SSL_CERT,
|
||||
SSL_KEY,
|
||||
SingletonBaseConfig,
|
||||
asyncExitHook,
|
||||
logger,
|
||||
mergeConfig,
|
||||
@ -16,9 +17,9 @@ import { readFileSync } from 'fs'
|
||||
import { FtpSrv } from 'ftp-srv'
|
||||
import { PhFs } from './PhFs'
|
||||
|
||||
export type FtpConfig = { mothershipUrl: string }
|
||||
export type FtpConfig = SingletonBaseConfig & { mothershipUrl: string }
|
||||
|
||||
export const ftpService = mkSingleton((config: Partial<FtpConfig> = {}) => {
|
||||
export const ftpService = mkSingleton((config: FtpConfig) => {
|
||||
const { mothershipUrl } = mergeConfig(
|
||||
{
|
||||
mothershipUrl: MOTHERSHIP_URL(),
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
import { logger } from '@'
|
||||
import { LoggerService } from '@'
|
||||
import { MOTHERSHIP_URL, neverendingPromise, tryFetch } from '../../../../..'
|
||||
import { ftpService } from '../FtpService'
|
||||
|
||||
export async function ftp() {
|
||||
const { info } = logger()
|
||||
const logger = LoggerService().create(`cli:edge:ftp:serve`)
|
||||
const { info } = logger
|
||||
info(`Starting`)
|
||||
|
||||
await tryFetch(MOTHERSHIP_URL(`/api/health`), {})
|
||||
|
||||
await ftpService({
|
||||
mothershipUrl: MOTHERSHIP_URL(),
|
||||
logger,
|
||||
})
|
||||
|
||||
await neverendingPromise()
|
||||
await neverendingPromise(logger)
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import {
|
||||
InstanceFields,
|
||||
LoggerService,
|
||||
mkInstanceDataPath,
|
||||
MOTHERSHIP_ADMIN_PASSWORD,
|
||||
MOTHERSHIP_ADMIN_USERNAME,
|
||||
@ -18,7 +19,10 @@ export const MigrateCommand = () => {
|
||||
.option(`-i, --instance <instanceId>`, `The instance to migrate`)
|
||||
.option(`-m, --mount-point <mountPoint>`, `The mount point`, `cloud-storage`)
|
||||
.action(async (options) => {
|
||||
console.log({ options })
|
||||
const logger = LoggerService().create(`cli:edge:volume:migrate`)
|
||||
const { dbg } = logger
|
||||
dbg({ options })
|
||||
|
||||
const { instance: instanceId, mountPoint } = options
|
||||
|
||||
const pb = new PocketBase(MOTHERSHIP_URL())
|
||||
|
||||
@ -3,7 +3,7 @@ import {
|
||||
DAEMON_PORT,
|
||||
IPCIDR_LIST,
|
||||
IS_DEV,
|
||||
logger,
|
||||
LoggerService,
|
||||
MOTHERSHIP_NAME,
|
||||
MOTHERSHIP_PORT,
|
||||
neverendingPromise,
|
||||
@ -23,7 +23,8 @@ import { createIpWhitelistMiddleware } from './cidr'
|
||||
import { createVhostProxyMiddleware } from './createVhostProxyMiddleware'
|
||||
|
||||
export const firewall = async () => {
|
||||
const { dbg, error } = logger()
|
||||
const logger = LoggerService().create(`cli:firewall:serve`)
|
||||
const { dbg, error } = logger
|
||||
|
||||
const PROD_ROUTES = {
|
||||
[`${MOTHERSHIP_NAME()}.${APEX_DOMAIN()}`]: `http://localhost:${MOTHERSHIP_PORT()}`,
|
||||
@ -98,5 +99,5 @@ export const firewall = async () => {
|
||||
dbg('HTTPS server running on port 443')
|
||||
})
|
||||
|
||||
await neverendingPromise()
|
||||
await neverendingPromise(logger)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { logger } from '@'
|
||||
import { LoggerService, neverendingPromise } from '@'
|
||||
import { Command } from 'commander'
|
||||
import { mothership } from './mothership'
|
||||
|
||||
@ -11,9 +11,11 @@ export const ServeCommand = () => {
|
||||
.description(`Run the PocketHost mothership`)
|
||||
.option(`--isolate`, `Use Docker for process isolation.`, false)
|
||||
.action(async (options: Options) => {
|
||||
logger().context({ cli: 'mothership:serve' })
|
||||
console.log({ options })
|
||||
const logger = LoggerService().create(`cli:mothership:serve`)
|
||||
const { dbg } = logger
|
||||
dbg({ options })
|
||||
await mothership(options)
|
||||
await neverendingPromise(logger)
|
||||
})
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import {
|
||||
_MOTHERSHIP_APP_ROOT,
|
||||
APP_URL,
|
||||
DISCORD_ALERT_CHANNEL_URL,
|
||||
DISCORD_HEALTH_CHANNEL_URL,
|
||||
DISCORD_STREAM_CHANNEL_URL,
|
||||
DISCORD_TEST_CHANNEL_URL,
|
||||
exitHook,
|
||||
GobotService,
|
||||
IS_DEV,
|
||||
LS_WEBHOOK_SECRET,
|
||||
LoggerService,
|
||||
LS_WEBHOOK_SECRET,
|
||||
mkContainerHomePath,
|
||||
MOTHERSHIP_CLOUDFLARE_ACCOUNT_ID,
|
||||
MOTHERSHIP_CLOUDFLARE_API_TOKEN,
|
||||
MOTHERSHIP_CLOUDFLARE_ZONE_ID,
|
||||
@ -16,16 +19,16 @@ import {
|
||||
MOTHERSHIP_MIGRATIONS_DIR,
|
||||
MOTHERSHIP_PORT,
|
||||
MOTHERSHIP_SEMVER,
|
||||
MOTHERSHIP_URL,
|
||||
TEST_EMAIL,
|
||||
_MOTHERSHIP_APP_ROOT,
|
||||
mkContainerHomePath,
|
||||
tryFetch,
|
||||
} from '@'
|
||||
import { GobotOptions } from 'gobot'
|
||||
|
||||
export type MothershipConfig = {}
|
||||
|
||||
export async function mothership(cfg: MothershipConfig) {
|
||||
const logger = LoggerService().create(`Mothership`)
|
||||
const logger = LoggerService().create(`cli:mothership`)
|
||||
const { dbg, error, info, warn } = logger
|
||||
info(`Starting`)
|
||||
|
||||
@ -44,13 +47,13 @@ export async function mothership(cfg: MothershipConfig) {
|
||||
MOTHERSHIP_CLOUDFLARE_ZONE_ID: MOTHERSHIP_CLOUDFLARE_ZONE_ID(),
|
||||
MOTHERSHIP_CLOUDFLARE_ACCOUNT_ID: MOTHERSHIP_CLOUDFLARE_ACCOUNT_ID(),
|
||||
}
|
||||
dbg(env)
|
||||
dbg({ env })
|
||||
|
||||
const options: Partial<GobotOptions> = {
|
||||
version: MOTHERSHIP_SEMVER(),
|
||||
env,
|
||||
}
|
||||
dbg(`options`, options)
|
||||
dbg({ options })
|
||||
const { gobot } = GobotService()
|
||||
const bot = await gobot(`pocketbase`, options)
|
||||
|
||||
@ -71,6 +74,30 @@ export async function mothership(cfg: MothershipConfig) {
|
||||
args.push(`--dev`)
|
||||
}
|
||||
dbg({ args })
|
||||
const code = await bot.run(args, { env, cwd: _MOTHERSHIP_APP_ROOT() })
|
||||
dbg({ code })
|
||||
|
||||
bot.run(args, { env, cwd: _MOTHERSHIP_APP_ROOT() }, (proc) => {
|
||||
proc.stdout.on('data', (data) => {
|
||||
info(data.toString())
|
||||
})
|
||||
proc.stderr.on('data', (data) => {
|
||||
error(data.toString())
|
||||
})
|
||||
proc.on('close', (code, signal) => {
|
||||
error(`Pocketbase exited with code ${code} and signal ${signal}`)
|
||||
})
|
||||
proc.on('error', (err) => {
|
||||
error(`Pocketbase error: ${err}`)
|
||||
})
|
||||
proc.on('exit', (code, signal) => {
|
||||
error(`Pocketbase exited with code ${code} and signal ${signal}`)
|
||||
})
|
||||
proc.on('message', (msg) => {
|
||||
console.log(`***message`, msg)
|
||||
})
|
||||
exitHook(() => {
|
||||
proc.kill()
|
||||
})
|
||||
})
|
||||
const ready = tryFetch(MOTHERSHIP_URL(`/api/health`), { logger })
|
||||
return ready
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { logger, neverendingPromise } from '@'
|
||||
import { LoggerService, neverendingPromise } from '@'
|
||||
import { Command } from 'commander'
|
||||
import { daemon } from '../EdgeCommand/DaemonCommand/ServeCommand/daemon'
|
||||
import { firewall } from '../FirewallCommand/ServeCommand/firewall/server'
|
||||
@ -10,13 +10,17 @@ type Options = {
|
||||
|
||||
export const ServeCommand = () => {
|
||||
const cmd = new Command(`serve`).description(`Run the entire PocketHost stack`).action(async (options: Options) => {
|
||||
logger().context({ cli: 'serve' })
|
||||
const { dbg, error, info, warn } = logger()
|
||||
const logger = LoggerService().create(`cli:serve`)
|
||||
const { dbg, error, info, warn } = logger
|
||||
info(`Starting`)
|
||||
|
||||
await Promise.all([mothership(options), daemon(), firewall()])
|
||||
|
||||
await neverendingPromise()
|
||||
await mothership(options)
|
||||
dbg(`Mothership ready`)
|
||||
await daemon()
|
||||
dbg(`Daemon ready`)
|
||||
await firewall()
|
||||
dbg(`Firewall ready`)
|
||||
await neverendingPromise(logger)
|
||||
})
|
||||
return cmd
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { GobotService, ioc, RegisterEnvSettingsService, WinstonLoggerService } from '@'
|
||||
import { ConsoleLogger, DEBUG, GobotService, ioc, LogLevelName, RegisterEnvSettingsService } from '@'
|
||||
import { version } from '../../package.json'
|
||||
|
||||
export const initIoc = async () => {
|
||||
const logger = await WinstonLoggerService({})
|
||||
const logger = ConsoleLogger({ level: DEBUG() ? LogLevelName.Debug : LogLevelName.Info })
|
||||
ioc('logger', logger.context('ph_version', version))
|
||||
RegisterEnvSettingsService()
|
||||
GobotService({})
|
||||
GobotService({ logger })
|
||||
}
|
||||
|
||||
@ -14,45 +14,56 @@ export function ConsoleLogger(initialConfig: Partial<LoggerConfig> = {}): Logger
|
||||
let config: LoggerConfig = {
|
||||
level: LogLevelName.Info,
|
||||
pfx: [],
|
||||
breadcrumbs: [],
|
||||
context: {},
|
||||
...initialConfig,
|
||||
}
|
||||
|
||||
function log(level: LogLevelName, ...args: any[]) {
|
||||
function log(level: LogLevelName, args: any[]) {
|
||||
if (isLevelGte(level, config.level)) {
|
||||
const prefix = config.pfx.length > 0 ? `[${config.pfx.join(':')}] ` : ''
|
||||
CONSOLE_METHODS[level](`${prefix}${level.toUpperCase()}:`, ...args)
|
||||
}
|
||||
}
|
||||
|
||||
const breadcrumbs: string[] = []
|
||||
const context: Record<string, string | number | undefined> = {}
|
||||
const withBreadcrumbs = (args: any[]) => {
|
||||
return [breadcrumbs.map((b) => `[${b}]`).join(' '), ...args]
|
||||
}
|
||||
|
||||
const logger: Logger = {
|
||||
raw(...args: any[]) {
|
||||
log(LogLevelName.Raw, ...args)
|
||||
log(LogLevelName.Raw, withBreadcrumbs(args))
|
||||
},
|
||||
trace(...args: any[]) {
|
||||
log(LogLevelName.Trace, ...args)
|
||||
log(LogLevelName.Trace, withBreadcrumbs(args))
|
||||
},
|
||||
debug(...args: any[]) {
|
||||
log(LogLevelName.Debug, ...args)
|
||||
log(LogLevelName.Debug, withBreadcrumbs(args))
|
||||
},
|
||||
dbg(...args: any[]) {
|
||||
logger.debug(...args)
|
||||
},
|
||||
info(...args: any[]) {
|
||||
log(LogLevelName.Info, ...args)
|
||||
log(LogLevelName.Info, withBreadcrumbs(args))
|
||||
},
|
||||
warn(...args: any[]) {
|
||||
log(LogLevelName.Warn, ...args)
|
||||
log(LogLevelName.Warn, withBreadcrumbs(args))
|
||||
},
|
||||
error(...args: any[]) {
|
||||
log(LogLevelName.Error, ...args)
|
||||
log(LogLevelName.Error, withBreadcrumbs(args))
|
||||
},
|
||||
criticalError(...args: any[]) {
|
||||
logger.error('CRITICAL:', ...args)
|
||||
logger.error('CRITICAL:', withBreadcrumbs(args))
|
||||
},
|
||||
create(name: string, configOverride?: Partial<LoggerConfig>): Logger {
|
||||
const newConfig = {
|
||||
...config,
|
||||
breadcrumbs: [...breadcrumbs, name],
|
||||
context: { ...context },
|
||||
pfx: [...config.pfx, name],
|
||||
logger: logger,
|
||||
...configOverride,
|
||||
}
|
||||
return ConsoleLogger(newConfig)
|
||||
@ -60,16 +71,22 @@ export function ConsoleLogger(initialConfig: Partial<LoggerConfig> = {}): Logger
|
||||
child(name: string): Logger {
|
||||
return logger.create(name)
|
||||
},
|
||||
breadcrumb(s: object): Logger {
|
||||
console.log('Breadcrumb:', s)
|
||||
breadcrumb(s: string): Logger {
|
||||
breadcrumbs.push(s)
|
||||
return logger
|
||||
},
|
||||
context(name: string | object, value?: string | number): Logger {
|
||||
console.log('Context:', name, value)
|
||||
if (typeof name === `object`) {
|
||||
Object.entries(name).forEach(([k, v]) => {
|
||||
context[k] = v
|
||||
})
|
||||
} else {
|
||||
context[name] = value
|
||||
}
|
||||
return logger
|
||||
},
|
||||
abort(...args: any[]): never {
|
||||
log(LogLevelName.Abort, ...args)
|
||||
log(LogLevelName.Abort, withBreadcrumbs(args))
|
||||
process.exit(1)
|
||||
},
|
||||
shutdown() {
|
||||
|
||||
@ -4,6 +4,8 @@ import { ConsoleLogger } from './ConsoleLogger'
|
||||
export type LoggerConfig = {
|
||||
level: LogLevelName
|
||||
pfx: string[]
|
||||
breadcrumbs: string[]
|
||||
context: Record<string, LoggerContextValue>
|
||||
}
|
||||
|
||||
export const isLevelLte = (a: LogLevelName, b: LogLevelName) => {
|
||||
@ -48,6 +50,8 @@ export const LogLevels = {
|
||||
[LogLevelName.Abort]: 6,
|
||||
} as const
|
||||
|
||||
export type LoggerContextValue = string | number | undefined
|
||||
|
||||
export type Logger = {
|
||||
raw: (...args: any[]) => void
|
||||
dbg: (...args: any[]) => void
|
||||
@ -59,8 +63,8 @@ export type Logger = {
|
||||
child: (name: string) => Logger
|
||||
trace: (...args: any[]) => void
|
||||
debug: (...args: any[]) => void
|
||||
breadcrumb: (s: object) => Logger
|
||||
context: (name: string | object, value?: string | number) => Logger
|
||||
breadcrumb: (s: string) => Logger
|
||||
context: (name: string | object, value?: LoggerContextValue) => Logger
|
||||
abort: (...args: any[]) => never
|
||||
shutdown: () => void
|
||||
setLevel: (level: LogLevelName) => void
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import { Logger } from './Logger'
|
||||
|
||||
export type SingletonApi = Object
|
||||
|
||||
export type SingletonBaseConfig = {}
|
||||
export type SingletonBaseConfig = {
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export function mkSingleton<TConfig extends SingletonBaseConfig, TInstance extends SingletonApi>(
|
||||
factory: (config: TConfig) => TInstance
|
||||
|
||||
@ -19,6 +19,14 @@ export type InstanceSecretCollection = {
|
||||
[name: InstanceSecretKey]: InstanceSecretValue
|
||||
}
|
||||
|
||||
export type InstanceWebhookEndpoint = string
|
||||
export type InstanceWebhookValue = string
|
||||
export type InstanceWebhookCollection = InstanceWebhookItem[]
|
||||
export type InstanceWebhookItem = {
|
||||
endpoint: InstanceWebhookEndpoint
|
||||
value: InstanceWebhookValue
|
||||
}
|
||||
|
||||
export type InstanceFields<TExtra = {}> = BaseFields & {
|
||||
region: string
|
||||
subdomain: Subdomain
|
||||
@ -26,6 +34,7 @@ export type InstanceFields<TExtra = {}> = BaseFields & {
|
||||
status: InstanceStatus
|
||||
version: VersionId
|
||||
secrets: InstanceSecretCollection | null
|
||||
webhooks: InstanceWebhookCollection | null
|
||||
power: boolean
|
||||
suspension: string
|
||||
syncAdmin: boolean
|
||||
|
||||
@ -3,7 +3,9 @@ import { InstanceFields, InstanceId } from '..'
|
||||
|
||||
export type UpdateInstancePayload = {
|
||||
id: InstanceId
|
||||
fields: Partial<Pick<InstanceFields, 'power' | 'secrets' | 'subdomain' | 'syncAdmin' | 'version' | 'dev' | 'cname'>>
|
||||
fields: Partial<
|
||||
Pick<InstanceFields, 'power' | 'secrets' | 'webhooks' | 'subdomain' | 'syncAdmin' | 'version' | 'dev' | 'cname'>
|
||||
>
|
||||
}
|
||||
|
||||
export const SECRET_KEY_REGEX = /^[A-Z][A-Z0-9_]*$/
|
||||
@ -37,6 +39,18 @@ export const UpdateInstancePayloadSchema: JSONSchemaType<UpdateInstancePayload>
|
||||
},
|
||||
required: [],
|
||||
},
|
||||
webhooks: {
|
||||
type: 'array',
|
||||
nullable: true,
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
endpoint: { type: 'string' },
|
||||
value: { type: 'string' },
|
||||
},
|
||||
required: ['endpoint', 'value'],
|
||||
},
|
||||
},
|
||||
dev: { type: 'boolean', nullable: true },
|
||||
cname: { type: 'string', nullable: true },
|
||||
},
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
import TransportStream from 'winston-transport'
|
||||
import { discordAlert } from '..'
|
||||
|
||||
export type DiscordTransportType = {
|
||||
webhookUrl: string
|
||||
} & TransportStream.TransportStreamOptions
|
||||
|
||||
export class DiscordTransport extends TransportStream {
|
||||
private url: string
|
||||
constructor(opts: DiscordTransportType) {
|
||||
super(opts)
|
||||
this.url = opts.webhookUrl
|
||||
}
|
||||
|
||||
log(info: any, callback: any) {
|
||||
discordAlert(info)
|
||||
callback()
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { logger } from '@'
|
||||
import { Logger } from '@'
|
||||
import exitHook, { asyncExitHook as _, gracefulExit as __ } from 'exit-hook'
|
||||
|
||||
export const asyncExitHook = (cb: () => Promise<any>) => _(cb, { wait: 5000 })
|
||||
@ -11,7 +11,7 @@ export const gracefulExit = async (signal?: number) => {
|
||||
}
|
||||
export { exitHook }
|
||||
|
||||
export const neverendingPromise = () =>
|
||||
export const neverendingPromise = (logger: Logger) =>
|
||||
new Promise((resolve) => {
|
||||
logger().dbg('Neverending promise')
|
||||
logger.dbg('Neverending promise')
|
||||
})
|
||||
|
||||
@ -10,4 +10,3 @@ export * from './process'
|
||||
export * from './Settings'
|
||||
export * from './smartFetch'
|
||||
export * from './tryFetch'
|
||||
export * from './winston'
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { LoggerService } from '@'
|
||||
import { Logger, LoggerService } from '@'
|
||||
import fetch, { Response } from 'node-fetch'
|
||||
|
||||
export const TRYFETCH_RETRY_MS = 50
|
||||
@ -8,6 +8,7 @@ export type TryFetchConfig = {
|
||||
preflight: () => Promise<boolean>
|
||||
retryMs: number
|
||||
timeoutMs: number
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
/**
|
||||
@ -23,14 +24,14 @@ export type TryFetchConfig = {
|
||||
* Note: tryFetch exits ONLY on success or a rejected preflight.
|
||||
*/
|
||||
export const tryFetch = async (url: string, config?: Partial<TryFetchConfig>) => {
|
||||
const { preflight, retryMs, timeoutMs }: TryFetchConfig = {
|
||||
const { preflight, retryMs, timeoutMs, logger }: TryFetchConfig = {
|
||||
preflight: async () => true,
|
||||
retryMs: TRYFETCH_RETRY_MS,
|
||||
timeoutMs: TRYFETCH_TIMEOUT_MS,
|
||||
logger: config?.logger ?? LoggerService(),
|
||||
...config,
|
||||
}
|
||||
const logger = LoggerService().create(`tryFetch`).breadcrumb({ url })
|
||||
const { dbg } = logger
|
||||
const { dbg } = logger.create(`tryFetch`).breadcrumb(url)
|
||||
return new Promise<Response>((resolve, reject) => {
|
||||
const again = () => setTimeout(_real_tryFetch, retryMs)
|
||||
const _real_tryFetch = async () => {
|
||||
|
||||
@ -1,143 +0,0 @@
|
||||
import { asyncExitHook, DEBUG, DISCORD_ALERT_CHANNEL_URL, Logger, mkSingleton } from '@'
|
||||
import { inspect } from 'node:util'
|
||||
import winston from 'winston'
|
||||
import { DiscordTransport } from './DiscordTransport'
|
||||
|
||||
const format = winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.printf(({ level, message, timestamp, ...meta }) => {
|
||||
const final: string[] = []
|
||||
// @ts-expect-error
|
||||
;[...message, meta].forEach((m: string) => {
|
||||
if (typeof m === 'string' && !!m.match(/\n/)) {
|
||||
final.push(...m.split(/\n/))
|
||||
} else if (typeof m === 'object') {
|
||||
// Filter out Symbol properties and inspect the object
|
||||
const filtered = Object.fromEntries(Object.entries(m).filter(([key]) => typeof key === 'string'))
|
||||
final.push(
|
||||
inspect(filtered, {
|
||||
depth: null,
|
||||
compact: true,
|
||||
breakLength: Infinity,
|
||||
})
|
||||
)
|
||||
} else {
|
||||
final.push(m)
|
||||
}
|
||||
})
|
||||
return `${level}: ${final.join(' ')}`
|
||||
})
|
||||
)
|
||||
|
||||
export const WinstonLoggerService = mkSingleton<{}, Logger>(() => {
|
||||
const logger = winston.createLogger({
|
||||
format: winston.format.json(),
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
level: DEBUG() ? 'debug' : 'info',
|
||||
format,
|
||||
}),
|
||||
new winston.transports.File({
|
||||
filename: 'error.log',
|
||||
level: 'error',
|
||||
maxsize: 100 * 1024 * 1024,
|
||||
maxFiles: 10,
|
||||
tailable: true,
|
||||
}),
|
||||
new winston.transports.File({
|
||||
filename: 'debug.log',
|
||||
level: 'debug',
|
||||
maxsize: 100 * 1024 * 1024,
|
||||
maxFiles: 10,
|
||||
tailable: true,
|
||||
}),
|
||||
],
|
||||
rejectionHandlers: [
|
||||
new winston.transports.Console({
|
||||
level: 'error',
|
||||
format,
|
||||
}),
|
||||
new winston.transports.File({
|
||||
filename: 'rejections.log',
|
||||
maxsize: 100 * 1024 * 1024,
|
||||
maxFiles: 10,
|
||||
tailable: true,
|
||||
}),
|
||||
],
|
||||
exceptionHandlers: [
|
||||
new winston.transports.Console({
|
||||
level: 'error',
|
||||
format,
|
||||
}),
|
||||
new winston.transports.File({
|
||||
filename: 'exceptions.log',
|
||||
maxsize: 100 * 1024 * 1024,
|
||||
maxFiles: 10,
|
||||
tailable: true,
|
||||
}),
|
||||
],
|
||||
defaultMeta: {},
|
||||
})
|
||||
logger.exitOnError = true
|
||||
|
||||
asyncExitHook(async () => {
|
||||
console.log('Closing Winston logger outside')
|
||||
return new Promise<void>((resolve) => {
|
||||
console.log('Closing Winston logger inside promise')
|
||||
setTimeout(() => {
|
||||
console.log('Closing Winston logger inside timeout')
|
||||
logger.close()
|
||||
resolve()
|
||||
}, 2000)
|
||||
})
|
||||
})
|
||||
|
||||
{
|
||||
const url = DISCORD_ALERT_CHANNEL_URL()
|
||||
if (url) {
|
||||
logger.add(new DiscordTransport({ level: 'error', webhookUrl: url }))
|
||||
}
|
||||
}
|
||||
|
||||
const createApi = (logger: winston.Logger): Logger => {
|
||||
const api: Logger = {
|
||||
create: (name: string) => {
|
||||
return createApi(logger.child({ ...logger.defaultMeta, name }))
|
||||
},
|
||||
raw: (...args: any[]) => logger.silly(args),
|
||||
dbg: (...args: any[]) => logger.debug(args),
|
||||
warn: (...args: any[]) => logger.warn(args),
|
||||
info: (...args: any[]) => logger.info(args),
|
||||
error: (...args: any[]) => logger.error(args),
|
||||
criticalError: (...args: any[]) => logger.error(args),
|
||||
setLevel: (level) => {},
|
||||
trace: (...args: any[]) => logger.silly(args),
|
||||
debug: (...args: any[]) => logger.debug(args),
|
||||
breadcrumb: (s) => {
|
||||
Object.assign(logger.defaultMeta, s)
|
||||
return api
|
||||
},
|
||||
context: (name: string | object, value?: string | number) => {
|
||||
if (typeof name === 'string') {
|
||||
if (value !== undefined) {
|
||||
logger.defaultMeta[name] = value
|
||||
} else {
|
||||
delete logger.defaultMeta[name]
|
||||
}
|
||||
} else {
|
||||
Object.assign(logger.defaultMeta, name)
|
||||
}
|
||||
return api
|
||||
},
|
||||
shutdown: () => {},
|
||||
child: (name) => api.create(name),
|
||||
abort: (...args) => {
|
||||
logger.error(args)
|
||||
process.exit(1)
|
||||
},
|
||||
}
|
||||
return api
|
||||
}
|
||||
|
||||
return createApi(logger)
|
||||
})
|
||||
@ -1,4 +1,4 @@
|
||||
import { ensureInstanceDirectoryStructure, logger, LoggerService, mkInstanceDataPath, stringify } from '@'
|
||||
import { ensureInstanceDirectoryStructure, Logger, mkInstanceDataPath, stringify } from '@'
|
||||
import Bottleneck from 'bottleneck'
|
||||
import { existsSync } from 'fs'
|
||||
import { appendFile, cp, stat, truncate } from 'fs/promises'
|
||||
@ -74,8 +74,8 @@ const MultiChannelLimiter = () => {
|
||||
|
||||
const limiter = MultiChannelLimiter()
|
||||
|
||||
export function InstanceLogWriter(instanceId: string, volume: string, target: string) {
|
||||
const lgr = logger().create(`InstanceLogWriter`).breadcrumb({ instanceId, target })
|
||||
export function InstanceLogWriter(instanceId: string, volume: string, target: string, logger: Logger) {
|
||||
const lgr = logger.create(`InstanceLogWriter`).breadcrumb(`${instanceId}-${target}`)
|
||||
const { dbg, info, error, warn } = lgr
|
||||
|
||||
ensureInstanceDirectoryStructure(instanceId, volume, lgr)
|
||||
@ -124,9 +124,8 @@ export function InstanceLogWriter(instanceId: string, volume: string, target: st
|
||||
return api
|
||||
}
|
||||
|
||||
export function InstanceLogReader(instanceId: string, volume: string, target: string) {
|
||||
const logger = LoggerService().create(instanceId).breadcrumb({ target })
|
||||
const { dbg, info, error, warn } = logger
|
||||
export function InstanceLogReader(instanceId: string, volume: string, target: string, logger: Logger) {
|
||||
const { dbg, info, error, warn } = logger.create(`InstanceLogReader`).breadcrumb(`${instanceId}-${target}`)
|
||||
|
||||
ensureInstanceDirectoryStructure(instanceId, volume, logger)
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ export type InstanceServiceConfig = SingletonBaseConfig & {
|
||||
|
||||
export type InstanceServiceApi = AsyncReturnType<typeof instanceService>
|
||||
export const instanceService = mkSingleton(async (config: InstanceServiceConfig) => {
|
||||
const instanceServiceLogger = LoggerService().create('InstanceService')
|
||||
const instanceServiceLogger = (config.logger ?? LoggerService()).create('InstanceService')
|
||||
const { dbg, raw, error, warn } = instanceServiceLogger
|
||||
const { client } = await MothershipAdminClientService()
|
||||
|
||||
@ -62,7 +62,7 @@ export const instanceService = mkSingleton(async (config: InstanceServiceConfig)
|
||||
const { id, subdomain, version } = instance
|
||||
const systemInstanceLogger = instanceServiceLogger.create(`${subdomain}:${id}:${version}`)
|
||||
const { dbg, warn, error, info, trace } = systemInstanceLogger
|
||||
const userInstanceLogger = InstanceLogWriter(instance.id, instance.volume, `exec`)
|
||||
const userInstanceLogger = InstanceLogWriter(instance.id, instance.volume, `exec`, systemInstanceLogger)
|
||||
|
||||
shutdownManager.push(() => {
|
||||
dbg(`Shutting down`)
|
||||
@ -140,6 +140,7 @@ export const instanceService = mkSingleton(async (config: InstanceServiceConfig)
|
||||
PH_INSTANCE_URL: mkInstanceUrl(instance),
|
||||
},
|
||||
version,
|
||||
logger: systemInstanceLogger,
|
||||
}
|
||||
|
||||
/** Add admin sync info if enabled */
|
||||
@ -183,6 +184,7 @@ export const instanceService = mkSingleton(async (config: InstanceServiceConfig)
|
||||
if (stopped()) throw new Error(`Container stopped ${id}`)
|
||||
return started()
|
||||
},
|
||||
logger: systemInstanceLogger,
|
||||
})
|
||||
|
||||
/** Idle check */
|
||||
@ -234,7 +236,7 @@ export const instanceService = mkSingleton(async (config: InstanceServiceConfig)
|
||||
const mirror = await MothershipMirrorService()
|
||||
|
||||
;(await proxyService()).use(async (req, res, next) => {
|
||||
const logger = LoggerService().create(`InstanceRequest`)
|
||||
const logger = (config.logger ?? LoggerService()).create(`InstanceRequest`)
|
||||
|
||||
const { dbg } = logger
|
||||
|
||||
|
||||
@ -11,32 +11,42 @@ import {
|
||||
import { forEach } from '@s-libs/micro-dash'
|
||||
|
||||
export const mkInstanceCache = (client: PocketBase) => {
|
||||
const { dbg } = LoggerService().create(`InstanceCache`)
|
||||
const { dbg, error } = LoggerService().create(`InstanceCache`)
|
||||
|
||||
const cache: { [_: InstanceId]: InstanceFields_WithUser | undefined } = {}
|
||||
const byUid: {
|
||||
[_: UserId]: { [_: InstanceId]: InstanceFields_WithUser }
|
||||
} = {}
|
||||
|
||||
client.collection(`users`).subscribe<UserFields>(`*`, (e) => {
|
||||
const { action, record } = e
|
||||
if ([`create`, `update`].includes(action)) {
|
||||
dbg({ action, record })
|
||||
updateUser(record)
|
||||
}
|
||||
})
|
||||
|
||||
client.collection(INSTANCE_COLLECTION).subscribe<InstanceFields_WithUser>(
|
||||
`*`,
|
||||
(e) => {
|
||||
client
|
||||
.collection(`users`)
|
||||
.subscribe<UserFields>(`*`, (e) => {
|
||||
const { action, record } = e
|
||||
if ([`create`, `update`].includes(action)) {
|
||||
setItem(record)
|
||||
dbg({ action, record })
|
||||
updateUser(record)
|
||||
}
|
||||
},
|
||||
{ expand: 'uid' }
|
||||
)
|
||||
})
|
||||
.catch((e) => {
|
||||
error(e)
|
||||
})
|
||||
|
||||
client
|
||||
.collection(INSTANCE_COLLECTION)
|
||||
.subscribe<InstanceFields_WithUser>(
|
||||
`*`,
|
||||
(e) => {
|
||||
const { action, record } = e
|
||||
if ([`create`, `update`].includes(action)) {
|
||||
setItem(record)
|
||||
dbg({ action, record })
|
||||
}
|
||||
},
|
||||
{ expand: 'uid' }
|
||||
)
|
||||
.catch((e) => {
|
||||
error(e)
|
||||
})
|
||||
|
||||
function blankItem(host: string) {
|
||||
cache[host] = undefined
|
||||
|
||||
@ -2,7 +2,7 @@ import {
|
||||
GetUserTokenPayload,
|
||||
GetUserTokenPayloadSchema,
|
||||
GetUserTokenResult,
|
||||
LoggerService,
|
||||
Logger,
|
||||
PocketBase,
|
||||
RestCommands,
|
||||
RestMethods,
|
||||
@ -14,8 +14,8 @@ import { createInstanceMixin } from './InstanceMIxin'
|
||||
|
||||
export type PocketbaseClientApi = ReturnType<typeof createAdminPbClient>
|
||||
|
||||
export const createAdminPbClient = (url: string) => {
|
||||
const _clientLogger = LoggerService().create('PbClient')
|
||||
export const createAdminPbClient = (url: string, logger: Logger) => {
|
||||
const _clientLogger = logger.create('PbClient')
|
||||
const { info } = _clientLogger
|
||||
|
||||
info(`Initializing client: ${url}`)
|
||||
|
||||
@ -5,15 +5,17 @@ import {
|
||||
MOTHERSHIP_ADMIN_USERNAME,
|
||||
MOTHERSHIP_URL,
|
||||
PocketBase,
|
||||
SingletonBaseConfig,
|
||||
mergeConfig,
|
||||
mkSingleton,
|
||||
} from '@'
|
||||
import { createAdminPbClient } from './createAdminPbClient'
|
||||
|
||||
export type ClientServiceConfig = {
|
||||
export type ClientServiceConfig = SingletonBaseConfig & {
|
||||
url: string
|
||||
username: string
|
||||
password: string
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export type MixinContext = {
|
||||
@ -21,18 +23,18 @@ export type MixinContext = {
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export const MothershipAdminClientService = mkSingleton(async (cfg: Partial<ClientServiceConfig> = {}) => {
|
||||
const { url, username, password } = mergeConfig<ClientServiceConfig>(
|
||||
export const MothershipAdminClientService = mkSingleton(async (cfg: ClientServiceConfig) => {
|
||||
const { url, username, password, logger } = mergeConfig<ClientServiceConfig>(
|
||||
{
|
||||
url: MOTHERSHIP_URL(),
|
||||
username: MOTHERSHIP_ADMIN_USERNAME(),
|
||||
password: MOTHERSHIP_ADMIN_PASSWORD(),
|
||||
logger: LoggerService(),
|
||||
},
|
||||
cfg
|
||||
)
|
||||
const _clientLogger = LoggerService().create(`client singleton`)
|
||||
const { dbg, error } = _clientLogger
|
||||
const client = createAdminPbClient(url)
|
||||
const { dbg, error } = logger.create(`MothershipAdminClientService`)
|
||||
const client = createAdminPbClient(url, logger)
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
|
||||
@ -16,7 +16,7 @@ export type MothershipMirrorServiceConfig = SingletonBaseConfig & {
|
||||
}
|
||||
|
||||
export const MothershipMirrorService = mkSingleton(async (config: MothershipMirrorServiceConfig) => {
|
||||
const { dbg, error } = LoggerService().create(`MothershipMirrorService`)
|
||||
const { dbg, error } = (config.logger ?? LoggerService()).create(`MothershipMirrorService`)
|
||||
|
||||
const client = config.client
|
||||
|
||||
@ -117,6 +117,7 @@ export const MothershipMirrorService = mkSingleton(async (config: MothershipMirr
|
||||
upsertInstance(instance)
|
||||
})
|
||||
})
|
||||
.catch(error)
|
||||
const usersPromise = client
|
||||
.collection(`users`)
|
||||
.getFullList<UserFields>()
|
||||
@ -126,6 +127,7 @@ export const MothershipMirrorService = mkSingleton(async (config: MothershipMirr
|
||||
upsertUser(user)
|
||||
})
|
||||
})
|
||||
.catch(error)
|
||||
await Promise.all([instancesPromise, usersPromise])
|
||||
}
|
||||
await init().catch(error)
|
||||
|
||||
@ -2,6 +2,7 @@ import {
|
||||
APEX_DOMAIN,
|
||||
GobotService,
|
||||
InstanceLogWriter,
|
||||
Logger,
|
||||
LoggerService,
|
||||
SingletonBaseConfig,
|
||||
asyncExitHook,
|
||||
@ -30,6 +31,7 @@ export type SpawnConfig = {
|
||||
stdout?: MemoryStream
|
||||
stderr?: MemoryStream
|
||||
dev?: boolean
|
||||
logger: Logger
|
||||
}
|
||||
export type PocketbaseServiceApi = AsyncReturnType<typeof createPocketbaseService>
|
||||
|
||||
@ -46,7 +48,7 @@ export type PocketbaseProcess = {
|
||||
export const DOCKER_INSTANCE_IMAGE_NAME = `benallfree/pockethost-instance`
|
||||
|
||||
export const createPocketbaseService = async (config: PocketbaseServiceConfig) => {
|
||||
const _serviceLogger = LoggerService().create('PocketbaseService')
|
||||
const _serviceLogger = (config.logger ?? LoggerService()).create('PocketbaseService')
|
||||
const { dbg, error, warn, abort } = _serviceLogger
|
||||
|
||||
const { gobot } = GobotService()
|
||||
@ -58,7 +60,7 @@ export const createPocketbaseService = async (config: PocketbaseServiceConfig) =
|
||||
|
||||
const _spawn = async (cfg: SpawnConfig) => {
|
||||
const cm = createCleanupManager()
|
||||
const logger = LoggerService().create('spawn')
|
||||
const logger = (cfg.logger ?? config.logger ?? LoggerService()).create('spawn')
|
||||
const { dbg, info, warn, error } = logger
|
||||
|
||||
const _cfg: Required<SpawnConfig> = {
|
||||
@ -72,8 +74,8 @@ export const createPocketbaseService = async (config: PocketbaseServiceConfig) =
|
||||
}
|
||||
const { version, subdomain, instanceId, volume, extraBinds, env, stderr, stdout, dev } = _cfg
|
||||
|
||||
logger.breadcrumb({ subdomain, instanceId })
|
||||
const iLogger = InstanceLogWriter(instanceId, volume, 'exec')
|
||||
logger.breadcrumb(`${subdomain}-${instanceId}`)
|
||||
const iLogger = InstanceLogWriter(instanceId, volume, 'exec', logger)
|
||||
|
||||
const _version = version || maxVersion // If _version is blank, we use the max version available
|
||||
const realVersion = await bot.maxSatisfyingVersion(_version)
|
||||
@ -260,7 +262,7 @@ export const createPocketbaseService = async (config: PocketbaseServiceConfig) =
|
||||
})
|
||||
|
||||
const url = mkInternalUrl(container.portBinding)
|
||||
logger.breadcrumb({ url })
|
||||
logger.breadcrumb(url)
|
||||
dbg(`Making exit hook for ${url}`)
|
||||
const unsub = asyncExitHook(async () => {
|
||||
await api.kill()
|
||||
|
||||
@ -60,7 +60,7 @@ export const realtimeLog = mkSingleton(async (config: RealtimeLogConfig) => {
|
||||
dbg(`Instance is `, instance)
|
||||
|
||||
/** Get a database connection */
|
||||
const instanceLogger = InstanceLogReader(instance.id, instance.volume, `exec`)
|
||||
const instanceLogger = InstanceLogReader(instance.id, instance.volume, `exec`, logger)
|
||||
|
||||
/** Start the stream */
|
||||
res.writeHead(200, {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user