@dxos/phoenix 0.1.58-main.5e5d64f → 0.1.58-main.60c63b5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib/node/index.cjs
CHANGED
|
@@ -41,20 +41,21 @@ var import_node_fs2 = require("node:fs");
|
|
|
41
41
|
var import_promises = require("node:fs/promises");
|
|
42
42
|
var import_node_path = require("node:path");
|
|
43
43
|
var import_pkg_up = __toESM(require("pkg-up"));
|
|
44
|
+
var import_async2 = require("@dxos/async");
|
|
44
45
|
var import_invariant = require("@dxos/invariant");
|
|
46
|
+
var import_keys = require("@dxos/keys");
|
|
45
47
|
var import_lock_file2 = require("@dxos/lock-file");
|
|
46
48
|
var import_log = require("@dxos/log");
|
|
47
49
|
|
|
48
|
-
// packages/common/phoenix/src/utils.ts
|
|
49
|
-
var import_node_fs = require("node:fs");
|
|
50
|
-
var import_async = require("@dxos/async");
|
|
51
|
-
var import_lock_file = require("@dxos/lock-file");
|
|
52
|
-
|
|
53
50
|
// packages/common/phoenix/src/defs.ts
|
|
54
51
|
var LOCK_TIMEOUT = 1e3;
|
|
55
52
|
var LOCK_CHECK_INTERVAL = 50;
|
|
53
|
+
var DAEMON_START_TIMEOUT = 1e4;
|
|
56
54
|
|
|
57
55
|
// packages/common/phoenix/src/utils.ts
|
|
56
|
+
var import_node_fs = require("node:fs");
|
|
57
|
+
var import_async = require("@dxos/async");
|
|
58
|
+
var import_lock_file = require("@dxos/lock-file");
|
|
58
59
|
var waitForLockAcquisition = async (lockFile) => (0, import_async.waitForCondition)({
|
|
59
60
|
condition: async () => await import_lock_file.LockFile.isLocked(lockFile),
|
|
60
61
|
timeout: LOCK_TIMEOUT,
|
|
@@ -104,14 +105,16 @@ var DaemonManager = class {
|
|
|
104
105
|
async start(params) {
|
|
105
106
|
(0, import_invariant.invariant)(params.command, "command is required", {
|
|
106
107
|
F: __dxlog_file,
|
|
107
|
-
L:
|
|
108
|
+
L: 49,
|
|
108
109
|
S: this,
|
|
109
110
|
A: [
|
|
110
111
|
"params.command",
|
|
111
112
|
"'command is required'"
|
|
112
113
|
]
|
|
113
114
|
});
|
|
115
|
+
const watchdogId = import_keys.PublicKey.random().toHex();
|
|
114
116
|
const watchDogParams = {
|
|
117
|
+
watchdogId,
|
|
115
118
|
...this._getConfigFiles(params.uid),
|
|
116
119
|
...params
|
|
117
120
|
};
|
|
@@ -135,6 +138,7 @@ var DaemonManager = class {
|
|
|
135
138
|
const watchDog = (0, import_node_child_process.fork)(watchdogPath, [
|
|
136
139
|
JSON.stringify(watchDogParams)
|
|
137
140
|
], {
|
|
141
|
+
stdio: "pipe",
|
|
138
142
|
detached: true,
|
|
139
143
|
cwd: __dirname
|
|
140
144
|
});
|
|
@@ -145,12 +149,19 @@ var DaemonManager = class {
|
|
|
145
149
|
signal
|
|
146
150
|
}, {
|
|
147
151
|
F: __dxlog_file,
|
|
148
|
-
L:
|
|
152
|
+
L: 81,
|
|
149
153
|
S: this,
|
|
150
154
|
C: (f, a) => f(...a)
|
|
151
155
|
});
|
|
152
156
|
}
|
|
153
157
|
});
|
|
158
|
+
const started = new import_async2.Trigger();
|
|
159
|
+
watchDog.stdout.on("data", (data) => {
|
|
160
|
+
if (String(data).includes(watchdogId)) {
|
|
161
|
+
started.wake();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
await (0, import_async2.asyncTimeout)(started.wait(), DAEMON_START_TIMEOUT);
|
|
154
165
|
await waitForLockAcquisition(watchDogParams.lockFile);
|
|
155
166
|
await waitForLockFileBeingFilledWithInfo(watchDogParams.lockFile);
|
|
156
167
|
watchDog.disconnect();
|
|
@@ -171,7 +182,7 @@ var DaemonManager = class {
|
|
|
171
182
|
} catch (err) {
|
|
172
183
|
(0, import_invariant.invariant)(err instanceof Error, "Invalid error type.", {
|
|
173
184
|
F: __dxlog_file,
|
|
174
|
-
L:
|
|
185
|
+
L: 112,
|
|
175
186
|
S: this,
|
|
176
187
|
A: [
|
|
177
188
|
"err instanceof Error",
|
|
@@ -186,7 +197,7 @@ var DaemonManager = class {
|
|
|
186
197
|
return this.getInfo(uid);
|
|
187
198
|
}
|
|
188
199
|
async list() {
|
|
189
|
-
const uids =
|
|
200
|
+
const uids = await (0, import_promises.readdir)((0, import_node_path.join)(this._rootPath, "profile"));
|
|
190
201
|
return Promise.all(uids.map(async (uid) => {
|
|
191
202
|
return this.getInfo(uid);
|
|
192
203
|
}));
|
|
@@ -222,7 +233,7 @@ var import_node_child_process2 = require("node:child_process");
|
|
|
222
233
|
var import_node_fs3 = require("node:fs");
|
|
223
234
|
var import_node_util = require("node:util");
|
|
224
235
|
var import_ps_tree = __toESM(require("ps-tree"));
|
|
225
|
-
var
|
|
236
|
+
var import_async3 = require("@dxos/async");
|
|
226
237
|
var import_context = require("@dxos/context");
|
|
227
238
|
var import_invariant2 = require("@dxos/invariant");
|
|
228
239
|
var import_lock_file3 = require("@dxos/lock-file");
|
|
@@ -428,13 +439,13 @@ var WatchDog = class {
|
|
|
428
439
|
}
|
|
429
440
|
};
|
|
430
441
|
_ts_decorate([
|
|
431
|
-
|
|
442
|
+
import_async3.synchronized
|
|
432
443
|
], WatchDog.prototype, "start", null);
|
|
433
444
|
_ts_decorate([
|
|
434
|
-
|
|
445
|
+
import_async3.synchronized
|
|
435
446
|
], WatchDog.prototype, "stop", null);
|
|
436
447
|
_ts_decorate([
|
|
437
|
-
|
|
448
|
+
import_async3.synchronized
|
|
438
449
|
], WatchDog.prototype, "kill", null);
|
|
439
450
|
// Annotate the CommonJS export names for ESM import in node:
|
|
440
451
|
0 && (module.exports = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../src/index.ts", "../../../src/daemon-manager.ts", "../../../src/
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n// Inspired by https://github.com/foreversd/forever\n// Their copyright notice is included below.\n// Copyright (C) 2010 Charlie Robbins & the Contributors\n//\n\nexport * from './daemon-manager';\nexport * from './watchdog';\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { fork } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, unlinkSync } from 'node:fs';\nimport { readdir } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport pkgUp from 'pkg-up';\n\nimport { invariant } from '@dxos/invariant';\nimport { LockFile } from '@dxos/lock-file';\nimport { log } from '@dxos/log';\n\nimport { waitForLockAcquisition, waitForLockFileBeingFilledWithInfo, waitForLockRelease } from './utils';\nimport { ChildParams, Logs, Lock, ProcessInfo, WatchDogParams } from './watchdog';\n\nconst LOCK_FILE_NAME = 'lockfile';\n\n/**\n * Params to start a daemon.\n * User have no control over the lock file.\n */\nexport type StartParams = ChildParams & Partial<Logs>;\n\nexport class DaemonManager {\n constructor(private readonly _rootPath: string) {\n if (!existsSync(join(_rootPath, 'profile'))) {\n mkdirSync(join(_rootPath, 'profile'), { recursive: true });\n }\n }\n\n private _getConfigFiles(uid: string): Logs & Lock {\n const defaultConfigDir = join(this._rootPath, 'profile', uid);\n if (!existsSync(defaultConfigDir)) {\n mkdirSync(defaultConfigDir, { recursive: true });\n }\n return {\n lockFile: join(defaultConfigDir, LOCK_FILE_NAME),\n logFile: join(defaultConfigDir, 'file.log'),\n errFile: join(defaultConfigDir, 'err.log'),\n };\n }\n\n async start(params: StartParams) {\n invariant(params.command, 'command is required');\n const watchDogParams: WatchDogParams = {\n ...this._getConfigFiles(params.uid),\n ...params,\n };\n\n {\n // Create log folders.\n mkdirSync(dirname(watchDogParams.logFile), { recursive: true });\n mkdirSync(dirname(watchDogParams.errFile), { recursive: true });\n }\n\n {\n // Clear stale lock file if process is not running.\n if (await LockFile.isLocked(watchDogParams.lockFile)) {\n throw new Error('Lock file is already locked.');\n }\n unlinkSync(watchDogParams.lockFile);\n }\n\n const watchdogPath = join(dirname(pkgUp.sync({ cwd: __dirname })!), 'bin', 'watchdog');\n\n const watchDog = fork(watchdogPath, [JSON.stringify(watchDogParams)], {\n detached: true,\n cwd: __dirname,\n });\n\n watchDog.on('exit', (code, signal) => {\n if (code && code !== 0) {\n log.error('Monitor died unexpectedly', { code, signal });\n }\n });\n\n await waitForLockAcquisition(watchDogParams.lockFile);\n await waitForLockFileBeingFilledWithInfo(watchDogParams.lockFile);\n\n watchDog.disconnect();\n watchDog.unref();\n\n return this.getInfo(params.uid);\n }\n\n async stop(uid: string, force?: boolean) {\n const lockFile = this._getConfigFiles(uid).lockFile;\n const processInfo = JSON.parse(readFileSync(lockFile, { encoding: 'utf-8' }));\n try {\n if (force) {\n process.kill(processInfo.pid, 'SIGKILL');\n } else {\n process.kill(processInfo.pid, 'SIGINT');\n }\n } catch (err) {\n invariant(err instanceof Error, 'Invalid error type.');\n if (!err.name.includes('ESRCH') && !err.message.includes('ESRCH')) {\n throw err;\n }\n }\n await waitForLockRelease(lockFile);\n\n return this.getInfo(uid);\n }\n\n async list(): Promise<ProcessInfo[]> {\n const uids = (await readdir(join(this._rootPath, 'profile'))).filter((uid) => !uid.startsWith('.'));\n\n return Promise.all(\n uids.map(async (uid) => {\n return this.getInfo(uid);\n }),\n );\n }\n\n async getInfo(uid: string): Promise<ProcessInfo> {\n const files = this._getConfigFiles(uid);\n\n let info: ProcessInfo = { running: await LockFile.isLocked(files.lockFile), uid, ...files };\n if (existsSync(files.lockFile)) {\n try {\n info = {\n ...info,\n ...JSON.parse(readFileSync(files.lockFile, { encoding: 'utf-8' })),\n };\n } catch (err) {}\n }\n\n return info;\n }\n\n async isRunning(uid: string): Promise<boolean> {\n const lockFile = this._getConfigFiles(uid).lockFile;\n return LockFile.isLocked(lockFile);\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { readFileSync } from 'node:fs';\n\nimport { waitForCondition } from '@dxos/async';\nimport { LockFile } from '@dxos/lock-file';\n\nimport { LOCK_CHECK_INTERVAL, LOCK_TIMEOUT } from './defs';\n\nexport const waitForLockAcquisition = async (lockFile: string) =>\n waitForCondition({\n condition: async () => await LockFile.isLocked(lockFile),\n timeout: LOCK_TIMEOUT,\n interval: LOCK_CHECK_INTERVAL,\n error: new Error('Lock file is not being acquired.'),\n });\n\nexport const waitForLockFileBeingFilledWithInfo = async (lockFile: string) =>\n waitForCondition({\n condition: () => readFileSync(lockFile, { encoding: 'utf-8' }).includes('pid'),\n timeout: LOCK_TIMEOUT,\n interval: LOCK_CHECK_INTERVAL,\n error: new Error('Lock file is not being propagated with info.'),\n });\n\nexport const waitForLockRelease = async (lockFile: string) =>\n waitForCondition({\n condition: async () => !(await LockFile.isLocked(lockFile)),\n timeout: LOCK_TIMEOUT,\n interval: LOCK_CHECK_INTERVAL,\n error: new Error('Lock file is not being released.'),\n });\n", "//\n// Copyright 2023 DXOS.org\n//\n\nexport const LOCK_TIMEOUT = 1_000;\nexport const LOCK_CHECK_INTERVAL = 50;\nexport const DAEMON_START_TIMEOUT = 10_000;\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport { writeFileSync } from 'node:fs';\nimport { FileHandle } from 'node:fs/promises';\nimport { promisify } from 'node:util';\nimport psTree from 'ps-tree';\n\nimport { synchronized } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { LockFile } from '@dxos/lock-file';\nimport { log } from '@dxos/log';\n\nimport { waitForLockAcquisition, waitForLockRelease } from './utils';\n\nexport type DaemonInfo = {\n pid: number;\n command: string;\n args: string[];\n cwd: string;\n timestamp: number;\n};\n\nexport type ProcessInfo = WatchDogParams & {\n pid?: number;\n timestamp?: number;\n restarts?: number;\n running?: boolean;\n};\n\nexport type Lock = {\n lockFile: string; // Path to lock file\n};\n\nexport type Logs = {\n //\n // Log files and associated logging options for this instance\n //\n logFile: string; // Path to log output all logs\n errFile: string; // Path to log output from child stderr\n};\n\nexport type ChildParams = {\n uid: string; // Unique identifier for this instance\n\n //\n // Basic configuration options\n //\n maxRestarts?: number | undefined; // Sets the maximum number of times a given script should run\n killTree?: boolean | undefined; // Kills the entire child process tree on `exit`\n\n //\n // Command to spawn as well as options and other vars\n // (env, cwd, etc) to pass along\n //\n command?: string; // Binary to run (default: 'node')\n args?: string[] | undefined; // Additional arguments to pass to the script,\n\n //\n // More specific options to pass along to `child_process.spawn` which\n // will override anything passed to the `spawnWith` option\n //\n env?: NodeJS.ProcessEnv | undefined;\n cwd?: string | undefined;\n shell?: boolean | undefined;\n};\n\nexport type WatchDogParams = ChildParams & Lock & Logs;\n\nexport class WatchDog {\n private _lock?: FileHandle;\n private _child?: ChildProcessWithoutNullStreams;\n private _restarts = 0;\n private _processCtx?: Context;\n\n constructor(private readonly _params: WatchDogParams) {}\n\n @synchronized\n async start() {\n await this._acquireLock();\n this._log('Lock acquired.');\n const { cwd, shell, env, command, args } = { cwd: process.cwd(), ...this._params };\n invariant(command, 'Command is not defined.');\n\n this._log(`Spawning process ${command} ${args?.join(' ')}`);\n this._child = spawn(command, args, { cwd, shell, env, stdio: 'pipe' });\n this._processCtx = new Context();\n\n const childInfo: ProcessInfo = {\n pid: process.pid,\n timestamp: Date.now(),\n restarts: this._restarts,\n ...this._params,\n };\n\n writeFileSync(this._params.lockFile, JSON.stringify(childInfo, undefined, 2), { encoding: 'utf-8' });\n\n this._child.stdout.on('data', (data: Uint8Array) => {\n this._log(String(data));\n });\n this._child.stderr.on('data', (data: Uint8Array) => {\n this._err(data);\n });\n\n // Setup restart handler.\n {\n const restartHandler = async (code: number, signal: number | NodeJS.Signals) => {\n if (code && code !== 0) {\n this._err(`Died unexpectedly with exit code ${code} (signal: ${signal}).`);\n await this.restart();\n }\n };\n\n this._child.on('close', restartHandler);\n\n // We should unsubscribe from the event when the process is killed by us to not try to restart it.\n this._processCtx.onDispose(() => {\n this._child!.off('close', restartHandler);\n });\n }\n\n this._child.on('close', (code: number, signal: number | NodeJS.Signals) => {\n this._log(`Stopped with exit code ${code} (signal: ${signal}).`);\n });\n\n invariant(this._child.pid, 'Child process has no pid.');\n this._log(`Started with pid ${this._child.pid}.`);\n }\n\n /**\n * Sends SIGINT to the child process and the tree it spawned (if `killTree` param is `true`).\n */\n @synchronized\n async stop() {\n if (!this._child) {\n return;\n }\n\n await this._killWithSignal('SIGKILL');\n\n await this._releaseLock();\n }\n\n /**\n * Sends SIGKILL to the child process and the tree it spawned (if `killTree` param is `true`).\n */\n @synchronized\n async kill() {\n if (!this._child) {\n return;\n }\n\n await this._killWithSignal('SIGKILL');\n\n await this._releaseLock();\n }\n\n async restart() {\n await this.kill();\n if (this._params.maxRestarts !== undefined && this._restarts >= this._params.maxRestarts) {\n this._err('Max restarts number is reached');\n } else {\n log('Restarting...');\n this._restarts++;\n await this.start();\n }\n }\n\n async _killWithSignal(signal: number | NodeJS.Signals) {\n invariant(this._processCtx, 'Process context is not defined.');\n await this._processCtx.dispose();\n\n // Kill child process tree.\n if (this._params.killTree) {\n if (process.platform !== 'win32') {\n invariant(this._child?.pid, 'Child process has no pid.');\n const children = await promisify(psTree)(this._child.pid);\n children\n .map((p) => p.PID)\n .forEach((tpid) => {\n invariant(tpid, 'Process id is not defined.');\n process.kill(Number(tpid), signal);\n });\n }\n }\n\n invariant(this._child?.pid, 'Child process has no pid.');\n this._child.kill(signal);\n this._child = undefined;\n }\n\n private async _acquireLock() {\n if (await LockFile.isLocked(this._params.lockFile)) {\n throw new Error('Lock file is already locked.');\n }\n this._lock = await LockFile.acquire(this._params.lockFile);\n await waitForLockAcquisition(this._params.lockFile);\n }\n\n private async _releaseLock() {\n invariant(this._lock, 'Lock is not defined.');\n\n await LockFile.release(this._lock);\n await waitForLockRelease(this._params.lockFile);\n\n this._lock = undefined;\n }\n\n private _log(message: string | Uint8Array) {\n writeFileSync(this._params.logFile, message + '\\n', {\n flag: 'a+',\n encoding: 'utf-8',\n });\n }\n\n private _err(message: string | Uint8Array) {\n this._log(message);\n writeFileSync(this._params.errFile, message + '\\n', {\n flag: 'a+',\n encoding: 'utf-8',\n });\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;ACIA,gCAAqB;AACrB,IAAAA,kBAAgE;AAChE,sBAAwB;AACxB,uBAA8B;AAC9B,oBAAkB;AAElB,uBAA0B;AAC1B,IAAAC,oBAAyB;AACzB,iBAAoB;;;
|
|
6
|
-
"names": ["import_node_fs", "import_lock_file", "LOCK_TIMEOUT", "LOCK_CHECK_INTERVAL", "waitForLockAcquisition", "lockFile", "waitForCondition", "condition", "LockFile", "isLocked", "timeout", "LOCK_TIMEOUT", "interval", "LOCK_CHECK_INTERVAL", "error", "Error", "waitForLockFileBeingFilledWithInfo", "readFileSync", "encoding", "includes", "waitForLockRelease", "LOCK_FILE_NAME", "DaemonManager", "constructor", "_rootPath", "existsSync", "join", "mkdirSync", "recursive", "_getConfigFiles", "uid", "defaultConfigDir", "lockFile", "logFile", "errFile", "start", "params", "invariant", "command", "watchDogParams", "dirname", "LockFile", "isLocked", "Error", "unlinkSync", "watchdogPath", "pkgUp", "sync", "cwd", "__dirname", "watchDog", "fork", "JSON", "stringify", "detached", "on", "code", "signal", "log", "error", "waitForLockAcquisition", "waitForLockFileBeingFilledWithInfo", "disconnect", "unref", "getInfo", "stop", "force", "processInfo", "parse", "readFileSync", "encoding", "process", "kill", "pid", "err", "name", "
|
|
3
|
+
"sources": ["../../../src/index.ts", "../../../src/daemon-manager.ts", "../../../src/defs.ts", "../../../src/utils.ts", "../../../src/watchdog.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n// Inspired by https://github.com/foreversd/forever\n// Their copyright notice is included below.\n// Copyright (C) 2010 Charlie Robbins & the Contributors\n//\n\nexport * from './daemon-manager';\nexport * from './watchdog';\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { fork } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, unlinkSync } from 'node:fs';\nimport { readdir } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport pkgUp from 'pkg-up';\n\nimport { Trigger, asyncTimeout } from '@dxos/async';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { LockFile } from '@dxos/lock-file';\nimport { log } from '@dxos/log';\n\nimport { DAEMON_START_TIMEOUT } from './defs';\nimport { waitForLockAcquisition, waitForLockFileBeingFilledWithInfo, waitForLockRelease } from './utils';\nimport { ChildParams, Logs, Lock, ProcessInfo, WatchDogParams } from './watchdog';\n\nconst LOCK_FILE_NAME = 'lockfile';\n\n/**\n * Params to start a daemon.\n * User have no control over the lock file.\n */\nexport type StartParams = ChildParams & Partial<Logs>;\n\nexport class DaemonManager {\n constructor(private readonly _rootPath: string) {\n if (!existsSync(join(_rootPath, 'profile'))) {\n mkdirSync(join(_rootPath, 'profile'), { recursive: true });\n }\n }\n\n private _getConfigFiles(uid: string): Logs & Lock {\n const defaultConfigDir = join(this._rootPath, 'profile', uid);\n if (!existsSync(defaultConfigDir)) {\n mkdirSync(defaultConfigDir, { recursive: true });\n }\n return {\n lockFile: join(defaultConfigDir, LOCK_FILE_NAME),\n logFile: join(defaultConfigDir, 'file.log'),\n errFile: join(defaultConfigDir, 'err.log'),\n };\n }\n\n async start(params: StartParams) {\n invariant(params.command, 'command is required');\n const watchdogId = PublicKey.random().toHex();\n const watchDogParams: WatchDogParams & { watchdogId: string } = {\n watchdogId,\n ...this._getConfigFiles(params.uid),\n ...params,\n };\n\n {\n // Create log folders.\n mkdirSync(dirname(watchDogParams.logFile), { recursive: true });\n mkdirSync(dirname(watchDogParams.errFile), { recursive: true });\n }\n\n {\n // Clear stale lock file if process is not running.\n if (await LockFile.isLocked(watchDogParams.lockFile)) {\n throw new Error('Lock file is already locked.');\n }\n unlinkSync(watchDogParams.lockFile);\n }\n\n const watchdogPath = join(dirname(pkgUp.sync({ cwd: __dirname })!), 'bin', 'watchdog');\n\n const watchDog = fork(watchdogPath, [JSON.stringify(watchDogParams)], {\n stdio: 'pipe',\n detached: true,\n cwd: __dirname,\n });\n\n watchDog.on('exit', (code, signal) => {\n if (code && code !== 0) {\n log.error('Monitor died unexpectedly', { code, signal });\n }\n });\n\n const started = new Trigger();\n watchDog.stdout!.on('data', (data) => {\n if (String(data).includes(watchdogId)) {\n started.wake();\n }\n });\n\n await asyncTimeout(started.wait(), DAEMON_START_TIMEOUT);\n await waitForLockAcquisition(watchDogParams.lockFile);\n await waitForLockFileBeingFilledWithInfo(watchDogParams.lockFile);\n\n watchDog.disconnect();\n watchDog.unref();\n\n return this.getInfo(params.uid);\n }\n\n async stop(uid: string, force?: boolean) {\n const lockFile = this._getConfigFiles(uid).lockFile;\n const processInfo = JSON.parse(readFileSync(lockFile, { encoding: 'utf-8' }));\n try {\n if (force) {\n process.kill(processInfo.pid, 'SIGKILL');\n } else {\n process.kill(processInfo.pid, 'SIGINT');\n }\n } catch (err) {\n invariant(err instanceof Error, 'Invalid error type.');\n if (!err.name.includes('ESRCH') && !err.message.includes('ESRCH')) {\n throw err;\n }\n }\n await waitForLockRelease(lockFile);\n\n return this.getInfo(uid);\n }\n\n async list(): Promise<ProcessInfo[]> {\n const uids = await readdir(join(this._rootPath, 'profile'));\n return Promise.all(\n uids.map(async (uid) => {\n return this.getInfo(uid);\n }),\n );\n }\n\n async getInfo(uid: string): Promise<ProcessInfo> {\n const files = this._getConfigFiles(uid);\n\n let info: ProcessInfo = { running: await LockFile.isLocked(files.lockFile), uid, ...files };\n if (existsSync(files.lockFile)) {\n try {\n info = {\n ...info,\n ...JSON.parse(readFileSync(files.lockFile, { encoding: 'utf-8' })),\n };\n } catch (err) {}\n }\n\n return info;\n }\n\n async isRunning(uid: string): Promise<boolean> {\n const lockFile = this._getConfigFiles(uid).lockFile;\n return LockFile.isLocked(lockFile);\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\nexport const LOCK_TIMEOUT = 1_000;\nexport const LOCK_CHECK_INTERVAL = 50;\nexport const DAEMON_START_TIMEOUT = 10_000;\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { readFileSync } from 'node:fs';\n\nimport { waitForCondition } from '@dxos/async';\nimport { LockFile } from '@dxos/lock-file';\n\nimport { LOCK_CHECK_INTERVAL, LOCK_TIMEOUT } from './defs';\n\nexport const waitForLockAcquisition = async (lockFile: string) =>\n waitForCondition({\n condition: async () => await LockFile.isLocked(lockFile),\n timeout: LOCK_TIMEOUT,\n interval: LOCK_CHECK_INTERVAL,\n error: new Error('Lock file is not being acquired.'),\n });\n\nexport const waitForLockFileBeingFilledWithInfo = async (lockFile: string) =>\n waitForCondition({\n condition: () => readFileSync(lockFile, { encoding: 'utf-8' }).includes('pid'),\n timeout: LOCK_TIMEOUT,\n interval: LOCK_CHECK_INTERVAL,\n error: new Error('Lock file is not being propagated with info.'),\n });\n\nexport const waitForLockRelease = async (lockFile: string) =>\n waitForCondition({\n condition: async () => !(await LockFile.isLocked(lockFile)),\n timeout: LOCK_TIMEOUT,\n interval: LOCK_CHECK_INTERVAL,\n error: new Error('Lock file is not being released.'),\n });\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport { writeFileSync } from 'node:fs';\nimport { FileHandle } from 'node:fs/promises';\nimport { promisify } from 'node:util';\nimport psTree from 'ps-tree';\n\nimport { synchronized } from '@dxos/async';\nimport { Context } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { LockFile } from '@dxos/lock-file';\nimport { log } from '@dxos/log';\n\nimport { waitForLockAcquisition, waitForLockRelease } from './utils';\n\nexport type DaemonInfo = {\n pid: number;\n command: string;\n args: string[];\n cwd: string;\n timestamp: number;\n};\n\nexport type ProcessInfo = WatchDogParams & {\n pid?: number;\n timestamp?: number;\n restarts?: number;\n running?: boolean;\n};\n\nexport type Lock = {\n lockFile: string; // Path to lock file\n};\n\nexport type Logs = {\n //\n // Log files and associated logging options for this instance\n //\n logFile: string; // Path to log output all logs\n errFile: string; // Path to log output from child stderr\n};\n\nexport type ChildParams = {\n uid: string; // Unique identifier for this instance\n\n //\n // Basic configuration options\n //\n maxRestarts?: number | undefined; // Sets the maximum number of times a given script should run\n killTree?: boolean | undefined; // Kills the entire child process tree on `exit`\n\n //\n // Command to spawn as well as options and other vars\n // (env, cwd, etc) to pass along\n //\n command?: string; // Binary to run (default: 'node')\n args?: string[] | undefined; // Additional arguments to pass to the script,\n\n //\n // More specific options to pass along to `child_process.spawn` which\n // will override anything passed to the `spawnWith` option\n //\n env?: NodeJS.ProcessEnv | undefined;\n cwd?: string | undefined;\n shell?: boolean | undefined;\n};\n\nexport type WatchDogParams = ChildParams & Lock & Logs;\n\nexport class WatchDog {\n private _lock?: FileHandle;\n private _child?: ChildProcessWithoutNullStreams;\n private _restarts = 0;\n private _processCtx?: Context;\n\n constructor(private readonly _params: WatchDogParams) {}\n\n @synchronized\n async start() {\n await this._acquireLock();\n this._log('Lock acquired.');\n const { cwd, shell, env, command, args } = { cwd: process.cwd(), ...this._params };\n invariant(command, 'Command is not defined.');\n\n this._log(`Spawning process ${command} ${args?.join(' ')}`);\n this._child = spawn(command, args, { cwd, shell, env, stdio: 'pipe' });\n this._processCtx = new Context();\n\n const childInfo: ProcessInfo = {\n pid: process.pid,\n timestamp: Date.now(),\n restarts: this._restarts,\n ...this._params,\n };\n\n writeFileSync(this._params.lockFile, JSON.stringify(childInfo, undefined, 2), { encoding: 'utf-8' });\n\n this._child.stdout.on('data', (data: Uint8Array) => {\n this._log(String(data));\n });\n this._child.stderr.on('data', (data: Uint8Array) => {\n this._err(data);\n });\n\n // Setup restart handler.\n {\n const restartHandler = async (code: number, signal: number | NodeJS.Signals) => {\n if (code && code !== 0) {\n this._err(`Died unexpectedly with exit code ${code} (signal: ${signal}).`);\n await this.restart();\n }\n };\n\n this._child.on('close', restartHandler);\n\n // We should unsubscribe from the event when the process is killed by us to not try to restart it.\n this._processCtx.onDispose(() => {\n this._child!.off('close', restartHandler);\n });\n }\n\n this._child.on('close', (code: number, signal: number | NodeJS.Signals) => {\n this._log(`Stopped with exit code ${code} (signal: ${signal}).`);\n });\n\n invariant(this._child.pid, 'Child process has no pid.');\n this._log(`Started with pid ${this._child.pid}.`);\n }\n\n /**\n * Sends SIGINT to the child process and the tree it spawned (if `killTree` param is `true`).\n */\n @synchronized\n async stop() {\n if (!this._child) {\n return;\n }\n\n await this._killWithSignal('SIGKILL');\n\n await this._releaseLock();\n }\n\n /**\n * Sends SIGKILL to the child process and the tree it spawned (if `killTree` param is `true`).\n */\n @synchronized\n async kill() {\n if (!this._child) {\n return;\n }\n\n await this._killWithSignal('SIGKILL');\n\n await this._releaseLock();\n }\n\n async restart() {\n await this.kill();\n if (this._params.maxRestarts !== undefined && this._restarts >= this._params.maxRestarts) {\n this._err('Max restarts number is reached');\n } else {\n log('Restarting...');\n this._restarts++;\n await this.start();\n }\n }\n\n async _killWithSignal(signal: number | NodeJS.Signals) {\n invariant(this._processCtx, 'Process context is not defined.');\n await this._processCtx.dispose();\n\n // Kill child process tree.\n if (this._params.killTree) {\n if (process.platform !== 'win32') {\n invariant(this._child?.pid, 'Child process has no pid.');\n const children = await promisify(psTree)(this._child.pid);\n children\n .map((p) => p.PID)\n .forEach((tpid) => {\n invariant(tpid, 'Process id is not defined.');\n process.kill(Number(tpid), signal);\n });\n }\n }\n\n invariant(this._child?.pid, 'Child process has no pid.');\n this._child.kill(signal);\n this._child = undefined;\n }\n\n private async _acquireLock() {\n if (await LockFile.isLocked(this._params.lockFile)) {\n throw new Error('Lock file is already locked.');\n }\n this._lock = await LockFile.acquire(this._params.lockFile);\n await waitForLockAcquisition(this._params.lockFile);\n }\n\n private async _releaseLock() {\n invariant(this._lock, 'Lock is not defined.');\n\n await LockFile.release(this._lock);\n await waitForLockRelease(this._params.lockFile);\n\n this._lock = undefined;\n }\n\n private _log(message: string | Uint8Array) {\n writeFileSync(this._params.logFile, message + '\\n', {\n flag: 'a+',\n encoding: 'utf-8',\n });\n }\n\n private _err(message: string | Uint8Array) {\n this._log(message);\n writeFileSync(this._params.errFile, message + '\\n', {\n flag: 'a+',\n encoding: 'utf-8',\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_node_fs", "import_async", "import_lock_file", "LOCK_TIMEOUT", "LOCK_CHECK_INTERVAL", "DAEMON_START_TIMEOUT", "waitForLockAcquisition", "lockFile", "waitForCondition", "condition", "LockFile", "isLocked", "timeout", "LOCK_TIMEOUT", "interval", "LOCK_CHECK_INTERVAL", "error", "Error", "waitForLockFileBeingFilledWithInfo", "readFileSync", "encoding", "includes", "waitForLockRelease", "LOCK_FILE_NAME", "DaemonManager", "constructor", "_rootPath", "existsSync", "join", "mkdirSync", "recursive", "_getConfigFiles", "uid", "defaultConfigDir", "lockFile", "logFile", "errFile", "start", "params", "invariant", "command", "watchdogId", "PublicKey", "random", "toHex", "watchDogParams", "dirname", "LockFile", "isLocked", "Error", "unlinkSync", "watchdogPath", "pkgUp", "sync", "cwd", "__dirname", "watchDog", "fork", "JSON", "stringify", "stdio", "detached", "on", "code", "signal", "log", "error", "started", "Trigger", "stdout", "data", "String", "includes", "wake", "asyncTimeout", "wait", "DAEMON_START_TIMEOUT", "waitForLockAcquisition", "waitForLockFileBeingFilledWithInfo", "disconnect", "unref", "getInfo", "stop", "force", "processInfo", "parse", "readFileSync", "encoding", "process", "kill", "pid", "err", "name", "message", "waitForLockRelease", "list", "uids", "readdir", "Promise", "all", "map", "files", "info", "running", "isRunning", "import_node_child_process", "import_node_fs", "import_async", "import_invariant", "import_lock_file", "import_log", "WatchDog", "constructor", "_params", "_restarts", "start", "_acquireLock", "_log", "cwd", "shell", "env", "command", "args", "process", "invariant", "join", "_child", "spawn", "stdio", "_processCtx", "Context", "childInfo", "pid", "timestamp", "Date", "now", "restarts", "writeFileSync", "lockFile", "JSON", "stringify", "undefined", "encoding", "stdout", "on", "data", "String", "stderr", "_err", "restartHandler", "code", "signal", "restart", "onDispose", "off", "stop", "_killWithSignal", "_releaseLock", "kill", "maxRestarts", "log", "dispose", "killTree", "platform", "children", "promisify", "psTree", "map", "p", "PID", "forEach", "tpid", "Number", "LockFile", "isLocked", "Error", "_lock", "acquire", "waitForLockAcquisition", "release", "waitForLockRelease", "message", "logFile", "flag", "errFile", "synchronized"]
|
|
7
7
|
}
|
package/dist/lib/node/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/common/phoenix/src/defs.ts":{"bytes":844,"imports":[],"format":"esm"},"packages/common/phoenix/src/utils.ts":{"bytes":4044,"imports":[{"path":"node:fs","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/lock-file","kind":"import-statement","external":true},{"path":"packages/common/phoenix/src/defs.ts","kind":"import-statement","original":"./defs"}],"format":"esm"},"packages/common/phoenix/src/daemon-manager.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/common/phoenix/src/defs.ts":{"bytes":844,"imports":[],"format":"esm"},"packages/common/phoenix/src/utils.ts":{"bytes":4044,"imports":[{"path":"node:fs","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/lock-file","kind":"import-statement","external":true},{"path":"packages/common/phoenix/src/defs.ts","kind":"import-statement","original":"./defs"}],"format":"esm"},"packages/common/phoenix/src/daemon-manager.ts":{"bytes":17255,"imports":[{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:fs/promises","kind":"import-statement","external":true},{"path":"node:path","kind":"import-statement","external":true},{"path":"pkg-up","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/keys","kind":"import-statement","external":true},{"path":"@dxos/lock-file","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"packages/common/phoenix/src/defs.ts","kind":"import-statement","original":"./defs"},{"path":"packages/common/phoenix/src/utils.ts","kind":"import-statement","original":"./utils"}],"format":"esm"},"packages/common/phoenix/src/watchdog.ts":{"bytes":22416,"imports":[{"path":"node:child_process","kind":"import-statement","external":true},{"path":"node:fs","kind":"import-statement","external":true},{"path":"node:util","kind":"import-statement","external":true},{"path":"ps-tree","kind":"import-statement","external":true},{"path":"@dxos/async","kind":"import-statement","external":true},{"path":"@dxos/context","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/lock-file","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"packages/common/phoenix/src/utils.ts","kind":"import-statement","original":"./utils"}],"format":"esm"},"packages/common/phoenix/src/index.ts":{"bytes":1006,"imports":[{"path":"packages/common/phoenix/src/daemon-manager.ts","kind":"import-statement","original":"./daemon-manager"},{"path":"packages/common/phoenix/src/watchdog.ts","kind":"import-statement","original":"./watchdog"}],"format":"esm"}},"outputs":{"packages/common/phoenix/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":21757},"packages/common/phoenix/dist/lib/node/index.cjs":{"imports":[{"path":"node:child_process","kind":"require-call","external":true},{"path":"node:fs","kind":"require-call","external":true},{"path":"node:fs/promises","kind":"require-call","external":true},{"path":"node:path","kind":"require-call","external":true},{"path":"pkg-up","kind":"require-call","external":true},{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/invariant","kind":"require-call","external":true},{"path":"@dxos/keys","kind":"require-call","external":true},{"path":"@dxos/lock-file","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true},{"path":"node:fs","kind":"require-call","external":true},{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/lock-file","kind":"require-call","external":true},{"path":"node:child_process","kind":"require-call","external":true},{"path":"node:fs","kind":"require-call","external":true},{"path":"node:util","kind":"require-call","external":true},{"path":"ps-tree","kind":"require-call","external":true},{"path":"@dxos/async","kind":"require-call","external":true},{"path":"@dxos/context","kind":"require-call","external":true},{"path":"@dxos/invariant","kind":"require-call","external":true},{"path":"@dxos/lock-file","kind":"require-call","external":true},{"path":"@dxos/log","kind":"require-call","external":true}],"exports":[],"entryPoint":"packages/common/phoenix/src/index.ts","inputs":{"packages/common/phoenix/src/index.ts":{"bytesInOutput":159},"packages/common/phoenix/src/daemon-manager.ts":{"bytesInOutput":5124},"packages/common/phoenix/src/defs.ts":{"bytesInOutput":86},"packages/common/phoenix/src/utils.ts":{"bytesInOutput":1027},"packages/common/phoenix/src/watchdog.ts":{"bytesInOutput":6674}},"bytes":14886}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon-manager.d.ts","sourceRoot":"","sources":["../../../src/daemon-manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"daemon-manager.d.ts","sourceRoot":"","sources":["../../../src/daemon-manager.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,WAAW,EAAE,IAAI,EAAQ,WAAW,EAAkB,MAAM,YAAY,CAAC;AAIlF;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEtD,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM;IAM9C,OAAO,CAAC,eAAe;IAYjB,KAAK,CAAC,MAAM,EAAE,WAAW;IAsDzB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;IAoBjC,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAS9B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAgB1C,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAI/C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/phoenix",
|
|
3
|
-
"version": "0.1.58-main.
|
|
3
|
+
"version": "0.1.58-main.60c63b5",
|
|
4
4
|
"description": "Basic node daemon.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
"fs-extra": "^8.1.0",
|
|
17
17
|
"pkg-up": "^3.1.0",
|
|
18
18
|
"ps-tree": "^1.2.0",
|
|
19
|
-
"@dxos/async": "0.1.58-main.
|
|
20
|
-
"@dxos/context": "0.1.58-main.
|
|
21
|
-
"@dxos/invariant": "0.1.58-main.
|
|
22
|
-
"@dxos/keys": "0.1.58-main.
|
|
23
|
-
"@dxos/lock-file": "0.1.58-main.
|
|
24
|
-
"@dxos/log": "0.1.58-main.
|
|
25
|
-
"@dxos/node-std": "0.1.58-main.
|
|
26
|
-
"@dxos/util": "0.1.58-main.
|
|
19
|
+
"@dxos/async": "0.1.58-main.60c63b5",
|
|
20
|
+
"@dxos/context": "0.1.58-main.60c63b5",
|
|
21
|
+
"@dxos/invariant": "0.1.58-main.60c63b5",
|
|
22
|
+
"@dxos/keys": "0.1.58-main.60c63b5",
|
|
23
|
+
"@dxos/lock-file": "0.1.58-main.60c63b5",
|
|
24
|
+
"@dxos/log": "0.1.58-main.60c63b5",
|
|
25
|
+
"@dxos/node-std": "0.1.58-main.60c63b5",
|
|
26
|
+
"@dxos/util": "0.1.58-main.60c63b5"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/fs-extra": "^9.0.4",
|
package/src/daemon-manager.ts
CHANGED
|
@@ -8,10 +8,13 @@ import { readdir } from 'node:fs/promises';
|
|
|
8
8
|
import { dirname, join } from 'node:path';
|
|
9
9
|
import pkgUp from 'pkg-up';
|
|
10
10
|
|
|
11
|
+
import { Trigger, asyncTimeout } from '@dxos/async';
|
|
11
12
|
import { invariant } from '@dxos/invariant';
|
|
13
|
+
import { PublicKey } from '@dxos/keys';
|
|
12
14
|
import { LockFile } from '@dxos/lock-file';
|
|
13
15
|
import { log } from '@dxos/log';
|
|
14
16
|
|
|
17
|
+
import { DAEMON_START_TIMEOUT } from './defs';
|
|
15
18
|
import { waitForLockAcquisition, waitForLockFileBeingFilledWithInfo, waitForLockRelease } from './utils';
|
|
16
19
|
import { ChildParams, Logs, Lock, ProcessInfo, WatchDogParams } from './watchdog';
|
|
17
20
|
|
|
@@ -44,7 +47,9 @@ export class DaemonManager {
|
|
|
44
47
|
|
|
45
48
|
async start(params: StartParams) {
|
|
46
49
|
invariant(params.command, 'command is required');
|
|
47
|
-
const
|
|
50
|
+
const watchdogId = PublicKey.random().toHex();
|
|
51
|
+
const watchDogParams: WatchDogParams & { watchdogId: string } = {
|
|
52
|
+
watchdogId,
|
|
48
53
|
...this._getConfigFiles(params.uid),
|
|
49
54
|
...params,
|
|
50
55
|
};
|
|
@@ -66,6 +71,7 @@ export class DaemonManager {
|
|
|
66
71
|
const watchdogPath = join(dirname(pkgUp.sync({ cwd: __dirname })!), 'bin', 'watchdog');
|
|
67
72
|
|
|
68
73
|
const watchDog = fork(watchdogPath, [JSON.stringify(watchDogParams)], {
|
|
74
|
+
stdio: 'pipe',
|
|
69
75
|
detached: true,
|
|
70
76
|
cwd: __dirname,
|
|
71
77
|
});
|
|
@@ -76,6 +82,14 @@ export class DaemonManager {
|
|
|
76
82
|
}
|
|
77
83
|
});
|
|
78
84
|
|
|
85
|
+
const started = new Trigger();
|
|
86
|
+
watchDog.stdout!.on('data', (data) => {
|
|
87
|
+
if (String(data).includes(watchdogId)) {
|
|
88
|
+
started.wake();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
await asyncTimeout(started.wait(), DAEMON_START_TIMEOUT);
|
|
79
93
|
await waitForLockAcquisition(watchDogParams.lockFile);
|
|
80
94
|
await waitForLockFileBeingFilledWithInfo(watchDogParams.lockFile);
|
|
81
95
|
|
|
@@ -106,8 +120,7 @@ export class DaemonManager {
|
|
|
106
120
|
}
|
|
107
121
|
|
|
108
122
|
async list(): Promise<ProcessInfo[]> {
|
|
109
|
-
const uids =
|
|
110
|
-
|
|
123
|
+
const uids = await readdir(join(this._rootPath, 'profile'));
|
|
111
124
|
return Promise.all(
|
|
112
125
|
uids.map(async (uid) => {
|
|
113
126
|
return this.getInfo(uid);
|