mirror of
https://github.com/pockethost/pockethost.git
synced 2025-03-30 15:08:30 +00:00
chore: log context update
This commit is contained in:
parent
ac5948be40
commit
56aff5db0a
@ -21,6 +21,7 @@ export const createWatchHelper = (config: WatchHelperConfig) => {
|
||||
|
||||
const watchById = safeCatch(
|
||||
`watchById`,
|
||||
logger(),
|
||||
async <TRec>(
|
||||
collectionName: string,
|
||||
id: RecordId,
|
||||
@ -93,6 +94,7 @@ export const createWatchHelper = (config: WatchHelperConfig) => {
|
||||
|
||||
const watchAllById = safeCatch(
|
||||
`watchAllById`,
|
||||
logger(),
|
||||
async <TRec extends BaseFields>(
|
||||
collectionName: string,
|
||||
idName: keyof TRec,
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { ClientResponseError } from 'pocketbase'
|
||||
import { logger } from './Logger'
|
||||
import { Logger } from './Logger'
|
||||
|
||||
let c = 0
|
||||
export const safeCatch = <TIn extends any[], TOut>(
|
||||
name: string,
|
||||
logger: Logger,
|
||||
cb: (...args: TIn) => Promise<TOut>,
|
||||
timeoutMs = 5000
|
||||
) => {
|
||||
@ -11,7 +12,7 @@ export const safeCatch = <TIn extends any[], TOut>(
|
||||
const _c = c++
|
||||
const uuid = `${name}:${_c}`
|
||||
const pfx = `safeCatch:${uuid}`
|
||||
const { raw, error, warn, dbg } = logger().create(pfx)
|
||||
const { raw, error, warn, dbg } = logger.create(pfx)
|
||||
raw(`args`, args)
|
||||
const tid = setTimeout(() => {
|
||||
error(`timeout ${timeoutMs}ms waiting for ${pfx}`)
|
||||
|
@ -16,17 +16,18 @@ import {
|
||||
rpcService,
|
||||
sqliteService,
|
||||
} from '$services'
|
||||
import { logger } from '@pockethost/common'
|
||||
import { logger as loggerService } from '@pockethost/common'
|
||||
import { exec } from 'child_process'
|
||||
import { centralDbService } from './services/CentralDbService'
|
||||
import { instanceLoggerService } from './services/InstanceLoggerService'
|
||||
|
||||
logger({ debug: DEBUG, trace: TRACE, errorTrace: !DEBUG })
|
||||
loggerService({ debug: DEBUG, trace: TRACE, errorTrace: !DEBUG })
|
||||
|
||||
// npm install eventsource --save
|
||||
global.EventSource = require('eventsource')
|
||||
;(async () => {
|
||||
const { dbg, error, info, warn } = logger().create(`server.ts`)
|
||||
const logger = loggerService().create(`server.ts`)
|
||||
const { dbg, error, info, warn } = logger
|
||||
info(`Starting`)
|
||||
|
||||
/**
|
||||
@ -45,6 +46,7 @@ global.EventSource = require('eventsource')
|
||||
const pbService = await pocketbase({
|
||||
cachePath: PH_BIN_CACHE,
|
||||
checkIntervalMs: 1000 * 5 * 60,
|
||||
logger,
|
||||
})
|
||||
|
||||
/**
|
||||
@ -73,18 +75,18 @@ global.EventSource = require('eventsource')
|
||||
/**
|
||||
* Launch services
|
||||
*/
|
||||
await clientService(url)
|
||||
ftpService({})
|
||||
await rpcService({})
|
||||
await clientService({ url, logger })
|
||||
ftpService({ logger })
|
||||
await rpcService({ logger })
|
||||
await proxyService({
|
||||
logger,
|
||||
coreInternalUrl: url,
|
||||
})
|
||||
await instanceLoggerService({})
|
||||
await sqliteService({})
|
||||
await realtimeLog({})
|
||||
await instanceService({})
|
||||
await centralDbService({})
|
||||
await backupService({})
|
||||
await instanceLoggerService({ logger })
|
||||
await sqliteService({ logger })
|
||||
await realtimeLog({ logger })
|
||||
await instanceService({ logger })
|
||||
await centralDbService({ logger })
|
||||
|
||||
info(`Hooking into process exit event`)
|
||||
|
||||
|
@ -1,14 +1,19 @@
|
||||
import { PUBLIC_APP_DB } from '$constants'
|
||||
import { logger, mkSingleton } from '@pockethost/common'
|
||||
import { mkSingleton, SingletonBaseConfig } from '@pockethost/common'
|
||||
import { proxyService } from './ProxyService'
|
||||
|
||||
export const centralDbService = mkSingleton(async () => {
|
||||
const { dbg } = logger().create(`centralDbService`)
|
||||
export type CentralDbServiceConfig = SingletonBaseConfig
|
||||
|
||||
export const centralDbService = mkSingleton(
|
||||
async (config: CentralDbServiceConfig) => {
|
||||
const { logger } = config
|
||||
const { dbg } = logger.create(`centralDbService`)
|
||||
|
||||
;(await proxyService()).use(
|
||||
PUBLIC_APP_DB,
|
||||
['/api(/*)', '/_(/*)', '/'],
|
||||
(req, res, meta) => {
|
||||
(req, res, meta, logger) => {
|
||||
const { dbg } = logger
|
||||
const { subdomain, coreInternalUrl, proxy } = meta
|
||||
|
||||
if (subdomain !== PUBLIC_APP_DB) return
|
||||
@ -25,4 +30,5 @@ export const centralDbService = mkSingleton(async () => {
|
||||
return {
|
||||
shutdown() {},
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
@ -7,12 +7,12 @@ import {
|
||||
SSL_KEY,
|
||||
} from '$constants'
|
||||
import { clientService, createPbClient } from '$services'
|
||||
import { logger, mkSingleton } from '@pockethost/common'
|
||||
import { mkSingleton, SingletonBaseConfig } from '@pockethost/common'
|
||||
import { readFileSync } from 'fs'
|
||||
import { FtpSrv } from 'ftp-srv'
|
||||
import { PhFs } from './PhFs'
|
||||
|
||||
export type FtpConfig = {}
|
||||
export type FtpConfig = SingletonBaseConfig & {}
|
||||
|
||||
export enum FolderNames {
|
||||
PbData = 'pb_data',
|
||||
@ -49,13 +49,14 @@ const tls = {
|
||||
}
|
||||
|
||||
export const ftpService = mkSingleton((config: FtpConfig) => {
|
||||
const log = logger().create('FtpService')
|
||||
const { dbg, info } = log
|
||||
const { logger } = config
|
||||
const _ftpServiceLogger = logger.create('FtpService')
|
||||
const { dbg, info } = _ftpServiceLogger
|
||||
|
||||
const ftpServer = new FtpSrv({
|
||||
url: 'ftp://0.0.0.0:' + PH_FTP_PORT,
|
||||
anonymous: false,
|
||||
log: log.create(`ftpServer`, { errorTrace: false }),
|
||||
log: _ftpServiceLogger.create(`ftpServer`, { errorTrace: false }),
|
||||
tls,
|
||||
pasv_url: PH_FTP_PASV_IP,
|
||||
pasv_max: PH_FTP_PASV_PORT_MAX,
|
||||
@ -66,13 +67,13 @@ export const ftpService = mkSingleton((config: FtpConfig) => {
|
||||
'login',
|
||||
async ({ connection, username, password }, resolve, reject) => {
|
||||
const url = (await clientService()).client.url
|
||||
const client = createPbClient(url)
|
||||
const client = createPbClient(url, _ftpServiceLogger)
|
||||
try {
|
||||
await client.client
|
||||
.collection('users')
|
||||
.authWithPassword(username, password)
|
||||
dbg(`Logged in`)
|
||||
const fs = new PhFs(connection, client)
|
||||
const fs = new PhFs(connection, client, _ftpServiceLogger)
|
||||
resolve({ fs })
|
||||
} catch (e) {
|
||||
reject(new Error(`Invalid username or password`))
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { DAEMON_PB_DATA_DIR } from '$constants'
|
||||
import { Logger, logger } from '@pockethost/common'
|
||||
import { Logger } from '@pockethost/common'
|
||||
import { existsSync, mkdirSync } from 'fs'
|
||||
import { FileStat, FileSystem, FtpConnection } from 'ftp-srv'
|
||||
import { join } from 'path'
|
||||
@ -16,10 +16,14 @@ export class PhFs extends FileSystem {
|
||||
private log: Logger
|
||||
private client: PocketbaseClientApi
|
||||
|
||||
constructor(connection: FtpConnection, client: PocketbaseClientApi) {
|
||||
constructor(
|
||||
connection: FtpConnection,
|
||||
client: PocketbaseClientApi,
|
||||
logger: Logger
|
||||
) {
|
||||
super(connection, { root: '/', cwd: '/' })
|
||||
this.client = client
|
||||
this.log = logger().create(`PhFs`)
|
||||
this.log = logger.create(`PhFs`)
|
||||
}
|
||||
|
||||
async chdir(path?: string | undefined): Promise<string> {
|
||||
|
@ -0,0 +1,5 @@
|
||||
import { Logger } from '@pockethost/common'
|
||||
|
||||
export type DaemonContext = {
|
||||
parentLogger: Logger
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
import { SqliteChangeEvent, sqliteService } from '$services'
|
||||
import {
|
||||
InstanceLogFields,
|
||||
InstanceLogFields_Create,
|
||||
newId,
|
||||
pocketNow,
|
||||
RecordId,
|
||||
safeCatch,
|
||||
StreamNames,
|
||||
} from '@pockethost/common'
|
||||
import knex from 'knex'
|
||||
import { AsyncReturnType } from 'type-fest'
|
||||
import { DaemonContext } from './DaemonContext'
|
||||
|
||||
export type SqliteLogger = AsyncReturnType<typeof createSqliteLogger>
|
||||
export const createSqliteLogger = async (
|
||||
logDbPath: string,
|
||||
context: DaemonContext
|
||||
) => {
|
||||
const { parentLogger } = context
|
||||
const _dbLogger = parentLogger.create(`${logDbPath}`)
|
||||
const { dbg } = _dbLogger
|
||||
|
||||
const { getDatabase } = sqliteService()
|
||||
const db = await getDatabase(logDbPath)
|
||||
|
||||
const conn = knex({
|
||||
client: 'sqlite3',
|
||||
connection: {
|
||||
filename: logDbPath,
|
||||
},
|
||||
useNullAsDefault: true,
|
||||
})
|
||||
|
||||
const write = safeCatch(
|
||||
`write`,
|
||||
_dbLogger,
|
||||
async (message: string, stream: StreamNames = StreamNames.Info) => {
|
||||
const _in: InstanceLogFields_Create = {
|
||||
id: newId(),
|
||||
message,
|
||||
stream,
|
||||
created: pocketNow(),
|
||||
updated: pocketNow(),
|
||||
}
|
||||
const sql = conn('logs').insert(_in).toString()
|
||||
dbg(`Writing log ${JSON.stringify(_in)} ${sql}`)
|
||||
await db.exec(sql)
|
||||
}
|
||||
)
|
||||
|
||||
const subscribe = (cb: (e: SqliteChangeEvent<InstanceLogFields>) => void) => {
|
||||
let _seenIds: { [_: RecordId]: boolean } | undefined = {}
|
||||
|
||||
const unsub = db.subscribe<InstanceLogFields>((e) => {
|
||||
// dbg(`Caught db modification ${logDbPath}`, e)
|
||||
const { table, record } = e
|
||||
if (table !== 'logs') return
|
||||
if (_seenIds) {
|
||||
_seenIds[record.id] = true
|
||||
}
|
||||
cb(e)
|
||||
})
|
||||
return unsub
|
||||
}
|
||||
|
||||
const fetch = async (limit: number = 100) => {
|
||||
return db.all<InstanceLogFields[]>(
|
||||
`select * from logs order by created desc limit ${limit}`
|
||||
)
|
||||
}
|
||||
|
||||
return { write, subscribe, fetch }
|
||||
}
|
@ -1,85 +1,30 @@
|
||||
import { DAEMON_PB_DATA_DIR } from '$constants'
|
||||
import { SqliteChangeEvent, sqliteService } from '$services'
|
||||
import { sqliteService } from '$services'
|
||||
import {
|
||||
InstanceId,
|
||||
InstanceLogFields,
|
||||
InstanceLogFields_Create,
|
||||
logger,
|
||||
mkSingleton,
|
||||
newId,
|
||||
pocketNow,
|
||||
RecordId,
|
||||
safeCatch,
|
||||
SingletonBaseConfig,
|
||||
StreamNames,
|
||||
} from '@pockethost/common'
|
||||
import { mkdirSync } from 'fs'
|
||||
import knex from 'knex'
|
||||
import { dirname, join } from 'path'
|
||||
import { AsyncReturnType } from 'type-fest'
|
||||
|
||||
export type InstanceLogger = AsyncReturnType<typeof mkApi>
|
||||
const mkApi = async (logDbPath: string) => {
|
||||
const { dbg } = logger().create(`InstanceLogger ${logDbPath}`)
|
||||
|
||||
const { getDatabase } = sqliteService()
|
||||
const db = await getDatabase(logDbPath)
|
||||
|
||||
const conn = knex({
|
||||
client: 'sqlite3',
|
||||
connection: {
|
||||
filename: logDbPath,
|
||||
},
|
||||
useNullAsDefault: true,
|
||||
})
|
||||
|
||||
const write = safeCatch(
|
||||
`workerLogger:write`,
|
||||
async (message: string, stream: StreamNames = StreamNames.Info) => {
|
||||
const _in: InstanceLogFields_Create = {
|
||||
id: newId(),
|
||||
message,
|
||||
stream,
|
||||
created: pocketNow(),
|
||||
updated: pocketNow(),
|
||||
}
|
||||
const sql = conn('logs').insert(_in).toString()
|
||||
dbg(`Writing log ${JSON.stringify(_in)} ${sql}`)
|
||||
await db.exec(sql)
|
||||
}
|
||||
)
|
||||
|
||||
const subscribe = (cb: (e: SqliteChangeEvent<InstanceLogFields>) => void) => {
|
||||
let _seenIds: { [_: RecordId]: boolean } | undefined = {}
|
||||
|
||||
const unsub = db.subscribe<InstanceLogFields>((e) => {
|
||||
// dbg(`Caught db modification ${logDbPath}`, e)
|
||||
const { table, record } = e
|
||||
if (table !== 'logs') return
|
||||
if (_seenIds) {
|
||||
_seenIds[record.id] = true
|
||||
}
|
||||
cb(e)
|
||||
})
|
||||
return unsub
|
||||
}
|
||||
|
||||
const fetch = async (limit: number = 100) => {
|
||||
return db.all<InstanceLogFields[]>(
|
||||
`select * from logs order by created desc limit ${limit}`
|
||||
)
|
||||
}
|
||||
|
||||
return { write, subscribe, fetch }
|
||||
}
|
||||
import { DaemonContext } from './DaemonContext'
|
||||
import { createSqliteLogger, SqliteLogger } from './SqliteLogger'
|
||||
|
||||
const instances: {
|
||||
[instanceId: InstanceId]: Promise<InstanceLogger>
|
||||
[instanceId: InstanceId]: Promise<SqliteLogger>
|
||||
} = {}
|
||||
|
||||
export const createInstanceLogger = (instanceId: InstanceId) => {
|
||||
export const createInstanceLogger = (
|
||||
instanceId: InstanceId,
|
||||
context: DaemonContext
|
||||
) => {
|
||||
const { parentLogger } = context
|
||||
|
||||
if (!instances[instanceId]) {
|
||||
instances[instanceId] = new Promise<InstanceLogger>(async (resolve) => {
|
||||
const { dbg } = logger().create(`WorkerLogger:${instanceId}`)
|
||||
instances[instanceId] = new Promise<SqliteLogger>(async (resolve) => {
|
||||
const _instanceLogger = parentLogger.create(`InstanceLogger`)
|
||||
const { dbg } = _instanceLogger
|
||||
|
||||
const logDbPath = join(
|
||||
DAEMON_PB_DATA_DIR,
|
||||
@ -98,7 +43,9 @@ export const createInstanceLogger = (instanceId: InstanceId) => {
|
||||
migrationsPath: join(__dirname, 'migrations'),
|
||||
})
|
||||
|
||||
const api = await mkApi(logDbPath)
|
||||
const api = await createSqliteLogger(logDbPath, {
|
||||
parentLogger: _instanceLogger,
|
||||
})
|
||||
await api.write(`Ran migrations`, StreamNames.System)
|
||||
resolve(api)
|
||||
})
|
||||
@ -107,8 +54,12 @@ export const createInstanceLogger = (instanceId: InstanceId) => {
|
||||
return instances[instanceId]!
|
||||
}
|
||||
|
||||
export const instanceLoggerService = mkSingleton(() => {
|
||||
const { dbg } = logger().create(`InstanceLoggerService`)
|
||||
export type InstanceLoggerServiceConfig = SingletonBaseConfig
|
||||
|
||||
export const instanceLoggerService = mkSingleton(
|
||||
(config: InstanceLoggerServiceConfig) => {
|
||||
const { logger } = config
|
||||
const { dbg } = logger.create(`InstanceLoggerService`)
|
||||
dbg(`Starting up`)
|
||||
return {
|
||||
get: createInstanceLogger,
|
||||
@ -116,4 +67,5 @@ export const instanceLoggerService = mkSingleton(() => {
|
||||
dbg(`Shutting down`)
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { DAEMON_PB_DATA_DIR, DENO_PATH } from '$constants'
|
||||
import { InstanceFields, logger, StreamNames } from '@pockethost/common'
|
||||
import { InstanceFields, Logger, StreamNames } from '@pockethost/common'
|
||||
import { keys } from '@s-libs/micro-dash'
|
||||
import { spawn } from 'child_process'
|
||||
import { join } from 'path'
|
||||
@ -11,12 +11,15 @@ export type DenoProcessConfig = {
|
||||
path: string
|
||||
port: number
|
||||
instance: InstanceFields
|
||||
logger: Logger
|
||||
}
|
||||
|
||||
export type DenoApi = AsyncReturnType<typeof createDenoProcess>
|
||||
|
||||
export const createDenoProcess = async (config: DenoProcessConfig) => {
|
||||
const { dbg, error } = logger().create(`DenoProcess.ts`)
|
||||
const { logger } = config
|
||||
const _denoLogger = logger.create(`DenoProcess.ts`)
|
||||
const { dbg, error } = _denoLogger
|
||||
|
||||
const { instance, port, path } = config
|
||||
const internalUrl = mkInternalUrl(port)
|
||||
@ -34,7 +37,9 @@ export const createDenoProcess = async (config: DenoProcessConfig) => {
|
||||
path,
|
||||
]
|
||||
|
||||
const denoLogger = await instanceLoggerService().get(instance.id)
|
||||
const denoLogger = await instanceLoggerService().get(instance.id, {
|
||||
parentLogger: _denoLogger,
|
||||
})
|
||||
|
||||
const denoWrite = (
|
||||
message: string,
|
||||
|
@ -16,13 +16,13 @@ import {
|
||||
createTimerManager,
|
||||
InstanceId,
|
||||
InstanceStatus,
|
||||
logger,
|
||||
mkSingleton,
|
||||
RpcCommands,
|
||||
safeCatch,
|
||||
SaveSecretsPayload,
|
||||
SaveSecretsPayloadSchema,
|
||||
SaveSecretsResult,
|
||||
SingletonBaseConfig,
|
||||
} from '@pockethost/common'
|
||||
import { forEachRight, map } from '@s-libs/micro-dash'
|
||||
import Bottleneck from 'bottleneck'
|
||||
@ -42,12 +42,14 @@ type InstanceApi = {
|
||||
startRequest: () => () => void
|
||||
}
|
||||
|
||||
export type InstanceServiceConfig = {}
|
||||
export type InstanceServiceConfig = SingletonBaseConfig & {}
|
||||
|
||||
export type InstanceServiceApi = AsyncReturnType<typeof instanceService>
|
||||
export const instanceService = mkSingleton(
|
||||
async (config: InstanceServiceConfig) => {
|
||||
const { dbg, raw, error, warn } = logger().create('InstanceService')
|
||||
const { logger } = config
|
||||
const _instanceLogger = logger.create('InstanceService')
|
||||
const { dbg, raw, error, warn } = _instanceLogger
|
||||
const { client } = await clientService()
|
||||
|
||||
const { registerCommand } = await rpcService()
|
||||
@ -91,9 +93,8 @@ export const instanceService = mkSingleton(
|
||||
const getInstance = (subdomain: string) =>
|
||||
instanceLimiter
|
||||
.schedule(async () => {
|
||||
const { dbg, warn, error } = logger().create(
|
||||
`InstanceService ${subdomain}`
|
||||
)
|
||||
const _subdomainLogger = _instanceLogger.create(subdomain)
|
||||
const { dbg, warn, error } = _subdomainLogger
|
||||
dbg(`Getting instance`)
|
||||
{
|
||||
const instance = instances[subdomain]
|
||||
@ -112,6 +113,7 @@ export const instanceService = mkSingleton(
|
||||
)
|
||||
}
|
||||
dbg(`Instance found`)
|
||||
_subdomainLogger.breadcrumb(instance.id)
|
||||
|
||||
dbg(`Checking for verified account`)
|
||||
if (!owner?.verified) {
|
||||
@ -132,9 +134,13 @@ export const instanceService = mkSingleton(
|
||||
error(`Failed to get port for ${subdomain}`)
|
||||
throw e
|
||||
})
|
||||
_subdomainLogger.breadcrumb(newPort.toString())
|
||||
dbg(`Found port: ${newPort}`)
|
||||
|
||||
const instanceLogger = await instanceLoggerService().get(instance.id)
|
||||
const instanceLogger = await instanceLoggerService().get(
|
||||
instance.id,
|
||||
{ parentLogger: _subdomainLogger }
|
||||
)
|
||||
|
||||
await clientLimiter.schedule(() => {
|
||||
dbg(`Instance status: starting`)
|
||||
@ -146,7 +152,9 @@ export const instanceService = mkSingleton(
|
||||
|
||||
dbg(`Starting instance`)
|
||||
await instanceLogger.write(`Starting instance`)
|
||||
const childProcess = await pbService.spawn({
|
||||
const childProcess = await (async () => {
|
||||
try {
|
||||
const cp = await pbService.spawn({
|
||||
command: 'serve',
|
||||
slug: instance.id,
|
||||
port: newPort,
|
||||
@ -156,6 +164,13 @@ export const instanceService = mkSingleton(
|
||||
api.shutdown()
|
||||
},
|
||||
})
|
||||
return cp
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Could not launch PocketBase ${instance.version}. It may be time to upgrade.`
|
||||
)
|
||||
}
|
||||
})()
|
||||
|
||||
const { pid } = childProcess
|
||||
assertTruthy(pid, `Expected PID here but got ${pid}`)
|
||||
@ -190,6 +205,7 @@ export const instanceService = mkSingleton(
|
||||
path: workerPath,
|
||||
port: newPort,
|
||||
instance,
|
||||
logger: _instanceLogger,
|
||||
})
|
||||
return api
|
||||
} else {
|
||||
@ -210,6 +226,7 @@ export const instanceService = mkSingleton(
|
||||
port: newPort,
|
||||
shutdown: safeCatch(
|
||||
`Instance ${subdomain} invocation ${invocation.id} pid ${pid} shutdown`,
|
||||
_subdomainLogger,
|
||||
async () => {
|
||||
dbg(`Shutting down`)
|
||||
await instanceLogger.write(`Shutting down instance`)
|
||||
@ -247,7 +264,7 @@ export const instanceService = mkSingleton(
|
||||
|
||||
{
|
||||
tm.repeat(
|
||||
safeCatch(`idleCheck`, async () => {
|
||||
safeCatch(`idleCheck`, _subdomainLogger, async () => {
|
||||
raw(
|
||||
`${subdomain} idle check: ${openRequestCount} open requests`
|
||||
)
|
||||
@ -272,7 +289,7 @@ export const instanceService = mkSingleton(
|
||||
}
|
||||
|
||||
{
|
||||
const uptime = safeCatch(`uptime`, async () => {
|
||||
const uptime = safeCatch(`uptime`, _subdomainLogger, async () => {
|
||||
raw(`${subdomain} uptime`)
|
||||
await clientLimiter.schedule(() =>
|
||||
client.pingInvocation(invocation)
|
||||
@ -314,7 +331,7 @@ export const instanceService = mkSingleton(
|
||||
;(await proxyService()).use(
|
||||
(subdomain) => subdomain !== PUBLIC_APP_DB,
|
||||
['/api(/*)', '/_(/*)', '(/*)'],
|
||||
async (req, res, meta) => {
|
||||
async (req, res, meta, logger) => {
|
||||
const { subdomain, host, proxy } = meta
|
||||
|
||||
// Do not handle central db requests, that is handled separately
|
||||
|
@ -9,10 +9,12 @@ import {
|
||||
import {
|
||||
createCleanupManager,
|
||||
createTimerManager,
|
||||
logger,
|
||||
safeCatch,
|
||||
} from '@pockethost/common'
|
||||
import { mkSingleton } from '@pockethost/common/src/mkSingleton'
|
||||
import {
|
||||
mkSingleton,
|
||||
SingletonBaseConfig,
|
||||
} from '@pockethost/common/src/mkSingleton'
|
||||
import { keys } from '@s-libs/micro-dash'
|
||||
import { spawn } from 'child_process'
|
||||
import { chmodSync, existsSync } from 'fs'
|
||||
@ -35,7 +37,7 @@ export type PocketbaseServiceApi = AsyncReturnType<
|
||||
typeof createPocketbaseService
|
||||
>
|
||||
|
||||
export type PocketbaseServiceConfig = {
|
||||
export type PocketbaseServiceConfig = SingletonBaseConfig & {
|
||||
cachePath: string
|
||||
checkIntervalMs: number
|
||||
}
|
||||
@ -60,7 +62,9 @@ export type Releases = Release[]
|
||||
export const createPocketbaseService = async (
|
||||
config: PocketbaseServiceConfig
|
||||
) => {
|
||||
const { dbg, error } = logger().create('PocketbaseService')
|
||||
const { logger } = config
|
||||
const _serviceLogger = logger.create('PocketbaseService')
|
||||
const { dbg, error } = _serviceLogger
|
||||
|
||||
const { cachePath, checkIntervalMs } = config
|
||||
|
||||
@ -100,7 +104,7 @@ export const createPocketbaseService = async (
|
||||
versions[sanitizedTagName] = Promise.resolve('')
|
||||
return
|
||||
}
|
||||
await downloadAndExtract(url, binPath)
|
||||
await downloadAndExtract(url, binPath, _serviceLogger)
|
||||
|
||||
resolve(binPath)
|
||||
})
|
||||
@ -138,7 +142,10 @@ export const createPocketbaseService = async (
|
||||
}
|
||||
}
|
||||
|
||||
const _spawn = safeCatch(`spawnInstance`, async (cfg: SpawnConfig) => {
|
||||
const _spawn = safeCatch(
|
||||
`spawnInstance`,
|
||||
_serviceLogger,
|
||||
async (cfg: SpawnConfig) => {
|
||||
const _cfg: Required<SpawnConfig> = {
|
||||
version: maxVersion,
|
||||
port: await getPort(),
|
||||
@ -207,7 +214,7 @@ export const createPocketbaseService = async (
|
||||
|
||||
const url = mkInternalUrl(port)
|
||||
if (command === 'serve') {
|
||||
await tryFetch(url, async () => isRunning)
|
||||
await tryFetch(_serviceLogger)(url, async () => isRunning)
|
||||
}
|
||||
const api: PocketbaseProcess = {
|
||||
url,
|
||||
@ -216,7 +223,8 @@ export const createPocketbaseService = async (
|
||||
kill: () => ls.kill(),
|
||||
}
|
||||
return api
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
const shutdown = () => {
|
||||
dbg(`Shutting down pocketbaseService`)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { PUBLIC_APP_DOMAIN } from '$constants'
|
||||
import { logger, mkSingleton } from '@pockethost/common'
|
||||
import { Logger, mkSingleton, SingletonBaseConfig } from '@pockethost/common'
|
||||
import { isFunction } from '@s-libs/micro-dash'
|
||||
import {
|
||||
createServer,
|
||||
@ -21,14 +21,17 @@ export type ProxyMiddleware = (
|
||||
coreInternalUrl: string
|
||||
proxy: Server
|
||||
host: string
|
||||
}
|
||||
},
|
||||
logger: Logger
|
||||
) => void | Promise<void>
|
||||
|
||||
export type ProxyServiceConfig = {
|
||||
export type ProxyServiceConfig = SingletonBaseConfig & {
|
||||
coreInternalUrl: string
|
||||
}
|
||||
export const proxyService = mkSingleton(async (config: ProxyServiceConfig) => {
|
||||
const { dbg, error, info, trace, warn } = logger().create('ProxyService')
|
||||
const { logger } = config
|
||||
const _proxyLogger = logger.create('ProxyService')
|
||||
const { dbg, error, info, trace, warn } = _proxyLogger
|
||||
|
||||
const { coreInternalUrl } = config
|
||||
|
||||
@ -38,7 +41,7 @@ export const proxyService = mkSingleton(async (config: ProxyServiceConfig) => {
|
||||
})
|
||||
|
||||
const server = createServer(async (req, res) => {
|
||||
dbg(`Incoming request ${req.headers.host}/${req.url}`)
|
||||
dbg(`Incoming request ${req.method} ${req.headers.host}/${req.url}`)
|
||||
if (!req.headers.host?.endsWith(PUBLIC_APP_DOMAIN)) {
|
||||
warn(
|
||||
`Request for ${req.headers.host} rejected because host does not end in ${PUBLIC_APP_DOMAIN}`
|
||||
@ -89,7 +92,8 @@ export const proxyService = mkSingleton(async (config: ProxyServiceConfig) => {
|
||||
handler: ProxyMiddleware,
|
||||
handlerName: string
|
||||
) => {
|
||||
const { dbg, trace } = logger().create(`ProxyService:${handlerName}`)
|
||||
const _handlerLogger = _proxyLogger.create(`${handlerName}`)
|
||||
const { dbg, trace } = _handlerLogger
|
||||
dbg({ subdomainFilter, urlFilters })
|
||||
|
||||
const _urlFilters = Array.isArray(urlFilters)
|
||||
@ -105,6 +109,10 @@ export const proxyService = mkSingleton(async (config: ProxyServiceConfig) => {
|
||||
if (!host) {
|
||||
throw new Error(`Host not found`)
|
||||
}
|
||||
const _requestLogger = _handlerLogger.create(host)
|
||||
const { dbg, trace } = _requestLogger
|
||||
_requestLogger.breadcrumb(req.method)
|
||||
_requestLogger.breadcrumb(req.url)
|
||||
const [subdomain, ...junk] = host.split('.')
|
||||
if (!subdomain) {
|
||||
throw new Error(`${host} has no subdomain.`)
|
||||
@ -133,7 +141,12 @@ export const proxyService = mkSingleton(async (config: ProxyServiceConfig) => {
|
||||
return
|
||||
}
|
||||
dbg(`${url} matches ${urlFilters}, sending to handler`)
|
||||
return handler(req, res, { host, subdomain, coreInternalUrl, proxy })
|
||||
return handler(
|
||||
req,
|
||||
res,
|
||||
{ host, subdomain, coreInternalUrl, proxy },
|
||||
_requestLogger
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { PUBLIC_APP_DB } from '$src/constants'
|
||||
import {
|
||||
InstanceFields,
|
||||
logger,
|
||||
mkSingleton,
|
||||
RecordId,
|
||||
SingletonBaseConfig,
|
||||
} from '@pockethost/common'
|
||||
import Bottleneck from 'bottleneck'
|
||||
import { text } from 'node:stream/consumers'
|
||||
@ -12,7 +12,7 @@ import { JsonifiableObject } from 'type-fest/source/jsonifiable'
|
||||
import { instanceLoggerService } from './InstanceLoggerService'
|
||||
import { proxyService } from './ProxyService'
|
||||
|
||||
export type RealtimeLogConfig = {}
|
||||
export type RealtimeLogConfig = SingletonBaseConfig & {}
|
||||
|
||||
const mkEvent = (name: string, data: JsonifiableObject) => {
|
||||
return `event: ${name}\ndata: ${JSON.stringify(data)}\n\n`
|
||||
@ -20,20 +20,21 @@ const mkEvent = (name: string, data: JsonifiableObject) => {
|
||||
|
||||
export type RealtimeLog = ReturnType<typeof realtimeLog>
|
||||
export const realtimeLog = mkSingleton(async (config: RealtimeLogConfig) => {
|
||||
const { dbg, error } = logger().create(`RealtimeLog.ts`)
|
||||
const { logger } = config
|
||||
const _realtimeLogger = logger.create(`RealtimeLog`)
|
||||
const { dbg, error } = _realtimeLogger
|
||||
|
||||
;(await proxyService()).use(
|
||||
PUBLIC_APP_DB,
|
||||
'/logs',
|
||||
async (req, res, meta) => {
|
||||
async (req, res, meta, logger) => {
|
||||
const { subdomain, host, coreInternalUrl } = meta
|
||||
if (!req.url?.startsWith('/logs')) {
|
||||
return
|
||||
}
|
||||
|
||||
const { dbg, error, trace } = logger().create(
|
||||
`RealtimeLog:${subdomain}:${host}`
|
||||
)
|
||||
const _requestLogger = logger.create(`${subdomain}`)
|
||||
const { dbg, error, trace } = _requestLogger
|
||||
|
||||
const write = async (data: any) => {
|
||||
return new Promise<void>((resolve) => {
|
||||
@ -115,7 +116,9 @@ export const realtimeLog = mkSingleton(async (config: RealtimeLogConfig) => {
|
||||
/**
|
||||
* Get a database connection
|
||||
*/
|
||||
const instanceLogger = await instanceLoggerService().get(instanceId)
|
||||
const instanceLogger = await instanceLoggerService().get(instanceId, {
|
||||
parentLogger: _requestLogger,
|
||||
})
|
||||
const { subscribe } = instanceLogger
|
||||
|
||||
/**
|
||||
@ -182,8 +185,6 @@ export const realtimeLog = mkSingleton(async (config: RealtimeLogConfig) => {
|
||||
})
|
||||
.catch(error)
|
||||
}
|
||||
|
||||
return true
|
||||
},
|
||||
`RealtimeLogService`
|
||||
)
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { clientService } from '$services'
|
||||
import {
|
||||
assertTruthy,
|
||||
logger,
|
||||
mkSingleton,
|
||||
RpcCommands,
|
||||
RpcFields,
|
||||
RpcStatus,
|
||||
RPC_COMMANDS,
|
||||
SingletonBaseConfig,
|
||||
} from '@pockethost/common'
|
||||
import { isObject } from '@s-libs/micro-dash'
|
||||
import Ajv, { JSONSchemaType, ValidateFunction } from 'ajv'
|
||||
@ -29,10 +29,11 @@ export type RpcRunner<
|
||||
TResult extends JsonObject
|
||||
> = (job: RpcFields<TPayload, TResult>) => Promise<TResult>
|
||||
|
||||
export type RpcServiceConfig = {}
|
||||
export type RpcServiceConfig = SingletonBaseConfig & {}
|
||||
|
||||
export const rpcService = mkSingleton(async (config: RpcServiceConfig) => {
|
||||
const { dbg, error } = logger().create('RpcService')
|
||||
const { logger } = config
|
||||
const { dbg, error } = logger.create('RpcService')
|
||||
const { client } = await clientService()
|
||||
|
||||
const limiter = new Bottleneck({ maxConcurrent: 1 })
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {
|
||||
createCleanupManager,
|
||||
createEvent,
|
||||
logger,
|
||||
mkSingleton,
|
||||
SingletonBaseConfig,
|
||||
} from '@pockethost/common'
|
||||
import Bottleneck from 'bottleneck'
|
||||
import { Database as SqliteDatabase, open } from 'sqlite'
|
||||
@ -28,12 +28,13 @@ export type SqliteServiceApi = {
|
||||
cb: SqliteChangeHandler<TRecord>
|
||||
) => SqliteUnsubscribe
|
||||
}
|
||||
export type SqliteServiceConfig = {}
|
||||
export type SqliteServiceConfig = SingletonBaseConfig & {}
|
||||
|
||||
export type SqliteService = ReturnType<typeof sqliteService>
|
||||
|
||||
export const sqliteService = mkSingleton((config: SqliteServiceConfig) => {
|
||||
const { dbg, trace } = logger().create(`sqliteService`)
|
||||
const { logger } = config
|
||||
const { dbg, trace } = logger.create(`sqliteService`)
|
||||
const connections: { [_: string]: Promise<SqliteServiceApi> } = {}
|
||||
|
||||
const cm = createCleanupManager()
|
||||
@ -41,7 +42,8 @@ export const sqliteService = mkSingleton((config: SqliteServiceConfig) => {
|
||||
const limiter = new Bottleneck({ maxConcurrent: 1 })
|
||||
|
||||
const getDatabase = async (filename: string): Promise<SqliteServiceApi> => {
|
||||
const { dbg } = logger().create(`sqliteService:${filename}`)
|
||||
const _dbLogger = logger.create(`${filename}`)
|
||||
const { dbg } = _dbLogger
|
||||
|
||||
trace(`Fetching database for ${filename}`, connections)
|
||||
if (!connections[filename]) {
|
||||
|
@ -4,7 +4,6 @@ import {
|
||||
InstanceFields_Create,
|
||||
InstanceId,
|
||||
InstanceStatus,
|
||||
logger,
|
||||
safeCatch,
|
||||
UserFields,
|
||||
} from '@pockethost/common'
|
||||
@ -16,12 +15,14 @@ import { MixinContext } from './PbClient'
|
||||
export type InstanceApi = ReturnType<typeof createInstanceMixin>
|
||||
|
||||
export const createInstanceMixin = (context: MixinContext) => {
|
||||
const { dbg, raw } = logger().create('InstanceMixin')
|
||||
const { logger } = context
|
||||
const { dbg, raw } = logger.create('InstanceMixin')
|
||||
|
||||
const { client, rawDb } = context
|
||||
|
||||
const createInstance = safeCatch(
|
||||
`createInstance`,
|
||||
logger,
|
||||
(payload: InstanceFields_Create): Promise<InstanceFields> => {
|
||||
return client.collection('instances').create<InstanceFields>(payload)
|
||||
}
|
||||
@ -29,6 +30,7 @@ export const createInstanceMixin = (context: MixinContext) => {
|
||||
|
||||
const getInstanceBySubdomain = safeCatch(
|
||||
`getInstanceBySubdomain`,
|
||||
logger,
|
||||
(subdomain: string): Promise<[InstanceFields, UserFields] | []> =>
|
||||
client
|
||||
.collection('instances')
|
||||
@ -46,6 +48,7 @@ export const createInstanceMixin = (context: MixinContext) => {
|
||||
|
||||
const getInstanceById = safeCatch(
|
||||
`getInstanceById`,
|
||||
logger,
|
||||
async (
|
||||
instanceId: InstanceId
|
||||
): Promise<[InstanceFields, UserFields] | []> => {
|
||||
@ -66,6 +69,7 @@ export const createInstanceMixin = (context: MixinContext) => {
|
||||
|
||||
const updateInstance = safeCatch(
|
||||
`updateInstance`,
|
||||
logger,
|
||||
async (instanceId: InstanceId, fields: Partial<InstanceFields>) => {
|
||||
await client.collection('instances').update(instanceId, fields)
|
||||
}
|
||||
@ -73,6 +77,7 @@ export const createInstanceMixin = (context: MixinContext) => {
|
||||
|
||||
const updateInstanceStatus = safeCatch(
|
||||
`updateInstanceStatus`,
|
||||
logger,
|
||||
async (instanceId: InstanceId, status: InstanceStatus) => {
|
||||
await updateInstance(instanceId, { status })
|
||||
}
|
||||
@ -80,17 +85,19 @@ export const createInstanceMixin = (context: MixinContext) => {
|
||||
|
||||
const getInstance = safeCatch(
|
||||
`getInstance`,
|
||||
logger,
|
||||
async (instanceId: InstanceId) => {
|
||||
return client.collection('instances').getOne<InstanceFields>(instanceId)
|
||||
}
|
||||
)
|
||||
|
||||
const getInstances = safeCatch(`getInstances`, async () => {
|
||||
const getInstances = safeCatch(`getInstances`, logger, async () => {
|
||||
return client.collection('instances').getFullList<InstanceFields>()
|
||||
})
|
||||
|
||||
const updateInstances = safeCatch(
|
||||
'updateInstances',
|
||||
logger,
|
||||
async (cb: (rec: InstanceFields) => Partial<InstanceFields>) => {
|
||||
const res = await client
|
||||
.collection('instances')
|
||||
@ -116,6 +123,7 @@ export const createInstanceMixin = (context: MixinContext) => {
|
||||
|
||||
const updateInstanceSeconds = safeCatch(
|
||||
`updateInstanceSeconds`,
|
||||
logger,
|
||||
async (instanceId: InstanceId, forPeriod = new Date()) => {
|
||||
const startIso = startOfMonth(forPeriod).toISOString()
|
||||
const endIso = endOfMonth(forPeriod).toISOString()
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {
|
||||
InstanceFields,
|
||||
InvocationFields,
|
||||
logger,
|
||||
pocketNow,
|
||||
safeCatch,
|
||||
} from '@pockethost/common'
|
||||
@ -12,12 +11,14 @@ export const createInvocationMixin = (
|
||||
context: MixinContext,
|
||||
instanceApi: InstanceApi
|
||||
) => {
|
||||
const { dbg } = logger().create('InvocationMixin')
|
||||
const { logger } = context
|
||||
const { dbg } = logger.create('InvocationMixin')
|
||||
|
||||
const { client } = context
|
||||
|
||||
const createInvocation = safeCatch(
|
||||
`createInvocation`,
|
||||
logger,
|
||||
async (instance: InstanceFields, pid: number) => {
|
||||
const init: Partial<InvocationFields> = {
|
||||
startedAt: pocketNow(),
|
||||
@ -34,6 +35,7 @@ export const createInvocationMixin = (
|
||||
|
||||
const pingInvocation = safeCatch(
|
||||
`pingInvocation`,
|
||||
logger,
|
||||
async (invocation: InvocationFields) => {
|
||||
const totalSeconds =
|
||||
(+new Date() - Date.parse(invocation.startedAt)) / 1000
|
||||
@ -50,6 +52,7 @@ export const createInvocationMixin = (
|
||||
|
||||
const finalizeInvocation = safeCatch(
|
||||
`finalizeInvocation`,
|
||||
logger,
|
||||
async (invocation: InvocationFields) => {
|
||||
dbg('finalizing')
|
||||
const totalSeconds =
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { DAEMON_PB_DATA_DIR, PUBLIC_APP_DB } from '$constants'
|
||||
import { logger, safeCatch } from '@pockethost/common'
|
||||
import { Logger, safeCatch } from '@pockethost/common'
|
||||
import { Knex } from 'knex'
|
||||
import { default as PocketBase, default as pocketbaseEs } from 'pocketbase'
|
||||
import { createBackupMixin } from './BackupMixin'
|
||||
import { createInstanceMixin } from './InstanceMIxin'
|
||||
import { createInvocationMixin } from './InvocationMixin'
|
||||
import { createRawPbClient } from './RawPbClient'
|
||||
@ -10,26 +9,30 @@ import { createRpcHelper } from './RpcHelper'
|
||||
|
||||
export type PocketbaseClientApi = ReturnType<typeof createPbClient>
|
||||
|
||||
export type MixinContext = { client: pocketbaseEs; rawDb: Knex }
|
||||
export type MixinContext = { client: pocketbaseEs; rawDb: Knex; logger: Logger }
|
||||
|
||||
export const createPbClient = (url: string) => {
|
||||
const { info } = logger().create('PbClient')
|
||||
export const createPbClient = (url: string, logger: Logger) => {
|
||||
const _clientLogger = logger.create('PbClient')
|
||||
const { info } = _clientLogger
|
||||
|
||||
info(`Initializing client: ${url}`)
|
||||
const rawDb = createRawPbClient(
|
||||
`${DAEMON_PB_DATA_DIR}/${PUBLIC_APP_DB}/pb_data/data.db`
|
||||
`${DAEMON_PB_DATA_DIR}/${PUBLIC_APP_DB}/pb_data/data.db`,
|
||||
_clientLogger
|
||||
)
|
||||
|
||||
const client = new PocketBase(url)
|
||||
|
||||
const adminAuthViaEmail = safeCatch(
|
||||
`adminAuthViaEmail`,
|
||||
_clientLogger,
|
||||
(email: string, password: string) =>
|
||||
client.admins.authWithPassword(email, password)
|
||||
)
|
||||
|
||||
const createFirstAdmin = safeCatch(
|
||||
`createFirstAdmin`,
|
||||
_clientLogger,
|
||||
(email: string, password: string) =>
|
||||
client.admins
|
||||
.create({ email, password, passwordConfirm: password })
|
||||
@ -40,10 +43,9 @@ export const createPbClient = (url: string) => {
|
||||
})
|
||||
)
|
||||
|
||||
const context: MixinContext = { client, rawDb }
|
||||
const context: MixinContext = { client, rawDb, logger: _clientLogger }
|
||||
const rpcApi = createRpcHelper(context)
|
||||
const instanceApi = createInstanceMixin(context)
|
||||
const backupApi = createBackupMixin(context)
|
||||
const invocationApi = createInvocationMixin(context, instanceApi)
|
||||
|
||||
const api = {
|
||||
@ -55,7 +57,6 @@ export const createPbClient = (url: string) => {
|
||||
...rpcApi,
|
||||
...instanceApi,
|
||||
...invocationApi,
|
||||
...backupApi,
|
||||
}
|
||||
|
||||
return api
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { logger } from '@pockethost/common'
|
||||
import { Logger } from '@pockethost/common'
|
||||
import { existsSync } from 'fs'
|
||||
import knex from 'knex'
|
||||
|
||||
export const createRawPbClient = (filename: string) => {
|
||||
const { dbg } = logger().create(`rawPbClient`)
|
||||
export const createRawPbClient = (filename: string, logger: Logger) => {
|
||||
const { dbg } = logger.create(`rawPbClient`)
|
||||
dbg(filename)
|
||||
|
||||
if (!existsSync(filename)) {
|
||||
|
@ -18,9 +18,10 @@ export type RpcHelperConfig = MixinContext
|
||||
export type RpcHelper = ReturnType<typeof createRpcHelper>
|
||||
|
||||
export const createRpcHelper = (config: RpcHelperConfig) => {
|
||||
const { client, rawDb } = config
|
||||
const { client, rawDb, logger } = config
|
||||
const onNewRpc = safeCatch(
|
||||
`onNewRpc`,
|
||||
logger,
|
||||
async (cb: (e: RpcFields<any, any>) => void) => {
|
||||
const unsub = await client
|
||||
.collection(RPC_COLLECTION)
|
||||
@ -32,7 +33,7 @@ export const createRpcHelper = (config: RpcHelperConfig) => {
|
||||
}
|
||||
)
|
||||
|
||||
const resetRpcs = safeCatch(`resetRpcs`, async () =>
|
||||
const resetRpcs = safeCatch(`resetRpcs`, logger, async () =>
|
||||
rawDb(RPC_COLLECTION)
|
||||
.whereNotIn('status', [
|
||||
RpcStatus.FinishedError,
|
||||
@ -44,7 +45,7 @@ export const createRpcHelper = (config: RpcHelperConfig) => {
|
||||
})
|
||||
)
|
||||
|
||||
const incompleteRpcs = safeCatch(`incompleteRpcs`, async () => {
|
||||
const incompleteRpcs = safeCatch(`incompleteRpcs`, logger, async () => {
|
||||
return client
|
||||
.collection(RPC_COLLECTION)
|
||||
.getFullList<RpcFields<any, any>>(100, {
|
||||
@ -54,6 +55,7 @@ export const createRpcHelper = (config: RpcHelperConfig) => {
|
||||
|
||||
const rejectRpc = safeCatch(
|
||||
`rejectRpc`,
|
||||
logger,
|
||||
async (rpc: RpcFields<any, any>, err: Error) => {
|
||||
const fields: Partial<RpcFields<any, any>> = {
|
||||
status: RpcStatus.FinishedError,
|
||||
@ -67,6 +69,7 @@ export const createRpcHelper = (config: RpcHelperConfig) => {
|
||||
|
||||
const setRpcStatus = safeCatch(
|
||||
`setRpcStatus`,
|
||||
logger,
|
||||
async (
|
||||
rpc: RpcFields<any, any>,
|
||||
status: RpcStatus,
|
||||
|
@ -5,12 +5,19 @@ import {
|
||||
PUBLIC_APP_DOMAIN,
|
||||
PUBLIC_APP_PROTOCOL,
|
||||
} from '$constants'
|
||||
import { logger, mkSingleton } from '@pockethost/common'
|
||||
import { Logger, mkSingleton } from '@pockethost/common'
|
||||
import { createPbClient } from './PbClient'
|
||||
|
||||
export const clientService = mkSingleton(async (url: string) => {
|
||||
const { dbg, error } = logger().create(`client singleton`)
|
||||
const client = createPbClient(url)
|
||||
export type ClientServiceConfig = {
|
||||
logger: Logger
|
||||
url: string
|
||||
}
|
||||
|
||||
export const clientService = mkSingleton(async (cfg: ClientServiceConfig) => {
|
||||
const { logger, url } = cfg
|
||||
const _clientLogger = logger.create(`client singleton`)
|
||||
const { dbg, error } = _clientLogger
|
||||
const client = createPbClient(url, _clientLogger)
|
||||
|
||||
try {
|
||||
await client.adminAuthViaEmail(DAEMON_PB_USERNAME, DAEMON_PB_PASSWORD)
|
||||
|
@ -1,4 +1,3 @@
|
||||
export * from './BackupService'
|
||||
export * from './clientService/clientService'
|
||||
export * from './clientService/PbClient'
|
||||
export * from './FtpService/FtpService'
|
||||
|
@ -1,11 +1,15 @@
|
||||
import { logger } from '@pockethost/common'
|
||||
import { Logger } from '@pockethost/common'
|
||||
import { chmodSync } from 'fs'
|
||||
import fetch from 'node-fetch'
|
||||
import { dirname } from 'path'
|
||||
import { Extract } from 'unzipper'
|
||||
|
||||
export const downloadAndExtract = async (url: string, binPath: string) => {
|
||||
const { dbg, error } = logger().create('downloadAndExtract')
|
||||
export const downloadAndExtract = async (
|
||||
url: string,
|
||||
binPath: string,
|
||||
logger: Logger
|
||||
) => {
|
||||
const { dbg, error } = logger.create('downloadAndExtract')
|
||||
|
||||
await new Promise<void>(async (resolve, reject) => {
|
||||
dbg(`Fetching ${url}`)
|
||||
|
@ -1,4 +1,3 @@
|
||||
export * from './backupInstance'
|
||||
export * from './downloadAndExtract'
|
||||
export * from './ensureDirExists'
|
||||
export * from './env'
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { logger, safeCatch } from '@pockethost/common'
|
||||
import { Logger, safeCatch } from '@pockethost/common'
|
||||
import { exec } from 'child_process'
|
||||
|
||||
export const pexec = safeCatch(`pexec`, (cmd: string) => {
|
||||
const { dbg, error } = logger().create('pexec')
|
||||
export const pexec = (logger: Logger) =>
|
||||
safeCatch(`pexec`, logger, (cmd: string) => {
|
||||
const { dbg, error } = logger.create('pexec')
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
dbg(cmd)
|
||||
exec(cmd, (err, stdout, stderr) => {
|
||||
|
@ -1,16 +1,19 @@
|
||||
import { logger, safeCatch } from '@pockethost/common'
|
||||
import { Logger, safeCatch } from '@pockethost/common'
|
||||
|
||||
export const tryFetch = safeCatch(
|
||||
export const tryFetch = (logger: Logger) =>
|
||||
safeCatch(
|
||||
`tryFetch`,
|
||||
logger,
|
||||
(url: string, preflight?: () => Promise<boolean>) => {
|
||||
const { dbg } = logger().create('tryFetch')
|
||||
const { dbg } = logger.create('tryFetch')
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const tryFetch = async () => {
|
||||
if (preflight) {
|
||||
dbg(`Checking preflight`)
|
||||
const shouldFetch = await preflight()
|
||||
if (!shouldFetch) {
|
||||
throw new Error(`tryFetch failed preflight, aborting`)
|
||||
reject(new Error(`tryFetch failed preflight, aborting`))
|
||||
return
|
||||
}
|
||||
}
|
||||
try {
|
||||
|
@ -44,7 +44,8 @@ export type PocketbaseClient = ReturnType<typeof createPocketbaseClient>
|
||||
|
||||
export const createPocketbaseClient = (config: PocketbaseClientConfig) => {
|
||||
const { url } = config
|
||||
const { dbg, error } = logger()
|
||||
const _logger = logger()
|
||||
const { dbg, error } = _logger
|
||||
|
||||
const client = new PocketBase(url)
|
||||
|
||||
@ -56,7 +57,7 @@ export const createPocketbaseClient = (config: PocketbaseClientConfig) => {
|
||||
|
||||
const logOut = () => authStore.clear()
|
||||
|
||||
const createUser = safeCatch(`createUser`, (email: string, password: string) =>
|
||||
const createUser = safeCatch(`createUser`, _logger, (email: string, password: string) =>
|
||||
client
|
||||
.collection('users')
|
||||
.create({
|
||||
@ -70,7 +71,7 @@ export const createPocketbaseClient = (config: PocketbaseClientConfig) => {
|
||||
})
|
||||
)
|
||||
|
||||
const confirmVerification = safeCatch(`confirmVerification`, (token: string) =>
|
||||
const confirmVerification = safeCatch(`confirmVerification`, _logger, (token: string) =>
|
||||
client
|
||||
.collection('users')
|
||||
.confirmVerification(token)
|
||||
@ -79,7 +80,7 @@ export const createPocketbaseClient = (config: PocketbaseClientConfig) => {
|
||||
})
|
||||
)
|
||||
|
||||
const requestPasswordReset = safeCatch(`requestPasswordReset`, (email: string) =>
|
||||
const requestPasswordReset = safeCatch(`requestPasswordReset`, _logger, (email: string) =>
|
||||
client
|
||||
.collection('users')
|
||||
.requestPasswordReset(email)
|
||||
@ -90,6 +91,7 @@ export const createPocketbaseClient = (config: PocketbaseClientConfig) => {
|
||||
|
||||
const requestPasswordResetConfirm = safeCatch(
|
||||
`requestPasswordResetConfirm`,
|
||||
_logger,
|
||||
(token: string, password: string) =>
|
||||
client
|
||||
.collection('users')
|
||||
@ -99,11 +101,11 @@ export const createPocketbaseClient = (config: PocketbaseClientConfig) => {
|
||||
})
|
||||
)
|
||||
|
||||
const authViaEmail = safeCatch(`authViaEmail`, (email: string, password: string) =>
|
||||
const authViaEmail = safeCatch(`authViaEmail`, _logger, (email: string, password: string) =>
|
||||
client.collection('users').authWithPassword(email, password)
|
||||
)
|
||||
|
||||
const refreshAuthToken = safeCatch(`refreshAuthToken`, () =>
|
||||
const refreshAuthToken = safeCatch(`refreshAuthToken`, _logger, () =>
|
||||
client.collection('users').authRefresh()
|
||||
)
|
||||
|
||||
@ -123,6 +125,7 @@ export const createPocketbaseClient = (config: PocketbaseClientConfig) => {
|
||||
|
||||
const getInstanceById = safeCatch(
|
||||
`getInstanceById`,
|
||||
_logger,
|
||||
(id: InstanceId): Promise<InstanceFields | undefined> =>
|
||||
client.collection('instances').getOne<InstanceFields>(id)
|
||||
)
|
||||
@ -145,7 +148,7 @@ export const createPocketbaseClient = (config: PocketbaseClientConfig) => {
|
||||
return map(e.data.data, (v, k) => (v ? v.message : undefined)).filter((v) => !!v)
|
||||
}
|
||||
|
||||
const resendVerificationEmail = safeCatch(`resendVerificationEmail`, async () => {
|
||||
const resendVerificationEmail = safeCatch(`resendVerificationEmail`, _logger, async () => {
|
||||
const user = client.authStore.model
|
||||
assertExists(user, `Login required`)
|
||||
await client.collection('users').requestVerification(user.email)
|
||||
@ -210,7 +213,7 @@ export const createPocketbaseClient = (config: PocketbaseClientConfig) => {
|
||||
unsub()
|
||||
return
|
||||
}
|
||||
const _check = safeCatch(`_checkVerified`, refreshAuthToken)
|
||||
const _check = safeCatch(`_checkVerified`, _logger, refreshAuthToken)
|
||||
setTimeout(_check, 1000)
|
||||
|
||||
// FIXME - THIS DOES NOT WORK, WE HAVE TO POLL INSTEAD. FIX IN V0.8
|
||||
|
Loading…
x
Reference in New Issue
Block a user