@iobroker/js-controller-cli 7.2.3-alpha.9-20260711-3ea5f3c89 → 8.0.0-alpha.1-20260921-e5941ca8a
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/build/cjs/lib/cli/cliCommand.d.ts +18 -1
- package/build/cjs/lib/cli/cliCommand.js.map +2 -2
- package/build/cjs/lib/cli/cliProcess.d.ts +9 -3
- package/build/cjs/lib/cli/cliProcess.js +50 -8
- package/build/cjs/lib/cli/cliProcess.js.map +2 -2
- package/build/cjs/lib/progressBar.d.ts +59 -0
- package/build/cjs/lib/progressBar.js +115 -0
- package/build/cjs/lib/progressBar.js.map +7 -0
- package/build/cjs/lib/setup/setupBackup.d.ts +19 -0
- package/build/cjs/lib/setup/setupBackup.js +79 -2
- package/build/cjs/lib/setup/setupBackup.js.map +2 -2
- package/build/cjs/lib/setup/setupInstall.d.ts +13 -0
- package/build/cjs/lib/setup/setupInstall.js +170 -4
- package/build/cjs/lib/setup/setupInstall.js.map +2 -2
- package/build/cjs/lib/setup/setupLicense.d.ts +5 -0
- package/build/cjs/lib/setup/setupLicense.js +26 -2
- package/build/cjs/lib/setup/setupLicense.js.map +2 -2
- package/build/cjs/lib/setup/setupMultihost.d.ts +7 -0
- package/build/cjs/lib/setup/setupMultihost.js +66 -2
- package/build/cjs/lib/setup/setupMultihost.js.map +2 -2
- package/build/cjs/lib/setup/setupRepo.d.ts +13 -0
- package/build/cjs/lib/setup/setupRepo.js +113 -2
- package/build/cjs/lib/setup/setupRepo.js.map +2 -2
- package/build/cjs/lib/setup/setupSetup.d.ts +7 -0
- package/build/cjs/lib/setup/setupSetup.js +157 -2
- package/build/cjs/lib/setup/setupSetup.js.map +2 -2
- package/build/cjs/lib/setup/setupUpgrade.d.ts +5 -0
- package/build/cjs/lib/setup/setupUpgrade.js +53 -2
- package/build/cjs/lib/setup/setupUpgrade.js.map +2 -2
- package/build/cjs/lib/setup/setupUpload.d.ts +5 -0
- package/build/cjs/lib/setup/setupUpload.js +78 -3
- package/build/cjs/lib/setup/setupUpload.js.map +2 -2
- package/build/cjs/lib/setup/setupUsers.d.ts +21 -0
- package/build/cjs/lib/setup/setupUsers.js +272 -2
- package/build/cjs/lib/setup/setupUsers.js.map +2 -2
- package/build/cjs/lib/setup/setupVendor.d.ts +5 -0
- package/build/cjs/lib/setup/setupVendor.js +27 -2
- package/build/cjs/lib/setup/setupVendor.js.map +2 -2
- package/build/cjs/lib/setup/setupVisDebug.d.ts +5 -0
- package/build/cjs/lib/setup/setupVisDebug.js +20 -2
- package/build/cjs/lib/setup/setupVisDebug.js.map +2 -2
- package/build/cjs/lib/setup.d.ts +1 -1
- package/build/cjs/lib/setup.js +827 -1666
- package/build/cjs/lib/setup.js.map +3 -3
- package/build/esm/lib/cli/cliCommand.d.ts +18 -1
- package/build/esm/lib/cli/cliCommand.d.ts.map +1 -1
- package/build/esm/lib/cli/cliCommand.js.map +1 -1
- package/build/esm/lib/cli/cliProcess.d.ts +9 -3
- package/build/esm/lib/cli/cliProcess.d.ts.map +1 -1
- package/build/esm/lib/cli/cliProcess.js +66 -8
- package/build/esm/lib/cli/cliProcess.js.map +1 -1
- package/build/esm/lib/progressBar.d.ts +59 -0
- package/build/esm/lib/progressBar.d.ts.map +1 -0
- package/build/esm/lib/progressBar.js +104 -0
- package/build/esm/lib/progressBar.js.map +1 -0
- package/build/esm/lib/setup/setupBackup.d.ts +19 -0
- package/build/esm/lib/setup/setupBackup.d.ts.map +1 -1
- package/build/esm/lib/setup/setupBackup.js +86 -1
- package/build/esm/lib/setup/setupBackup.js.map +1 -1
- package/build/esm/lib/setup/setupInstall.d.ts +13 -0
- package/build/esm/lib/setup/setupInstall.d.ts.map +1 -1
- package/build/esm/lib/setup/setupInstall.js +190 -2
- package/build/esm/lib/setup/setupInstall.js.map +1 -1
- package/build/esm/lib/setup/setupLicense.d.ts +5 -0
- package/build/esm/lib/setup/setupLicense.d.ts.map +1 -1
- package/build/esm/lib/setup/setupLicense.js +25 -1
- package/build/esm/lib/setup/setupLicense.js.map +1 -1
- package/build/esm/lib/setup/setupMultihost.d.ts +7 -0
- package/build/esm/lib/setup/setupMultihost.d.ts.map +1 -1
- package/build/esm/lib/setup/setupMultihost.js +81 -1
- package/build/esm/lib/setup/setupMultihost.js.map +1 -1
- package/build/esm/lib/setup/setupRepo.d.ts +13 -0
- package/build/esm/lib/setup/setupRepo.d.ts.map +1 -1
- package/build/esm/lib/setup/setupRepo.js +134 -0
- package/build/esm/lib/setup/setupRepo.js.map +1 -1
- package/build/esm/lib/setup/setupSetup.d.ts +7 -0
- package/build/esm/lib/setup/setupSetup.d.ts.map +1 -1
- package/build/esm/lib/setup/setupSetup.js +182 -0
- package/build/esm/lib/setup/setupSetup.js.map +1 -1
- package/build/esm/lib/setup/setupUpgrade.d.ts +5 -0
- package/build/esm/lib/setup/setupUpgrade.d.ts.map +1 -1
- package/build/esm/lib/setup/setupUpgrade.js +56 -0
- package/build/esm/lib/setup/setupUpgrade.js.map +1 -1
- package/build/esm/lib/setup/setupUpload.d.ts +5 -0
- package/build/esm/lib/setup/setupUpload.d.ts.map +1 -1
- package/build/esm/lib/setup/setupUpload.js +92 -2
- package/build/esm/lib/setup/setupUpload.js.map +1 -1
- package/build/esm/lib/setup/setupUsers.d.ts +21 -0
- package/build/esm/lib/setup/setupUsers.d.ts.map +1 -1
- package/build/esm/lib/setup/setupUsers.js +290 -0
- package/build/esm/lib/setup/setupUsers.js.map +1 -1
- package/build/esm/lib/setup/setupVendor.d.ts +5 -0
- package/build/esm/lib/setup/setupVendor.d.ts.map +1 -1
- package/build/esm/lib/setup/setupVendor.js +26 -1
- package/build/esm/lib/setup/setupVendor.js.map +1 -1
- package/build/esm/lib/setup/setupVisDebug.d.ts +5 -0
- package/build/esm/lib/setup/setupVisDebug.d.ts.map +1 -1
- package/build/esm/lib/setup/setupVisDebug.js +18 -0
- package/build/esm/lib/setup/setupVisDebug.js.map +1 -1
- package/build/esm/lib/setup.d.ts +1 -1
- package/build/esm/lib/setup.d.ts.map +1 -1
- package/build/esm/lib/setup.js +945 -1847
- package/build/esm/lib/setup.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +5 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DbConnectCallback } from '../_Types.js';
|
|
1
|
+
import type { CleanDatabaseHandler, DbConnectCallback, RestartController } from '../_Types.js';
|
|
2
2
|
/** Context provided to every CLI command */
|
|
3
3
|
export interface CLICommandContext {
|
|
4
4
|
/** Invoke this before doing anything in the database */
|
|
@@ -60,6 +60,23 @@ export interface CLICommandParams {
|
|
|
60
60
|
all?: boolean;
|
|
61
61
|
}
|
|
62
62
|
export type CLICommandOptions = CLICommandContext & CLICommandParams;
|
|
63
|
+
/** Everything a `processCommandXxx` handler needs from the {@link processCommand} dispatcher */
|
|
64
|
+
export interface ProcessCommandOptions {
|
|
65
|
+
/** the matched command (may be an alias, e.g. 'u' for 'upload') */
|
|
66
|
+
command: string | number;
|
|
67
|
+
/** positional arguments following the command */
|
|
68
|
+
args: string[];
|
|
69
|
+
/** parsed CLI flags */
|
|
70
|
+
params: Record<string, any>;
|
|
71
|
+
/** finish the command with the given exit code */
|
|
72
|
+
callback: (exitCode?: number) => void;
|
|
73
|
+
/** merged command context + params (contains dbConnect, showHelp, callback) */
|
|
74
|
+
commandOptions: CLICommandOptions;
|
|
75
|
+
/** clean the objects/states databases (defined in setup.ts) */
|
|
76
|
+
cleanDatabase: CleanDatabaseHandler;
|
|
77
|
+
/** restart the controller (defined in setup.ts) */
|
|
78
|
+
restartController: RestartController;
|
|
79
|
+
}
|
|
63
80
|
/** The base class for any CLI command */
|
|
64
81
|
export declare class CLICommand<TCommandOptions extends CLICommandOptions = CLICommandOptions> {
|
|
65
82
|
protected readonly options: TCommandOptions;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/cli/cliCommand.ts"],
|
|
4
|
-
"sourcesContent": ["import type { DbConnectCallback } from '../_Types.js';\n\n/** Context provided to every CLI command */\nexport interface CLICommandContext {\n /** Invoke this before doing anything in the database */\n dbConnect: (callback: DbConnectCallback) => void;\n /** Finish the command with the given exit code */\n callback: (code?: number) => void;\n /** Show the command help */\n showHelp: (yargs?: any) => void;\n}\n\n/** Parameters (CLI flags) that may be passed to a command */\nexport interface CLICommandParams {\n /** Text encoding to use for output */\n encoding?: BufferEncoding;\n /** Pretty-print the output */\n pretty?: boolean;\n /** Force the operation even if it would normally be refused */\n force?: boolean;\n /** Password to use */\n password?: string;\n /** Restrict the operation to the given group */\n ingroup?: string;\n /** Short alias for the version flag */\n v?: string;\n /** Show the version */\n version?: string | number;\n /** Timeout in milliseconds */\n timeout?: number;\n /** Only include enabled instances */\n enabled?: boolean;\n /** Only include disabled instances */\n disabled?: boolean;\n /** Port to use */\n port?: number;\n /** Use SSL */\n ssl?: boolean;\n /** IP address to bind to */\n ip?: string;\n /** Only include updatable adapters */\n updatable?: boolean;\n /** Host to operate on */\n host?: string;\n /** Certificate to use */\n cert?: string;\n /** Working directory */\n cwd?: string;\n /** File system path */\n path?: string;\n /** Module name */\n module?: string;\n /** Wait for the operation to complete */\n wait?: boolean;\n /** Automatically answer yes to confirmation prompts */\n yes?: boolean;\n /** Short alias for force */\n f?: boolean;\n /** Short alias for yes */\n y?: boolean;\n /** Apply the operation to all matching items */\n all?: boolean;\n}\n\nexport type CLICommandOptions = CLICommandContext & CLICommandParams;\n\n/** The base class for any CLI command */\nexport class CLICommand<TCommandOptions extends CLICommandOptions = CLICommandOptions> {\n protected readonly options: TCommandOptions;\n\n /**\n * @param options The command options including the context (callback, dbConnect) and parameters\n */\n constructor(options: TCommandOptions) {\n if (options === null || options === undefined) {\n throw new Error(`No options given`);\n }\n\n this.options = options;\n // Always require the callback and a wrapper for DB actions\n this.requireOption('callback');\n this.requireOption('dbConnect');\n }\n\n /**\n * Ensures that an argument was passed in the options.\n * Throws otherwise\n *\n * @param arg The name of the option that is required\n */\n requireOption(arg: keyof CLICommandOptions): void {\n if (this.options[arg] === undefined) {\n throw new Error(`Invalid arguments: ${arg} is missing`);\n }\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;
|
|
4
|
+
"sourcesContent": ["import type { CleanDatabaseHandler, DbConnectCallback, RestartController } from '../_Types.js';\n\n/** Context provided to every CLI command */\nexport interface CLICommandContext {\n /** Invoke this before doing anything in the database */\n dbConnect: (callback: DbConnectCallback) => void;\n /** Finish the command with the given exit code */\n callback: (code?: number) => void;\n /** Show the command help */\n showHelp: (yargs?: any) => void;\n}\n\n/** Parameters (CLI flags) that may be passed to a command */\nexport interface CLICommandParams {\n /** Text encoding to use for output */\n encoding?: BufferEncoding;\n /** Pretty-print the output */\n pretty?: boolean;\n /** Force the operation even if it would normally be refused */\n force?: boolean;\n /** Password to use */\n password?: string;\n /** Restrict the operation to the given group */\n ingroup?: string;\n /** Short alias for the version flag */\n v?: string;\n /** Show the version */\n version?: string | number;\n /** Timeout in milliseconds */\n timeout?: number;\n /** Only include enabled instances */\n enabled?: boolean;\n /** Only include disabled instances */\n disabled?: boolean;\n /** Port to use */\n port?: number;\n /** Use SSL */\n ssl?: boolean;\n /** IP address to bind to */\n ip?: string;\n /** Only include updatable adapters */\n updatable?: boolean;\n /** Host to operate on */\n host?: string;\n /** Certificate to use */\n cert?: string;\n /** Working directory */\n cwd?: string;\n /** File system path */\n path?: string;\n /** Module name */\n module?: string;\n /** Wait for the operation to complete */\n wait?: boolean;\n /** Automatically answer yes to confirmation prompts */\n yes?: boolean;\n /** Short alias for force */\n f?: boolean;\n /** Short alias for yes */\n y?: boolean;\n /** Apply the operation to all matching items */\n all?: boolean;\n}\n\nexport type CLICommandOptions = CLICommandContext & CLICommandParams;\n\n/** Everything a `processCommandXxx` handler needs from the {@link processCommand} dispatcher */\nexport interface ProcessCommandOptions {\n /** the matched command (may be an alias, e.g. 'u' for 'upload') */\n command: string | number;\n /** positional arguments following the command */\n args: string[];\n /** parsed CLI flags */\n params: Record<string, any>;\n /** finish the command with the given exit code */\n callback: (exitCode?: number) => void;\n /** merged command context + params (contains dbConnect, showHelp, callback) */\n commandOptions: CLICommandOptions;\n /** clean the objects/states databases (defined in setup.ts) */\n cleanDatabase: CleanDatabaseHandler;\n /** restart the controller (defined in setup.ts) */\n restartController: RestartController;\n}\n\n/** The base class for any CLI command */\nexport class CLICommand<TCommandOptions extends CLICommandOptions = CLICommandOptions> {\n protected readonly options: TCommandOptions;\n\n /**\n * @param options The command options including the context (callback, dbConnect) and parameters\n */\n constructor(options: TCommandOptions) {\n if (options === null || options === undefined) {\n throw new Error(`No options given`);\n }\n\n this.options = options;\n // Always require the callback and a wrapper for DB actions\n this.requireOption('callback');\n this.requireOption('dbConnect');\n }\n\n /**\n * Ensures that an argument was passed in the options.\n * Throws otherwise\n *\n * @param arg The name of the option that is required\n */\n requireOption(arg: keyof CLICommandOptions): void {\n if (this.options[arg] === undefined) {\n throw new Error(`Invalid arguments: ${arg} is missing`);\n }\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAoFA;;;;;AACM,MAAO,WAAU;EADvB,OACuB;;;EACA;;;;EAKnB,YAAY,SAAwB;AAChC,QAAI,YAAY,QAAQ,YAAY,QAAW;AAC3C,YAAM,IAAI,MAAM,kBAAkB;IACtC;AAEA,SAAK,UAAU;AAEf,SAAK,cAAc,UAAU;AAC7B,SAAK,cAAc,WAAW;EAClC;;;;;;;EAQA,cAAc,KAA4B;AACtC,QAAI,KAAK,QAAQ,GAAG,MAAM,QAAW;AACjC,YAAM,IAAI,MAAM,sBAAsB,GAAG,aAAa;IAC1D;EACJ;;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -49,14 +49,20 @@ export declare class CLIProcess extends CLICommand {
|
|
|
49
49
|
setAdapterInstanceEnabled(instance: string, enabled: boolean, restartIfRunning?: boolean): void;
|
|
50
50
|
/**
|
|
51
51
|
* Starts the JS controller
|
|
52
|
+
*
|
|
53
|
+
* @returns true if the controller was started or is already running, false if it could not be started
|
|
52
54
|
*/
|
|
53
|
-
startJSController(): Promise<
|
|
55
|
+
startJSController(): Promise<boolean>;
|
|
54
56
|
/**
|
|
55
57
|
* Stops the JS controller
|
|
56
58
|
*/
|
|
57
59
|
static stopJSController(): Promise<void>;
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Restarts the JS controller
|
|
62
|
+
*
|
|
63
|
+
* @returns true if the controller is running afterwards, false if it could not be started
|
|
64
|
+
*/
|
|
65
|
+
restartJSController(): Promise<boolean>;
|
|
60
66
|
/**
|
|
61
67
|
* Checks if ioBroker is running or not
|
|
62
68
|
*
|
|
@@ -65,8 +65,8 @@ class CLIProcess extends import_cliCommand.CLICommand {
|
|
|
65
65
|
async start(args) {
|
|
66
66
|
const adapterName = (0, import_cliTools.normalizeAdapterName)(args[0]);
|
|
67
67
|
if (!adapterName) {
|
|
68
|
-
await this.startJSController();
|
|
69
|
-
this.options.callback();
|
|
68
|
+
const running = await this.startJSController();
|
|
69
|
+
this.options.callback(running ? void 0 : import_js_controller_common.EXIT_CODES.UNKNOWN_ERROR);
|
|
70
70
|
} else if (adapterName === "all") {
|
|
71
71
|
this.setAllAdaptersEnabled(true);
|
|
72
72
|
} else if (/\.\d+$/.test(adapterName)) {
|
|
@@ -83,8 +83,8 @@ class CLIProcess extends import_cliCommand.CLICommand {
|
|
|
83
83
|
async restart(args) {
|
|
84
84
|
const adapterName = (0, import_cliTools.normalizeAdapterName)(args[0]);
|
|
85
85
|
if (!adapterName) {
|
|
86
|
-
await this.restartJSController();
|
|
87
|
-
this.options.callback();
|
|
86
|
+
const running = await this.restartJSController();
|
|
87
|
+
this.options.callback(running ? void 0 : import_js_controller_common.EXIT_CODES.UNKNOWN_ERROR);
|
|
88
88
|
} else if (/\.\d+$/.test(adapterName)) {
|
|
89
89
|
this.setAdapterInstanceEnabled(
|
|
90
90
|
adapterName,
|
|
@@ -189,6 +189,8 @@ class CLIProcess extends import_cliCommand.CLICommand {
|
|
|
189
189
|
}
|
|
190
190
|
/**
|
|
191
191
|
* Starts the JS controller
|
|
192
|
+
*
|
|
193
|
+
* @returns true if the controller was started or is already running, false if it could not be started
|
|
192
194
|
*/
|
|
193
195
|
async startJSController() {
|
|
194
196
|
let memoryLimitMB = 0;
|
|
@@ -209,8 +211,22 @@ Please call "${import_js_controller_common.tools.appName} setup first" to initia
|
|
|
209
211
|
console.error(`Could not read pid file: ${e.message}`);
|
|
210
212
|
}
|
|
211
213
|
if (pid) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
+
const staleReason = await getStalePidsFileReason(pid);
|
|
215
|
+
if (!staleReason) {
|
|
216
|
+
console.log(`Controller is already running with pid ${pid}`);
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
console.log(`Ignoring left over ${import_js_controller_common.tools.getPidsFileName()}: ${staleReason}`);
|
|
220
|
+
const pidsFileName = import_js_controller_common.tools.getPidsFileName();
|
|
221
|
+
try {
|
|
222
|
+
await import_fs_extra.default.unlink(pidsFileName);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
if (e.code !== "ENOENT") {
|
|
225
|
+
console.error(`Could not remove ${pidsFileName}: ${e.message}`);
|
|
226
|
+
console.error(`Please delete the file manually and run "${import_js_controller_common.tools.appName} start" again.`);
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
214
230
|
}
|
|
215
231
|
const args = [import_node_path.default.join(rootDir, "controller.js")];
|
|
216
232
|
if (memoryLimitMB) {
|
|
@@ -224,6 +240,7 @@ Please call "${import_js_controller_common.tools.appName} setup first" to initia
|
|
|
224
240
|
cwd: rootDir
|
|
225
241
|
});
|
|
226
242
|
child.unref();
|
|
243
|
+
return true;
|
|
227
244
|
}
|
|
228
245
|
/**
|
|
229
246
|
* Stops the JS controller
|
|
@@ -238,6 +255,17 @@ Please call "${import_js_controller_common.tools.appName} setup first" to initia
|
|
|
238
255
|
if (!pid) {
|
|
239
256
|
return;
|
|
240
257
|
}
|
|
258
|
+
if (import_js_controller_common.tools.isProcessRunning(pid) && await import_js_controller_common.tools.isForeignProcess(pid)) {
|
|
259
|
+
console.log(`Not stopping pid ${pid}, it belongs to a different program`);
|
|
260
|
+
try {
|
|
261
|
+
await import_fs_extra.default.unlink(import_js_controller_common.tools.getPidsFileName());
|
|
262
|
+
} catch (e) {
|
|
263
|
+
if (e.code !== "ENOENT") {
|
|
264
|
+
console.error(`Could not remove ${import_js_controller_common.tools.getPidsFileName()}: ${e.message}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
241
269
|
await tryKill(pid);
|
|
242
270
|
if (import_node_os.default.platform() !== "win32") {
|
|
243
271
|
let data = "";
|
|
@@ -260,10 +288,14 @@ Please call "${import_js_controller_common.tools.appName} setup first" to initia
|
|
|
260
288
|
} catch {
|
|
261
289
|
}
|
|
262
290
|
}
|
|
263
|
-
/**
|
|
291
|
+
/**
|
|
292
|
+
* Restarts the JS controller
|
|
293
|
+
*
|
|
294
|
+
* @returns true if the controller is running afterwards, false if it could not be started
|
|
295
|
+
*/
|
|
264
296
|
async restartJSController() {
|
|
265
297
|
await CLIProcess.stopJSController();
|
|
266
|
-
|
|
298
|
+
return this.startJSController();
|
|
267
299
|
}
|
|
268
300
|
/**
|
|
269
301
|
* Checks if ioBroker is running or not
|
|
@@ -369,6 +401,16 @@ async function setInstanceEnabled(objects, instanceObj, enabled, force) {
|
|
|
369
401
|
}
|
|
370
402
|
}
|
|
371
403
|
__name(setInstanceEnabled, "setInstanceEnabled");
|
|
404
|
+
async function getStalePidsFileReason(pid) {
|
|
405
|
+
if (!import_js_controller_common.tools.isProcessRunning(pid)) {
|
|
406
|
+
return `process ${pid} is not running any more`;
|
|
407
|
+
}
|
|
408
|
+
if (await import_js_controller_common.tools.isForeignProcess(pid)) {
|
|
409
|
+
return `pid ${pid} belongs to a different program, not to a controller`;
|
|
410
|
+
}
|
|
411
|
+
return void 0;
|
|
412
|
+
}
|
|
413
|
+
__name(getStalePidsFileReason, "getStalePidsFileReason");
|
|
372
414
|
async function tryKill(pid) {
|
|
373
415
|
try {
|
|
374
416
|
process.kill(pid, "SIGTERM");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/lib/cli/cliProcess.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from 'fs-extra';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { spawn } from 'node:child_process';\nimport deepClone from 'deep-clone';\nimport { setTimeout as wait } from 'node:timers/promises';\n\nimport {\n isLocalStatesDbServer,\n isLocalObjectsDbServer,\n getInstancesOrderedByStartPrio,\n tools,\n EXIT_CODES,\n} from '@iobroker/js-controller-common';\nimport * as CLI from '@/lib/cli/messages.js';\nimport { CLICommand } from '@/lib/cli/cliCommand.js';\nimport { getObjectFrom, getInstanceName, normalizeAdapterName, enumInstances } from '@/lib/cli/cliTools.js';\nimport type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport type { Client as StatesClient } from '@iobroker/db-states-redis';\nimport type { CLICommandOptions } from '@/lib/cli/cliCommand.js';\n\n/** Time to wait after killing pid until process is assumed as stopped */\nconst TRY_KILL_WAIT_MS = 5_000;\n\n// The root of this project. Change this when moving code to another directory\nconst rootDir = tools.getControllerDir();\nconst killAllScriptPath = path.join(rootDir, 'killall.sh');\n\n/** Command ioBroker process control (start/stop/restart/status) ... */\nexport class CLIProcess extends CLICommand {\n /**\n * @param options The command options including context and parameters\n */\n constructor(options: CLICommandOptions) {\n super(options);\n }\n\n // These CLI commands have no subcommands, but belong together thematically\n // (start/stop/restart/status)\n\n /**\n * Starts one or more adapters or the js-controller\n *\n * @param args parsed cli arguments\n */\n async start(args: string[]): Promise<void> {\n const adapterName = normalizeAdapterName(args[0]);\n if (!adapterName) {\n await this.startJSController();\n this.options.callback();\n } else if (adapterName === 'all') {\n this.setAllAdaptersEnabled(true);\n } else if (/\\.\\d+$/.test(adapterName)) {\n this.setAdapterInstanceEnabled(adapterName, true);\n } else {\n this.setAdapterEnabled(adapterName, true);\n }\n }\n\n /**\n * Restarts one or more instances or the js-controller\n *\n * @param args parsed cli arguments\n */\n async restart(args: string[]): Promise<void> {\n const adapterName = normalizeAdapterName(args[0]);\n if (!adapterName) {\n await this.restartJSController();\n this.options.callback();\n } else if (/\\.\\d+$/.test(adapterName)) {\n this.setAdapterInstanceEnabled(adapterName, true, /* restartIfRunning */ true);\n } else {\n this.setAdapterEnabled(adapterName, true, /* restartIfRunning */ true);\n }\n }\n\n /**\n * Stops one or more adapters or the js-controller\n *\n * @param args parsed cli arguments\n */\n async stop(args: string[]): Promise<void> {\n const adapterName = normalizeAdapterName(args[0]);\n if (adapterName === undefined) {\n await CLIProcess.stopJSController();\n this.options.callback();\n } else if (adapterName === 'all') {\n this.setAllAdaptersEnabled(false);\n } else if (/\\.\\d+$/.test(adapterName)) {\n this.setAdapterInstanceEnabled(adapterName, false);\n } else {\n this.setAdapterEnabled(adapterName, false);\n }\n }\n\n /**\n * Starts or stops all adapters\n *\n * @param enabled if adapters should be started or stopped\n */\n setAllAdaptersEnabled(enabled: boolean): void {\n const { callback, dbConnect } = this.options;\n dbConnect(async params => {\n const { objects } = params;\n // Enumerate all adapter instances\n const instances = await getInstancesOrderedByStartPrio(objects, console);\n // Create a promise for each. setInstanceEnabled only starts/stops when necessary\n const instancePromises = instances\n .filter(obj => obj.common.enabled !== enabled)\n .map(obj => setInstanceEnabled(objects, obj, enabled));\n // wait for all instances to be started/stopped\n await Promise.all(instancePromises);\n callback();\n });\n }\n\n /**\n * Starts or stops a single or all instances of adapter.\n * If there are multiple instances, all will be started/stopped/restarted\n *\n * @param adapter The adapter to start\n * @param enabled If adapter should be started or stopped\n * @param [restartIfRunning] Whether running instances should be restarted\n */\n setAdapterEnabled(adapter: string, enabled: boolean, restartIfRunning?: boolean): void {\n const { callback, dbConnect } = this.options;\n dbConnect(async params => {\n const { objects } = params;\n\n try {\n // Enumerate all adapter instances\n const adapterInstances = await enumInstances(objects, adapter);\n if (adapterInstances.length === 0) {\n CLI.error.noInstancesFound(adapter);\n return void callback(EXIT_CODES.UNKNOWN_ERROR);\n }\n for (const instance of adapterInstances) {\n await setInstanceEnabled(objects, instance, enabled, restartIfRunning);\n }\n return void callback();\n } catch (e) {\n CLI.error.unknown(e.message);\n return void callback(EXIT_CODES.UNKNOWN_ERROR);\n }\n });\n }\n\n /**\n * Starts or stops a specific adapter instance\n *\n * @param instance The instance to start, e.g. \"adaptername.0\"\n * @param enabled If the instance should be started or stopped\n * @param [restartIfRunning] Whether running instances should be restarted\n */\n setAdapterInstanceEnabled(instance: string, enabled: boolean, restartIfRunning?: boolean): void {\n const { callback, dbConnect } = this.options;\n dbConnect(async params => {\n const { objects } = params;\n\n const obj = (await objects.getObject(`system.adapter.${instance}`)) as\n ioBroker.InstanceObject | ioBroker.AdapterObject;\n\n if (!obj || obj.type !== 'instance') {\n CLI.error.invalidInstance(instance);\n return void callback();\n }\n\n try {\n await setInstanceEnabled(objects, obj, enabled, restartIfRunning);\n return void callback();\n } catch (e) {\n CLI.error.unknown(e.message);\n return void callback(EXIT_CODES.UNKNOWN_ERROR);\n }\n });\n }\n\n /**\n * Starts the JS controller\n */\n async startJSController(): Promise<void> {\n let memoryLimitMB = 0;\n try {\n const config: ioBroker.IoBrokerJson = fs.readJSONSync(tools.getConfigFileName(), { encoding: 'utf-8' });\n if (config?.system?.memoryLimitMB) {\n memoryLimitMB = Math.round(config.system.memoryLimitMB);\n }\n } catch {\n console.warn('Cannot read memoryLimitMB');\n console.warn(\n `May be config file does not exist.\\nPlease call \"${tools.appName} setup first\" to initialize the settings.`,\n );\n }\n\n let pid: number | undefined;\n try {\n pid = await tools.getControllerPid();\n } catch (e) {\n console.error(`Could not read pid file: ${e.message}`);\n }\n\n if (pid) {\n console.log(`Controller is already running with pid ${pid}`);\n return;\n }\n\n const args = [path.join(rootDir, 'controller.js')];\n if (memoryLimitMB) {\n args.push(`--max-old-space-size=${memoryLimitMB}`);\n }\n\n const child = spawn(process.execPath, args, {\n env: process.env,\n detached: true,\n stdio: ['ignore', 'ignore', 'ignore', 'ipc'],\n windowsHide: true,\n cwd: rootDir,\n });\n\n child.unref();\n }\n\n /**\n * Stops the JS controller\n */\n static async stopJSController(): Promise<void> {\n let pid: number | undefined;\n try {\n pid = await tools.getControllerPid();\n } catch (e) {\n console.error(`Could not read pid file: ${e.message}`);\n }\n\n if (!pid) {\n return;\n }\n\n await tryKill(pid);\n\n // On non-Windows OSes start a KILLALL script\n // to make sure nothing keeps running\n if (os.platform() !== 'win32') {\n let data = '';\n if (fs.existsSync(killAllScriptPath)) {\n fs.chmodSync(killAllScriptPath, '777');\n const child = spawn(killAllScriptPath, [], { windowsHide: true });\n child.stdout.on('data', _data => (data += _data.toString().replace(/\\n/g, '')));\n child.stderr.on('data', _data => (data += _data.toString().replace(/\\n/g, '')));\n return new Promise(resolve => {\n child.on('exit', exitCode => {\n console.log(`Exit code for \"killall.sh\": ${exitCode}`);\n resolve();\n });\n });\n }\n console.log('No \"killall.sh\" script found. Just stop.');\n }\n\n try {\n // delete pids.txt file\n fs.unlinkSync(tools.getPidsFileName());\n } catch {\n // ignore\n }\n }\n\n /** Restarts the JS controller */\n async restartJSController(): Promise<void> {\n await CLIProcess.stopJSController();\n await this.startJSController();\n }\n\n /**\n * Checks if ioBroker is running or not\n *\n * @param args parsed cli arguments\n */\n status(args: string[]): void {\n const { callback, dbConnect } = this.options;\n const adapterName = normalizeAdapterName(args[0]);\n const showEntireConfig = adapterName === 'all';\n\n dbConnect(async params => {\n const { objects, states, config, isOffline } = params;\n\n if (!adapterName || showEntireConfig) {\n // we want host info or/and whole config\n const hostAlive = await states.getState(`system.host.${tools.getHostName()}.alive`);\n\n const alive = hostAlive ? (hostAlive.val as boolean) : false;\n CLI.success.controllerStatus(alive);\n console.log();\n\n const hasLocalStatesServer = await isLocalStatesDbServer(config.states.type, config.states.host);\n const hasLocalObjectsServer = await isLocalObjectsDbServer(config.objects.type, config.objects.host);\n\n if (!hasLocalStatesServer && !hasLocalObjectsServer) {\n CLI.success.systemStatus(!isOffline);\n }\n\n console.log();\n if (showEntireConfig) {\n await showAllInstancesStatus(states, objects);\n console.log();\n showConfig(config);\n } else {\n console.log(`Objects type: ${config.objects.type}`);\n console.log(`States type: ${config.states.type}`);\n }\n return void callback(isOffline ? EXIT_CODES.CONTROLLER_NOT_RUNNING : undefined);\n }\n // we want to know the status of an adapter\n if (/\\.\\d+$/.test(adapterName)) {\n // instance specified\n await showInstanceStatus(states, adapterName);\n return void callback();\n }\n const adapterInstances = await enumInstances(objects, adapterName);\n // If there are multiple instances of this adapter, ask the user to specify which one\n if (adapterInstances.length > 1) {\n CLI.error.specifyInstance(\n adapterName,\n adapterInstances.map(obj => obj._id.substring('system.adapter.'.length)),\n );\n return void callback(EXIT_CODES.INVALID_ADAPTER_ID);\n } else if (adapterInstances.length === 0) {\n CLI.error.noInstancesFound(adapterName);\n return void callback(EXIT_CODES.UNKNOWN_ERROR);\n }\n\n const instanceId = adapterInstances[0]._id.split('.').pop();\n await showInstanceStatus(states, `${adapterName}.${instanceId}`);\n return void callback();\n });\n }\n}\n\n/**\n * Outputs the status of all existing adapter instances\n *\n * @param states The States DB\n * @param objects The Objects DB\n */\nasync function showAllInstancesStatus(states: StatesClient, objects: ObjectsClient): Promise<void> {\n const allInstances = await enumInstances(objects);\n for (const instance of allInstances) {\n const instanceId = instance._id.split('.').pop();\n await showInstanceStatus(states, `${instance.common.name}.${instanceId}`);\n }\n return Promise.resolve();\n}\n\n/**\n * Outputs the status of an adapter instance\n *\n * @param states the states object\n * @param adapterInstance <adapterName>.<instanceId>\n */\nasync function showInstanceStatus(states: StatesClient, adapterInstance: string): Promise<void> {\n const state = await states.getState(`system.adapter.${adapterInstance}.alive`);\n if (state?.val === true) {\n console.log(`Instance \"${adapterInstance}\" is running`);\n } else {\n console.log(`Instance \"${adapterInstance}\" is not running`);\n }\n}\n\n/**\n * Prints the config file to the console\n *\n * @param config the ioBroker json file content\n * @param root The path of the current config section being printed\n */\nfunction showConfig(config: ioBroker.IoBrokerJson, root?: string[]): void {\n if (!tools.isObject(config)) {\n return;\n }\n root ||= [];\n const prefix = root.join('/').toUpperCase();\n for (const attr of Object.keys(config)) {\n if (attr.match(/comment$/i)) {\n continue;\n }\n if (typeof (config as Record<string, any>)[attr] === 'object') {\n const nextRoot = deepClone(root);\n nextRoot.push(attr);\n showConfig((config as Record<string, any>)[attr], nextRoot);\n } else {\n console.log(`${prefix}${(prefix ? '/' : '') + attr}: ${(config as Record<string, any>)[attr]}`);\n }\n }\n}\n\n/**\n * Sets the enabled state of an instance to the given value\n *\n * @param objects The objects DB\n * @param instanceObj The instance object to change\n * @param enabled Whether the instance should be enabled or not\n * @param force Whether the object should be updated always\n */\nasync function setInstanceEnabled(\n objects: ObjectsClient,\n instanceObj: ioBroker.InstanceObject,\n enabled: boolean,\n force?: boolean,\n): Promise<void> {\n if (!force && instanceObj.common.enabled === enabled) {\n return;\n }\n\n instanceObj.common.enabled = enabled;\n instanceObj.from = getObjectFrom();\n instanceObj.ts = Date.now();\n await objects.setObject(instanceObj._id, instanceObj);\n const instanceName = getInstanceName(instanceObj._id);\n if (enabled) {\n CLI.success.adapterStarted(instanceName);\n } else {\n CLI.success.adapterStopped(instanceName);\n }\n}\n\n/**\n * Kills a process by its PID\n *\n * @param pid The PID of the process to kill\n */\nasync function tryKill(pid: number): Promise<void> {\n try {\n process.kill(pid, 'SIGTERM');\n } catch (e) {\n console.warn(`Could not send \"SIGTERM\" to process ${pid}: ${e.message}`);\n }\n\n await wait(TRY_KILL_WAIT_MS);\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;AAAA,sBAAe;AACf,uBAAiB;AACjB,qBAAe;AACf,gCAAsB;AACtB,wBAAsB;AACtB,sBAAmC;AAEnC,kCAMO;AACP,UAAqB;AACrB,wBAA2B;AAC3B,sBAAoF;AAMpF,MAAM,mBAAmB;AAGzB,MAAM,UAAU,kCAAM,iBAAgB;AACtC,MAAM,oBAAoB,iBAAAA,QAAK,KAAK,SAAS,YAAY;AAGnD,MAAO,mBAAmB,6BAAU;EA7B1C,OA6B0C;;;;;;EAItC,YAAY,SAA0B;AAClC,UAAM,OAAO;EACjB;;;;;;;;EAUA,MAAM,MAAM,MAAc;AACtB,UAAM,kBAAc,sCAAqB,KAAK,CAAC,CAAC;AAChD,QAAI,CAAC,aAAa;AACd,YAAM,KAAK,kBAAiB;
|
|
4
|
+
"sourcesContent": ["import fs from 'fs-extra';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { spawn } from 'node:child_process';\nimport deepClone from 'deep-clone';\nimport { setTimeout as wait } from 'node:timers/promises';\n\nimport {\n isLocalStatesDbServer,\n isLocalObjectsDbServer,\n getInstancesOrderedByStartPrio,\n tools,\n EXIT_CODES,\n} from '@iobroker/js-controller-common';\nimport * as CLI from '@/lib/cli/messages.js';\nimport { CLICommand } from '@/lib/cli/cliCommand.js';\nimport { getObjectFrom, getInstanceName, normalizeAdapterName, enumInstances } from '@/lib/cli/cliTools.js';\nimport type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport type { Client as StatesClient } from '@iobroker/db-states-redis';\nimport type { CLICommandOptions } from '@/lib/cli/cliCommand.js';\n\n/** Time to wait after killing pid until process is assumed as stopped */\nconst TRY_KILL_WAIT_MS = 5_000;\n\n// The root of this project. Change this when moving code to another directory\nconst rootDir = tools.getControllerDir();\nconst killAllScriptPath = path.join(rootDir, 'killall.sh');\n\n/** Command ioBroker process control (start/stop/restart/status) ... */\nexport class CLIProcess extends CLICommand {\n /**\n * @param options The command options including context and parameters\n */\n constructor(options: CLICommandOptions) {\n super(options);\n }\n\n // These CLI commands have no subcommands, but belong together thematically\n // (start/stop/restart/status)\n\n /**\n * Starts one or more adapters or the js-controller\n *\n * @param args parsed cli arguments\n */\n async start(args: string[]): Promise<void> {\n const adapterName = normalizeAdapterName(args[0]);\n if (!adapterName) {\n const running = await this.startJSController();\n this.options.callback(running ? undefined : EXIT_CODES.UNKNOWN_ERROR);\n } else if (adapterName === 'all') {\n this.setAllAdaptersEnabled(true);\n } else if (/\\.\\d+$/.test(adapterName)) {\n this.setAdapterInstanceEnabled(adapterName, true);\n } else {\n this.setAdapterEnabled(adapterName, true);\n }\n }\n\n /**\n * Restarts one or more instances or the js-controller\n *\n * @param args parsed cli arguments\n */\n async restart(args: string[]): Promise<void> {\n const adapterName = normalizeAdapterName(args[0]);\n if (!adapterName) {\n const running = await this.restartJSController();\n this.options.callback(running ? undefined : EXIT_CODES.UNKNOWN_ERROR);\n } else if (/\\.\\d+$/.test(adapterName)) {\n this.setAdapterInstanceEnabled(adapterName, true, /* restartIfRunning */ true);\n } else {\n this.setAdapterEnabled(adapterName, true, /* restartIfRunning */ true);\n }\n }\n\n /**\n * Stops one or more adapters or the js-controller\n *\n * @param args parsed cli arguments\n */\n async stop(args: string[]): Promise<void> {\n const adapterName = normalizeAdapterName(args[0]);\n if (adapterName === undefined) {\n await CLIProcess.stopJSController();\n this.options.callback();\n } else if (adapterName === 'all') {\n this.setAllAdaptersEnabled(false);\n } else if (/\\.\\d+$/.test(adapterName)) {\n this.setAdapterInstanceEnabled(adapterName, false);\n } else {\n this.setAdapterEnabled(adapterName, false);\n }\n }\n\n /**\n * Starts or stops all adapters\n *\n * @param enabled if adapters should be started or stopped\n */\n setAllAdaptersEnabled(enabled: boolean): void {\n const { callback, dbConnect } = this.options;\n dbConnect(async params => {\n const { objects } = params;\n // Enumerate all adapter instances\n const instances = await getInstancesOrderedByStartPrio(objects, console);\n // Create a promise for each. setInstanceEnabled only starts/stops when necessary\n const instancePromises = instances\n .filter(obj => obj.common.enabled !== enabled)\n .map(obj => setInstanceEnabled(objects, obj, enabled));\n // wait for all instances to be started/stopped\n await Promise.all(instancePromises);\n callback();\n });\n }\n\n /**\n * Starts or stops a single or all instances of adapter.\n * If there are multiple instances, all will be started/stopped/restarted\n *\n * @param adapter The adapter to start\n * @param enabled If adapter should be started or stopped\n * @param [restartIfRunning] Whether running instances should be restarted\n */\n setAdapterEnabled(adapter: string, enabled: boolean, restartIfRunning?: boolean): void {\n const { callback, dbConnect } = this.options;\n dbConnect(async params => {\n const { objects } = params;\n\n try {\n // Enumerate all adapter instances\n const adapterInstances = await enumInstances(objects, adapter);\n if (adapterInstances.length === 0) {\n CLI.error.noInstancesFound(adapter);\n return void callback(EXIT_CODES.UNKNOWN_ERROR);\n }\n for (const instance of adapterInstances) {\n await setInstanceEnabled(objects, instance, enabled, restartIfRunning);\n }\n return void callback();\n } catch (e) {\n CLI.error.unknown(e.message);\n return void callback(EXIT_CODES.UNKNOWN_ERROR);\n }\n });\n }\n\n /**\n * Starts or stops a specific adapter instance\n *\n * @param instance The instance to start, e.g. \"adaptername.0\"\n * @param enabled If the instance should be started or stopped\n * @param [restartIfRunning] Whether running instances should be restarted\n */\n setAdapterInstanceEnabled(instance: string, enabled: boolean, restartIfRunning?: boolean): void {\n const { callback, dbConnect } = this.options;\n dbConnect(async params => {\n const { objects } = params;\n\n const obj = (await objects.getObject(`system.adapter.${instance}`)) as\n ioBroker.InstanceObject | ioBroker.AdapterObject;\n\n if (!obj || obj.type !== 'instance') {\n CLI.error.invalidInstance(instance);\n return void callback();\n }\n\n try {\n await setInstanceEnabled(objects, obj, enabled, restartIfRunning);\n return void callback();\n } catch (e) {\n CLI.error.unknown(e.message);\n return void callback(EXIT_CODES.UNKNOWN_ERROR);\n }\n });\n }\n\n /**\n * Starts the JS controller\n *\n * @returns true if the controller was started or is already running, false if it could not be started\n */\n async startJSController(): Promise<boolean> {\n let memoryLimitMB = 0;\n try {\n const config: ioBroker.IoBrokerJson = fs.readJSONSync(tools.getConfigFileName(), { encoding: 'utf-8' });\n if (config?.system?.memoryLimitMB) {\n memoryLimitMB = Math.round(config.system.memoryLimitMB);\n }\n } catch {\n console.warn('Cannot read memoryLimitMB');\n console.warn(\n `May be config file does not exist.\\nPlease call \"${tools.appName} setup first\" to initialize the settings.`,\n );\n }\n\n let pid: number | undefined;\n try {\n pid = await tools.getControllerPid();\n } catch (e) {\n console.error(`Could not read pid file: ${e.message}`);\n }\n\n if (pid) {\n const staleReason = await getStalePidsFileReason(pid);\n\n if (!staleReason) {\n console.log(`Controller is already running with pid ${pid}`);\n return true;\n }\n\n // The pids file survived an unclean shutdown, e.g. a power loss. Without removing it\n // here every \"start\" would keep refusing and only \"restart\" would work, because that\n // one deletes the file on its way through stop.\n console.log(`Ignoring left over ${tools.getPidsFileName()}: ${staleReason}`);\n\n const pidsFileName = tools.getPidsFileName();\n try {\n await fs.unlink(pidsFileName);\n } catch (e) {\n if (e.code !== 'ENOENT') {\n console.error(`Could not remove ${pidsFileName}: ${e.message}`);\n console.error(`Please delete the file manually and run \"${tools.appName} start\" again.`);\n return false;\n }\n }\n }\n\n const args = [path.join(rootDir, 'controller.js')];\n if (memoryLimitMB) {\n args.push(`--max-old-space-size=${memoryLimitMB}`);\n }\n\n const child = spawn(process.execPath, args, {\n env: process.env,\n detached: true,\n stdio: ['ignore', 'ignore', 'ignore', 'ipc'],\n windowsHide: true,\n cwd: rootDir,\n });\n\n child.unref();\n return true;\n }\n\n /**\n * Stops the JS controller\n */\n static async stopJSController(): Promise<void> {\n let pid: number | undefined;\n try {\n pid = await tools.getControllerPid();\n } catch (e) {\n console.error(`Could not read pid file: ${e.message}`);\n }\n\n if (!pid) {\n return;\n }\n\n // Stopping the controller is fine, shooting at whoever inherited its pid after a reboot\n // is not - so a pid which provably belongs to a different program is only cleaned up\n if (tools.isProcessRunning(pid) && (await tools.isForeignProcess(pid))) {\n console.log(`Not stopping pid ${pid}, it belongs to a different program`);\n\n try {\n await fs.unlink(tools.getPidsFileName());\n } catch (e) {\n if (e.code !== 'ENOENT') {\n console.error(`Could not remove ${tools.getPidsFileName()}: ${e.message}`);\n }\n }\n return;\n }\n\n await tryKill(pid);\n\n // On non-Windows OSes start a KILLALL script\n // to make sure nothing keeps running\n if (os.platform() !== 'win32') {\n let data = '';\n if (fs.existsSync(killAllScriptPath)) {\n fs.chmodSync(killAllScriptPath, '777');\n const child = spawn(killAllScriptPath, [], { windowsHide: true });\n child.stdout.on('data', _data => (data += _data.toString().replace(/\\n/g, '')));\n child.stderr.on('data', _data => (data += _data.toString().replace(/\\n/g, '')));\n return new Promise(resolve => {\n child.on('exit', exitCode => {\n console.log(`Exit code for \"killall.sh\": ${exitCode}`);\n resolve();\n });\n });\n }\n console.log('No \"killall.sh\" script found. Just stop.');\n }\n\n try {\n // delete pids.txt file\n fs.unlinkSync(tools.getPidsFileName());\n } catch {\n // ignore\n }\n }\n\n /**\n * Restarts the JS controller\n *\n * @returns true if the controller is running afterwards, false if it could not be started\n */\n async restartJSController(): Promise<boolean> {\n await CLIProcess.stopJSController();\n return this.startJSController();\n }\n\n /**\n * Checks if ioBroker is running or not\n *\n * @param args parsed cli arguments\n */\n status(args: string[]): void {\n const { callback, dbConnect } = this.options;\n const adapterName = normalizeAdapterName(args[0]);\n const showEntireConfig = adapterName === 'all';\n\n dbConnect(async params => {\n const { objects, states, config, isOffline } = params;\n\n if (!adapterName || showEntireConfig) {\n // we want host info or/and whole config\n const hostAlive = await states.getState(`system.host.${tools.getHostName()}.alive`);\n\n const alive = hostAlive ? (hostAlive.val as boolean) : false;\n CLI.success.controllerStatus(alive);\n console.log();\n\n const hasLocalStatesServer = await isLocalStatesDbServer(config.states.type, config.states.host);\n const hasLocalObjectsServer = await isLocalObjectsDbServer(config.objects.type, config.objects.host);\n\n if (!hasLocalStatesServer && !hasLocalObjectsServer) {\n CLI.success.systemStatus(!isOffline);\n }\n\n console.log();\n if (showEntireConfig) {\n await showAllInstancesStatus(states, objects);\n console.log();\n showConfig(config);\n } else {\n console.log(`Objects type: ${config.objects.type}`);\n console.log(`States type: ${config.states.type}`);\n }\n return void callback(isOffline ? EXIT_CODES.CONTROLLER_NOT_RUNNING : undefined);\n }\n // we want to know the status of an adapter\n if (/\\.\\d+$/.test(adapterName)) {\n // instance specified\n await showInstanceStatus(states, adapterName);\n return void callback();\n }\n const adapterInstances = await enumInstances(objects, adapterName);\n // If there are multiple instances of this adapter, ask the user to specify which one\n if (adapterInstances.length > 1) {\n CLI.error.specifyInstance(\n adapterName,\n adapterInstances.map(obj => obj._id.substring('system.adapter.'.length)),\n );\n return void callback(EXIT_CODES.INVALID_ADAPTER_ID);\n } else if (adapterInstances.length === 0) {\n CLI.error.noInstancesFound(adapterName);\n return void callback(EXIT_CODES.UNKNOWN_ERROR);\n }\n\n const instanceId = adapterInstances[0]._id.split('.').pop();\n await showInstanceStatus(states, `${adapterName}.${instanceId}`);\n return void callback();\n });\n }\n}\n\n/**\n * Outputs the status of all existing adapter instances\n *\n * @param states The States DB\n * @param objects The Objects DB\n */\nasync function showAllInstancesStatus(states: StatesClient, objects: ObjectsClient): Promise<void> {\n const allInstances = await enumInstances(objects);\n for (const instance of allInstances) {\n const instanceId = instance._id.split('.').pop();\n await showInstanceStatus(states, `${instance.common.name}.${instanceId}`);\n }\n return Promise.resolve();\n}\n\n/**\n * Outputs the status of an adapter instance\n *\n * @param states the states object\n * @param adapterInstance <adapterName>.<instanceId>\n */\nasync function showInstanceStatus(states: StatesClient, adapterInstance: string): Promise<void> {\n const state = await states.getState(`system.adapter.${adapterInstance}.alive`);\n if (state?.val === true) {\n console.log(`Instance \"${adapterInstance}\" is running`);\n } else {\n console.log(`Instance \"${adapterInstance}\" is not running`);\n }\n}\n\n/**\n * Prints the config file to the console\n *\n * @param config the ioBroker json file content\n * @param root The path of the current config section being printed\n */\nfunction showConfig(config: ioBroker.IoBrokerJson, root?: string[]): void {\n if (!tools.isObject(config)) {\n return;\n }\n root ||= [];\n const prefix = root.join('/').toUpperCase();\n for (const attr of Object.keys(config)) {\n if (attr.match(/comment$/i)) {\n continue;\n }\n if (typeof (config as Record<string, any>)[attr] === 'object') {\n const nextRoot = deepClone(root);\n nextRoot.push(attr);\n showConfig((config as Record<string, any>)[attr], nextRoot);\n } else {\n console.log(`${prefix}${(prefix ? '/' : '') + attr}: ${(config as Record<string, any>)[attr]}`);\n }\n }\n}\n\n/**\n * Sets the enabled state of an instance to the given value\n *\n * @param objects The objects DB\n * @param instanceObj The instance object to change\n * @param enabled Whether the instance should be enabled or not\n * @param force Whether the object should be updated always\n */\nasync function setInstanceEnabled(\n objects: ObjectsClient,\n instanceObj: ioBroker.InstanceObject,\n enabled: boolean,\n force?: boolean,\n): Promise<void> {\n if (!force && instanceObj.common.enabled === enabled) {\n return;\n }\n\n instanceObj.common.enabled = enabled;\n instanceObj.from = getObjectFrom();\n instanceObj.ts = Date.now();\n await objects.setObject(instanceObj._id, instanceObj);\n const instanceName = getInstanceName(instanceObj._id);\n if (enabled) {\n CLI.success.adapterStarted(instanceName);\n } else {\n CLI.success.adapterStopped(instanceName);\n }\n}\n\n/**\n * Determine whether the pids file is a leftover instead of belonging to a running controller\n *\n * @param pid the controller pid recorded in the pids file\n * @returns a human readable reason if the file is stale, else undefined\n */\nasync function getStalePidsFileReason(pid: number): Promise<string | undefined> {\n if (!tools.isProcessRunning(pid)) {\n return `process ${pid} is not running any more`;\n }\n\n // The pid is in use, but that alone proves nothing: after a reboot the operating system may\n // have handed it to an unrelated program. Only a positive identification counts here - if the\n // process cannot be inspected we leave it alone, because starting a second controller makes\n // both of them fail with EADDRINUSE.\n if (await tools.isForeignProcess(pid)) {\n return `pid ${pid} belongs to a different program, not to a controller`;\n }\n\n return undefined;\n}\n\n/**\n * Kills a process by its PID\n *\n * @param pid The PID of the process to kill\n */\nasync function tryKill(pid: number): Promise<void> {\n try {\n process.kill(pid, 'SIGTERM');\n } catch (e) {\n console.warn(`Could not send \"SIGTERM\" to process ${pid}: ${e.message}`);\n }\n\n await wait(TRY_KILL_WAIT_MS);\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;AAAA,sBAAe;AACf,uBAAiB;AACjB,qBAAe;AACf,gCAAsB;AACtB,wBAAsB;AACtB,sBAAmC;AAEnC,kCAMO;AACP,UAAqB;AACrB,wBAA2B;AAC3B,sBAAoF;AAMpF,MAAM,mBAAmB;AAGzB,MAAM,UAAU,kCAAM,iBAAgB;AACtC,MAAM,oBAAoB,iBAAAA,QAAK,KAAK,SAAS,YAAY;AAGnD,MAAO,mBAAmB,6BAAU;EA7B1C,OA6B0C;;;;;;EAItC,YAAY,SAA0B;AAClC,UAAM,OAAO;EACjB;;;;;;;;EAUA,MAAM,MAAM,MAAc;AACtB,UAAM,kBAAc,sCAAqB,KAAK,CAAC,CAAC;AAChD,QAAI,CAAC,aAAa;AACd,YAAM,UAAU,MAAM,KAAK,kBAAiB;AAC5C,WAAK,QAAQ,SAAS,UAAU,SAAY,uCAAW,aAAa;IACxE,WAAW,gBAAgB,OAAO;AAC9B,WAAK,sBAAsB,IAAI;IACnC,WAAW,SAAS,KAAK,WAAW,GAAG;AACnC,WAAK,0BAA0B,aAAa,IAAI;IACpD,OAAO;AACH,WAAK,kBAAkB,aAAa,IAAI;IAC5C;EACJ;;;;;;EAOA,MAAM,QAAQ,MAAc;AACxB,UAAM,kBAAc,sCAAqB,KAAK,CAAC,CAAC;AAChD,QAAI,CAAC,aAAa;AACd,YAAM,UAAU,MAAM,KAAK,oBAAmB;AAC9C,WAAK,QAAQ,SAAS,UAAU,SAAY,uCAAW,aAAa;IACxE,WAAW,SAAS,KAAK,WAAW,GAAG;AACnC,WAAK;QAA0B;QAAa;;QAA6B;MAAI;IACjF,OAAO;AACH,WAAK;QAAkB;QAAa;;QAA6B;MAAI;IACzE;EACJ;;;;;;EAOA,MAAM,KAAK,MAAc;AACrB,UAAM,kBAAc,sCAAqB,KAAK,CAAC,CAAC;AAChD,QAAI,gBAAgB,QAAW;AAC3B,YAAM,WAAW,iBAAgB;AACjC,WAAK,QAAQ,SAAQ;IACzB,WAAW,gBAAgB,OAAO;AAC9B,WAAK,sBAAsB,KAAK;IACpC,WAAW,SAAS,KAAK,WAAW,GAAG;AACnC,WAAK,0BAA0B,aAAa,KAAK;IACrD,OAAO;AACH,WAAK,kBAAkB,aAAa,KAAK;IAC7C;EACJ;;;;;;EAOA,sBAAsB,SAAgB;AAClC,UAAM,EAAE,UAAU,UAAS,IAAK,KAAK;AACrC,cAAU,OAAM,WAAS;AACrB,YAAM,EAAE,QAAO,IAAK;AAEpB,YAAM,YAAY,UAAM,4DAA+B,SAAS,OAAO;AAEvE,YAAM,mBAAmB,UACpB,OAAO,SAAO,IAAI,OAAO,YAAY,OAAO,EAC5C,IAAI,SAAO,mBAAmB,SAAS,KAAK,OAAO,CAAC;AAEzD,YAAM,QAAQ,IAAI,gBAAgB;AAClC,eAAQ;IACZ,CAAC;EACL;;;;;;;;;EAUA,kBAAkB,SAAiB,SAAkB,kBAA0B;AAC3E,UAAM,EAAE,UAAU,UAAS,IAAK,KAAK;AACrC,cAAU,OAAM,WAAS;AACrB,YAAM,EAAE,QAAO,IAAK;AAEpB,UAAI;AAEA,cAAM,mBAAmB,UAAM,+BAAc,SAAS,OAAO;AAC7D,YAAI,iBAAiB,WAAW,GAAG;AAC/B,cAAI,MAAM,iBAAiB,OAAO;AAClC,iBAAO,KAAK,SAAS,uCAAW,aAAa;QACjD;AACA,mBAAW,YAAY,kBAAkB;AACrC,gBAAM,mBAAmB,SAAS,UAAU,SAAS,gBAAgB;QACzE;AACA,eAAO,KAAK,SAAQ;MACxB,SAAS,GAAG;AACR,YAAI,MAAM,QAAQ,EAAE,OAAO;AAC3B,eAAO,KAAK,SAAS,uCAAW,aAAa;MACjD;IACJ,CAAC;EACL;;;;;;;;EASA,0BAA0B,UAAkB,SAAkB,kBAA0B;AACpF,UAAM,EAAE,UAAU,UAAS,IAAK,KAAK;AACrC,cAAU,OAAM,WAAS;AACrB,YAAM,EAAE,QAAO,IAAK;AAEpB,YAAM,MAAO,MAAM,QAAQ,UAAU,kBAAkB,QAAQ,EAAE;AAGjE,UAAI,CAAC,OAAO,IAAI,SAAS,YAAY;AACjC,YAAI,MAAM,gBAAgB,QAAQ;AAClC,eAAO,KAAK,SAAQ;MACxB;AAEA,UAAI;AACA,cAAM,mBAAmB,SAAS,KAAK,SAAS,gBAAgB;AAChE,eAAO,KAAK,SAAQ;MACxB,SAAS,GAAG;AACR,YAAI,MAAM,QAAQ,EAAE,OAAO;AAC3B,eAAO,KAAK,SAAS,uCAAW,aAAa;MACjD;IACJ,CAAC;EACL;;;;;;EAOA,MAAM,oBAAiB;AACnB,QAAI,gBAAgB;AACpB,QAAI;AACA,YAAM,SAAgC,gBAAAC,QAAG,aAAa,kCAAM,kBAAiB,GAAI,EAAE,UAAU,QAAO,CAAE;AACtG,UAAI,QAAQ,QAAQ,eAAe;AAC/B,wBAAgB,KAAK,MAAM,OAAO,OAAO,aAAa;MAC1D;IACJ,QAAQ;AACJ,cAAQ,KAAK,2BAA2B;AACxC,cAAQ,KACJ;eAAoD,kCAAM,OAAO,2CAA2C;IAEpH;AAEA,QAAI;AACJ,QAAI;AACA,YAAM,MAAM,kCAAM,iBAAgB;IACtC,SAAS,GAAG;AACR,cAAQ,MAAM,4BAA4B,EAAE,OAAO,EAAE;IACzD;AAEA,QAAI,KAAK;AACL,YAAM,cAAc,MAAM,uBAAuB,GAAG;AAEpD,UAAI,CAAC,aAAa;AACd,gBAAQ,IAAI,0CAA0C,GAAG,EAAE;AAC3D,eAAO;MACX;AAKA,cAAQ,IAAI,sBAAsB,kCAAM,gBAAe,CAAE,KAAK,WAAW,EAAE;AAE3E,YAAM,eAAe,kCAAM,gBAAe;AAC1C,UAAI;AACA,cAAM,gBAAAA,QAAG,OAAO,YAAY;MAChC,SAAS,GAAG;AACR,YAAI,EAAE,SAAS,UAAU;AACrB,kBAAQ,MAAM,oBAAoB,YAAY,KAAK,EAAE,OAAO,EAAE;AAC9D,kBAAQ,MAAM,4CAA4C,kCAAM,OAAO,gBAAgB;AACvF,iBAAO;QACX;MACJ;IACJ;AAEA,UAAM,OAAO,CAAC,iBAAAD,QAAK,KAAK,SAAS,eAAe,CAAC;AACjD,QAAI,eAAe;AACf,WAAK,KAAK,wBAAwB,aAAa,EAAE;IACrD;AAEA,UAAM,YAAQ,iCAAM,QAAQ,UAAU,MAAM;MACxC,KAAK,QAAQ;MACb,UAAU;MACV,OAAO,CAAC,UAAU,UAAU,UAAU,KAAK;MAC3C,aAAa;MACb,KAAK;KACR;AAED,UAAM,MAAK;AACX,WAAO;EACX;;;;EAKA,aAAa,mBAAgB;AACzB,QAAI;AACJ,QAAI;AACA,YAAM,MAAM,kCAAM,iBAAgB;IACtC,SAAS,GAAG;AACR,cAAQ,MAAM,4BAA4B,EAAE,OAAO,EAAE;IACzD;AAEA,QAAI,CAAC,KAAK;AACN;IACJ;AAIA,QAAI,kCAAM,iBAAiB,GAAG,KAAM,MAAM,kCAAM,iBAAiB,GAAG,GAAI;AACpE,cAAQ,IAAI,oBAAoB,GAAG,qCAAqC;AAExE,UAAI;AACA,cAAM,gBAAAC,QAAG,OAAO,kCAAM,gBAAe,CAAE;MAC3C,SAAS,GAAG;AACR,YAAI,EAAE,SAAS,UAAU;AACrB,kBAAQ,MAAM,oBAAoB,kCAAM,gBAAe,CAAE,KAAK,EAAE,OAAO,EAAE;QAC7E;MACJ;AACA;IACJ;AAEA,UAAM,QAAQ,GAAG;AAIjB,QAAI,eAAAC,QAAG,SAAQ,MAAO,SAAS;AAC3B,UAAI,OAAO;AACX,UAAI,gBAAAD,QAAG,WAAW,iBAAiB,GAAG;AAClC,wBAAAA,QAAG,UAAU,mBAAmB,KAAK;AACrC,cAAM,YAAQ,iCAAM,mBAAmB,CAAA,GAAI,EAAE,aAAa,KAAI,CAAE;AAChE,cAAM,OAAO,GAAG,QAAQ,WAAU,QAAQ,MAAM,SAAQ,EAAG,QAAQ,OAAO,EAAE,CAAE;AAC9E,cAAM,OAAO,GAAG,QAAQ,WAAU,QAAQ,MAAM,SAAQ,EAAG,QAAQ,OAAO,EAAE,CAAE;AAC9E,eAAO,IAAI,QAAQ,aAAU;AACzB,gBAAM,GAAG,QAAQ,cAAW;AACxB,oBAAQ,IAAI,+BAA+B,QAAQ,EAAE;AACrD,oBAAO;UACX,CAAC;QACL,CAAC;MACL;AACA,cAAQ,IAAI,0CAA0C;IAC1D;AAEA,QAAI;AAEA,sBAAAA,QAAG,WAAW,kCAAM,gBAAe,CAAE;IACzC,QAAQ;IAER;EACJ;;;;;;EAOA,MAAM,sBAAmB;AACrB,UAAM,WAAW,iBAAgB;AACjC,WAAO,KAAK,kBAAiB;EACjC;;;;;;EAOA,OAAO,MAAc;AACjB,UAAM,EAAE,UAAU,UAAS,IAAK,KAAK;AACrC,UAAM,kBAAc,sCAAqB,KAAK,CAAC,CAAC;AAChD,UAAM,mBAAmB,gBAAgB;AAEzC,cAAU,OAAM,WAAS;AACrB,YAAM,EAAE,SAAS,QAAQ,QAAQ,UAAS,IAAK;AAE/C,UAAI,CAAC,eAAe,kBAAkB;AAElC,cAAM,YAAY,MAAM,OAAO,SAAS,eAAe,kCAAM,YAAW,CAAE,QAAQ;AAElF,cAAM,QAAQ,YAAa,UAAU,MAAkB;AACvD,YAAI,QAAQ,iBAAiB,KAAK;AAClC,gBAAQ,IAAG;AAEX,cAAM,uBAAuB,UAAM,mDAAsB,OAAO,OAAO,MAAM,OAAO,OAAO,IAAI;AAC/F,cAAM,wBAAwB,UAAM,oDAAuB,OAAO,QAAQ,MAAM,OAAO,QAAQ,IAAI;AAEnG,YAAI,CAAC,wBAAwB,CAAC,uBAAuB;AACjD,cAAI,QAAQ,aAAa,CAAC,SAAS;QACvC;AAEA,gBAAQ,IAAG;AACX,YAAI,kBAAkB;AAClB,gBAAM,uBAAuB,QAAQ,OAAO;AAC5C,kBAAQ,IAAG;AACX,qBAAW,MAAM;QACrB,OAAO;AACH,kBAAQ,IAAI,iBAAiB,OAAO,QAAQ,IAAI,EAAE;AAClD,kBAAQ,IAAI,iBAAiB,OAAO,OAAO,IAAI,EAAE;QACrD;AACA,eAAO,KAAK,SAAS,YAAY,uCAAW,yBAAyB,MAAS;MAClF;AAEA,UAAI,SAAS,KAAK,WAAW,GAAG;AAE5B,cAAM,mBAAmB,QAAQ,WAAW;AAC5C,eAAO,KAAK,SAAQ;MACxB;AACA,YAAM,mBAAmB,UAAM,+BAAc,SAAS,WAAW;AAEjE,UAAI,iBAAiB,SAAS,GAAG;AAC7B,YAAI,MAAM,gBACN,aACA,iBAAiB,IAAI,SAAO,IAAI,IAAI,UAAU,kBAAkB,MAAM,CAAC,CAAC;AAE5E,eAAO,KAAK,SAAS,uCAAW,kBAAkB;MACtD,WAAW,iBAAiB,WAAW,GAAG;AACtC,YAAI,MAAM,iBAAiB,WAAW;AACtC,eAAO,KAAK,SAAS,uCAAW,aAAa;MACjD;AAEA,YAAM,aAAa,iBAAiB,CAAC,EAAE,IAAI,MAAM,GAAG,EAAE,IAAG;AACzD,YAAM,mBAAmB,QAAQ,GAAG,WAAW,IAAI,UAAU,EAAE;AAC/D,aAAO,KAAK,SAAQ;IACxB,CAAC;EACL;;AASJ,eAAe,uBAAuB,QAAsB,SAAsB;AAC9E,QAAM,eAAe,UAAM,+BAAc,OAAO;AAChD,aAAW,YAAY,cAAc;AACjC,UAAM,aAAa,SAAS,IAAI,MAAM,GAAG,EAAE,IAAG;AAC9C,UAAM,mBAAmB,QAAQ,GAAG,SAAS,OAAO,IAAI,IAAI,UAAU,EAAE;EAC5E;AACA,SAAO,QAAQ,QAAO;AAC1B;AAPe;AAef,eAAe,mBAAmB,QAAsB,iBAAuB;AAC3E,QAAM,QAAQ,MAAM,OAAO,SAAS,kBAAkB,eAAe,QAAQ;AAC7E,MAAI,OAAO,QAAQ,MAAM;AACrB,YAAQ,IAAI,aAAa,eAAe,cAAc;EAC1D,OAAO;AACH,YAAQ,IAAI,aAAa,eAAe,kBAAkB;EAC9D;AACJ;AAPe;AAef,SAAS,WAAW,QAA+B,MAAe;AAC9D,MAAI,CAAC,kCAAM,SAAS,MAAM,GAAG;AACzB;EACJ;AACA,WAAS,CAAA;AACT,QAAM,SAAS,KAAK,KAAK,GAAG,EAAE,YAAW;AACzC,aAAW,QAAQ,OAAO,KAAK,MAAM,GAAG;AACpC,QAAI,KAAK,MAAM,WAAW,GAAG;AACzB;IACJ;AACA,QAAI,OAAQ,OAA+B,IAAI,MAAM,UAAU;AAC3D,YAAM,eAAW,kBAAAE,SAAU,IAAI;AAC/B,eAAS,KAAK,IAAI;AAClB,iBAAY,OAA+B,IAAI,GAAG,QAAQ;IAC9D,OAAO;AACH,cAAQ,IAAI,GAAG,MAAM,IAAI,SAAS,MAAM,MAAM,IAAI,KAAM,OAA+B,IAAI,CAAC,EAAE;IAClG;EACJ;AACJ;AAlBS;AA4BT,eAAe,mBACX,SACA,aACA,SACA,OAAe;AAEf,MAAI,CAAC,SAAS,YAAY,OAAO,YAAY,SAAS;AAClD;EACJ;AAEA,cAAY,OAAO,UAAU;AAC7B,cAAY,WAAO,+BAAa;AAChC,cAAY,KAAK,KAAK,IAAG;AACzB,QAAM,QAAQ,UAAU,YAAY,KAAK,WAAW;AACpD,QAAM,mBAAe,iCAAgB,YAAY,GAAG;AACpD,MAAI,SAAS;AACT,QAAI,QAAQ,eAAe,YAAY;EAC3C,OAAO;AACH,QAAI,QAAQ,eAAe,YAAY;EAC3C;AACJ;AApBe;AA4Bf,eAAe,uBAAuB,KAAW;AAC7C,MAAI,CAAC,kCAAM,iBAAiB,GAAG,GAAG;AAC9B,WAAO,WAAW,GAAG;EACzB;AAMA,MAAI,MAAM,kCAAM,iBAAiB,GAAG,GAAG;AACnC,WAAO,OAAO,GAAG;EACrB;AAEA,SAAO;AACX;AAde;AAqBf,eAAe,QAAQ,KAAW;AAC9B,MAAI;AACA,YAAQ,KAAK,KAAK,SAAS;EAC/B,SAAS,GAAG;AACR,YAAQ,KAAK,uCAAuC,GAAG,KAAK,EAAE,OAAO,EAAE;EAC3E;AAEA,YAAM,gBAAAC,YAAK,gBAAgB;AAC/B;AARe;",
|
|
6
6
|
"names": ["path", "fs", "os", "deepClone", "wait"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single-line progress bar for terminals which can overwrite their own output.
|
|
3
|
+
*
|
|
4
|
+
* Used where the CLI has a long-running job with a known number of steps. When the output does not
|
|
5
|
+
* go to a terminal - a pipe, a log file, a CI job - a bar would only leave a trail of control
|
|
6
|
+
* characters, so callers ask {@link ProgressBar.isSupported} first and keep their line-based output
|
|
7
|
+
* otherwise.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Draws progress as a bar which overwrites its own line.
|
|
11
|
+
*
|
|
12
|
+
* Callers decide whether to use it - see {@link ProgressBar.isSupported} - and keep their own
|
|
13
|
+
* line-based output when the destination is not a terminal.
|
|
14
|
+
*/
|
|
15
|
+
export declare class ProgressBar {
|
|
16
|
+
private readonly label;
|
|
17
|
+
private readonly total;
|
|
18
|
+
private readonly stream;
|
|
19
|
+
/** Timestamp of the last redraw, to keep the throttle */
|
|
20
|
+
private lastRedraw;
|
|
21
|
+
/** Whether a bar is currently on screen and its line still open */
|
|
22
|
+
private open;
|
|
23
|
+
/**
|
|
24
|
+
* @param label Shown in front of the bar, e.g. the name of what is being uploaded
|
|
25
|
+
* @param total Number of steps that make up 100%
|
|
26
|
+
* @param stream Where to draw, defaults to stdout
|
|
27
|
+
*/
|
|
28
|
+
constructor(label: string, total: number, stream?: NodeJS.WriteStream);
|
|
29
|
+
/**
|
|
30
|
+
* Whether this stream can show a progress bar at all
|
|
31
|
+
*
|
|
32
|
+
* @param stream The stream the bar would be drawn to, defaults to stdout
|
|
33
|
+
*/
|
|
34
|
+
static isSupported(stream?: NodeJS.WriteStream): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Draw the current progress, throttled
|
|
37
|
+
*
|
|
38
|
+
* The last step is always drawn, so the bar never stops short of the number it ends on.
|
|
39
|
+
*
|
|
40
|
+
* @param done How many steps are finished
|
|
41
|
+
*/
|
|
42
|
+
update(done: number): void;
|
|
43
|
+
/**
|
|
44
|
+
* Close the line without completing the bar, so other output can be written
|
|
45
|
+
*
|
|
46
|
+
* Needed before an error or a warning is printed: without it the message would land in the
|
|
47
|
+
* middle of the bar and the next redraw would overwrite it.
|
|
48
|
+
*/
|
|
49
|
+
interrupt(): void;
|
|
50
|
+
/** Draw the bar as complete and close its line */
|
|
51
|
+
finish(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Build the bar as it is written to the terminal
|
|
54
|
+
*
|
|
55
|
+
* @param done How many steps are finished
|
|
56
|
+
*/
|
|
57
|
+
private render;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=progressBar.d.ts.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var progressBar_exports = {};
|
|
21
|
+
__export(progressBar_exports, {
|
|
22
|
+
ProgressBar: () => ProgressBar
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(progressBar_exports);
|
|
25
|
+
const MIN_REDRAW_INTERVAL = 100;
|
|
26
|
+
const MIN_BAR_WIDTH = 10;
|
|
27
|
+
const DEFAULT_COLUMNS = 80;
|
|
28
|
+
const CR = "\r";
|
|
29
|
+
const CLEAR_TO_END = "\x1B[K";
|
|
30
|
+
class ProgressBar {
|
|
31
|
+
static {
|
|
32
|
+
__name(this, "ProgressBar");
|
|
33
|
+
}
|
|
34
|
+
label;
|
|
35
|
+
total;
|
|
36
|
+
stream;
|
|
37
|
+
/** Timestamp of the last redraw, to keep the throttle */
|
|
38
|
+
lastRedraw = 0;
|
|
39
|
+
/** Whether a bar is currently on screen and its line still open */
|
|
40
|
+
open = false;
|
|
41
|
+
/**
|
|
42
|
+
* @param label Shown in front of the bar, e.g. the name of what is being uploaded
|
|
43
|
+
* @param total Number of steps that make up 100%
|
|
44
|
+
* @param stream Where to draw, defaults to stdout
|
|
45
|
+
*/
|
|
46
|
+
constructor(label, total, stream = process.stdout) {
|
|
47
|
+
this.label = label;
|
|
48
|
+
this.total = total;
|
|
49
|
+
this.stream = stream;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Whether this stream can show a progress bar at all
|
|
53
|
+
*
|
|
54
|
+
* @param stream The stream the bar would be drawn to, defaults to stdout
|
|
55
|
+
*/
|
|
56
|
+
static isSupported(stream = process.stdout) {
|
|
57
|
+
return !!stream?.isTTY;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Draw the current progress, throttled
|
|
61
|
+
*
|
|
62
|
+
* The last step is always drawn, so the bar never stops short of the number it ends on.
|
|
63
|
+
*
|
|
64
|
+
* @param done How many steps are finished
|
|
65
|
+
*/
|
|
66
|
+
update(done) {
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
if (this.open && done < this.total && now - this.lastRedraw < MIN_REDRAW_INTERVAL) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.lastRedraw = now;
|
|
72
|
+
this.open = true;
|
|
73
|
+
this.stream.write(`${CR}${this.render(done)}${CLEAR_TO_END}`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Close the line without completing the bar, so other output can be written
|
|
77
|
+
*
|
|
78
|
+
* Needed before an error or a warning is printed: without it the message would land in the
|
|
79
|
+
* middle of the bar and the next redraw would overwrite it.
|
|
80
|
+
*/
|
|
81
|
+
interrupt() {
|
|
82
|
+
if (this.open) {
|
|
83
|
+
this.stream.write("\n");
|
|
84
|
+
this.open = false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** Draw the bar as complete and close its line */
|
|
88
|
+
finish() {
|
|
89
|
+
this.stream.write(`${CR}${this.render(this.total)}${CLEAR_TO_END}
|
|
90
|
+
`);
|
|
91
|
+
this.open = false;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Build the bar as it is written to the terminal
|
|
95
|
+
*
|
|
96
|
+
* @param done How many steps are finished
|
|
97
|
+
*/
|
|
98
|
+
render(done) {
|
|
99
|
+
const percent = this.total > 0 ? Math.min(100, Math.floor(100 * done / this.total)) : 100;
|
|
100
|
+
const suffix = ` ${String(percent).padStart(3)}% (${done}/${this.total})`;
|
|
101
|
+
const prefix = `${this.label} `;
|
|
102
|
+
const columns = this.stream.columns || DEFAULT_COLUMNS;
|
|
103
|
+
const width = columns - prefix.length - suffix.length - 3;
|
|
104
|
+
if (width < MIN_BAR_WIDTH) {
|
|
105
|
+
return prefix + suffix.trimStart();
|
|
106
|
+
}
|
|
107
|
+
const filled = Math.round(width * percent / 100);
|
|
108
|
+
return `${prefix}[${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}]${suffix}`;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
112
|
+
0 && (module.exports = {
|
|
113
|
+
ProgressBar
|
|
114
|
+
});
|
|
115
|
+
//# sourceMappingURL=progressBar.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/progressBar.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * A single-line progress bar for terminals which can overwrite their own output.\n *\n * Used where the CLI has a long-running job with a known number of steps. When the output does not\n * go to a terminal - a pipe, a log file, a CI job - a bar would only leave a trail of control\n * characters, so callers ask {@link ProgressBar.isSupported} first and keep their line-based output\n * otherwise.\n */\n\n/** Redraw no more often than this, so a large job does not spend its time drawing, in ms */\nconst MIN_REDRAW_INTERVAL = 100;\n/** Below this width the bar carries no information and only the numbers are printed */\nconst MIN_BAR_WIDTH = 10;\n/** Assumed terminal width when the stream does not report one */\nconst DEFAULT_COLUMNS = 80;\n\n/** Move to the start of the line */\nconst CR = '\\r';\n/** Erase from the cursor to the end of the line, so a shorter line leaves no remains */\nconst CLEAR_TO_END = '\\u001B[K';\n\n/**\n * Draws progress as a bar which overwrites its own line.\n *\n * Callers decide whether to use it - see {@link ProgressBar.isSupported} - and keep their own\n * line-based output when the destination is not a terminal.\n */\nexport class ProgressBar {\n private readonly label: string;\n private readonly total: number;\n private readonly stream: NodeJS.WriteStream;\n\n /** Timestamp of the last redraw, to keep the throttle */\n private lastRedraw = 0;\n /** Whether a bar is currently on screen and its line still open */\n private open = false;\n\n /**\n * @param label Shown in front of the bar, e.g. the name of what is being uploaded\n * @param total Number of steps that make up 100%\n * @param stream Where to draw, defaults to stdout\n */\n constructor(label: string, total: number, stream: NodeJS.WriteStream = process.stdout) {\n this.label = label;\n this.total = total;\n this.stream = stream;\n }\n\n /**\n * Whether this stream can show a progress bar at all\n *\n * @param stream The stream the bar would be drawn to, defaults to stdout\n */\n static isSupported(stream: NodeJS.WriteStream = process.stdout): boolean {\n return !!stream?.isTTY;\n }\n\n /**\n * Draw the current progress, throttled\n *\n * The last step is always drawn, so the bar never stops short of the number it ends on.\n *\n * @param done How many steps are finished\n */\n update(done: number): void {\n const now = Date.now();\n\n if (this.open && done < this.total && now - this.lastRedraw < MIN_REDRAW_INTERVAL) {\n return;\n }\n\n this.lastRedraw = now;\n this.open = true;\n this.stream.write(`${CR}${this.render(done)}${CLEAR_TO_END}`);\n }\n\n /**\n * Close the line without completing the bar, so other output can be written\n *\n * Needed before an error or a warning is printed: without it the message would land in the\n * middle of the bar and the next redraw would overwrite it.\n */\n interrupt(): void {\n if (this.open) {\n this.stream.write('\\n');\n this.open = false;\n }\n }\n\n /** Draw the bar as complete and close its line */\n finish(): void {\n this.stream.write(`${CR}${this.render(this.total)}${CLEAR_TO_END}\\n`);\n this.open = false;\n }\n\n /**\n * Build the bar as it is written to the terminal\n *\n * @param done How many steps are finished\n */\n private render(done: number): string {\n const percent = this.total > 0 ? Math.min(100, Math.floor((100 * done) / this.total)) : 100;\n // padded, so the following text does not jump around while the number grows\n const suffix = ` ${String(percent).padStart(3)}% (${done}/${this.total})`;\n const prefix = `${this.label} `;\n const columns = this.stream.columns || DEFAULT_COLUMNS;\n // the two brackets, and one column kept free so the line cannot wrap\n const width = columns - prefix.length - suffix.length - 3;\n\n if (width < MIN_BAR_WIDTH) {\n return prefix + suffix.trimStart();\n }\n\n const filled = Math.round((width * percent) / 100);\n\n return `${prefix}[${'\u2588'.repeat(filled)}${'\u2591'.repeat(width - filled)}]${suffix}`;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;AAAA;;;;;AAUA,MAAM,sBAAsB;AAE5B,MAAM,gBAAgB;AAEtB,MAAM,kBAAkB;AAGxB,MAAM,KAAK;AAEX,MAAM,eAAe;AAQf,MAAO,YAAW;EA3BxB,OA2BwB;;;EACH;EACA;EACA;;EAGT,aAAa;;EAEb,OAAO;;;;;;EAOf,YAAY,OAAe,OAAe,SAA6B,QAAQ,QAAM;AACjF,SAAK,QAAQ;AACb,SAAK,QAAQ;AACb,SAAK,SAAS;EAClB;;;;;;EAOA,OAAO,YAAY,SAA6B,QAAQ,QAAM;AAC1D,WAAO,CAAC,CAAC,QAAQ;EACrB;;;;;;;;EASA,OAAO,MAAY;AACf,UAAM,MAAM,KAAK,IAAG;AAEpB,QAAI,KAAK,QAAQ,OAAO,KAAK,SAAS,MAAM,KAAK,aAAa,qBAAqB;AAC/E;IACJ;AAEA,SAAK,aAAa;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO,MAAM,GAAG,EAAE,GAAG,KAAK,OAAO,IAAI,CAAC,GAAG,YAAY,EAAE;EAChE;;;;;;;EAQA,YAAS;AACL,QAAI,KAAK,MAAM;AACX,WAAK,OAAO,MAAM,IAAI;AACtB,WAAK,OAAO;IAChB;EACJ;;EAGA,SAAM;AACF,SAAK,OAAO,MAAM,GAAG,EAAE,GAAG,KAAK,OAAO,KAAK,KAAK,CAAC,GAAG,YAAY;CAAI;AACpE,SAAK,OAAO;EAChB;;;;;;EAOQ,OAAO,MAAY;AACvB,UAAM,UAAU,KAAK,QAAQ,IAAI,KAAK,IAAI,KAAK,KAAK,MAAO,MAAM,OAAQ,KAAK,KAAK,CAAC,IAAI;AAExF,UAAM,SAAS,IAAI,OAAO,OAAO,EAAE,SAAS,CAAC,CAAC,MAAM,IAAI,IAAI,KAAK,KAAK;AACtE,UAAM,SAAS,GAAG,KAAK,KAAK;AAC5B,UAAM,UAAU,KAAK,OAAO,WAAW;AAEvC,UAAM,QAAQ,UAAU,OAAO,SAAS,OAAO,SAAS;AAExD,QAAI,QAAQ,eAAe;AACvB,aAAO,SAAS,OAAO,UAAS;IACpC;AAEA,UAAM,SAAS,KAAK,MAAO,QAAQ,UAAW,GAAG;AAEjD,WAAO,GAAG,MAAM,IAAI,SAAI,OAAO,MAAM,CAAC,GAAG,SAAI,OAAO,QAAQ,MAAM,CAAC,IAAI,MAAM;EACjF;;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,6 +2,7 @@ import { EXIT_CODES } from '@iobroker/js-controller-common';
|
|
|
2
2
|
import type { Client as StatesRedisClient } from '@iobroker/db-states-redis';
|
|
3
3
|
import type { Client as ObjectsRedisClient } from '@iobroker/db-objects-redis';
|
|
4
4
|
import type { CleanDatabaseHandler, ProcessExitCallback, RestartController } from '../_Types.js';
|
|
5
|
+
import type { ProcessCommandOptions } from '../../lib/cli/cliCommand.js';
|
|
5
6
|
/** Options for the backup/restore command */
|
|
6
7
|
export interface CLIBackupRestoreOptions {
|
|
7
8
|
/** Whether this is part of a database migration */
|
|
@@ -211,4 +212,22 @@ export declare class BackupRestore {
|
|
|
211
212
|
*/
|
|
212
213
|
private _restorePreservedAdapters;
|
|
213
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* Processes the `restore` command
|
|
217
|
+
*
|
|
218
|
+
* @param options the command options
|
|
219
|
+
*/
|
|
220
|
+
export declare function processCommandRestore(options: ProcessCommandOptions): void;
|
|
221
|
+
/**
|
|
222
|
+
* Processes the `backup` command
|
|
223
|
+
*
|
|
224
|
+
* @param options the command options
|
|
225
|
+
*/
|
|
226
|
+
export declare function processCommandBackup(options: ProcessCommandOptions): void;
|
|
227
|
+
/**
|
|
228
|
+
* Processes the `validate` command
|
|
229
|
+
*
|
|
230
|
+
* @param options the command options
|
|
231
|
+
*/
|
|
232
|
+
export declare function processCommandValidate(options: ProcessCommandOptions): void;
|
|
214
233
|
//# sourceMappingURL=setupBackup.d.ts.map
|
|
@@ -29,7 +29,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
30
|
var setupBackup_exports = {};
|
|
31
31
|
__export(setupBackup_exports, {
|
|
32
|
-
BackupRestore: () => BackupRestore
|
|
32
|
+
BackupRestore: () => BackupRestore,
|
|
33
|
+
processCommandBackup: () => processCommandBackup,
|
|
34
|
+
processCommandRestore: () => processCommandRestore,
|
|
35
|
+
processCommandValidate: () => processCommandValidate
|
|
33
36
|
});
|
|
34
37
|
module.exports = __toCommonJS(setupBackup_exports);
|
|
35
38
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
@@ -1078,8 +1081,82 @@ class BackupRestore {
|
|
|
1078
1081
|
}
|
|
1079
1082
|
}
|
|
1080
1083
|
}
|
|
1084
|
+
function processCommandRestore(options) {
|
|
1085
|
+
const { args, params, callback, cleanDatabase, restartController } = options;
|
|
1086
|
+
(0, import_dbConnection.dbConnect)(params, async ({ isOffline, objects, states }) => {
|
|
1087
|
+
if (!isOffline) {
|
|
1088
|
+
console.error(`Stop ${import_js_controller_common.tools.appName} first!`);
|
|
1089
|
+
return void callback(import_js_controller_common.EXIT_CODES.CONTROLLER_RUNNING);
|
|
1090
|
+
}
|
|
1091
|
+
const backup = new BackupRestore({
|
|
1092
|
+
states,
|
|
1093
|
+
objects,
|
|
1094
|
+
cleanDatabase,
|
|
1095
|
+
restartController,
|
|
1096
|
+
processExit: callback
|
|
1097
|
+
});
|
|
1098
|
+
const { exitCode } = await backup.restoreBackup({
|
|
1099
|
+
name: args[0],
|
|
1100
|
+
force: !!params.force,
|
|
1101
|
+
dontDeleteAdapters: false
|
|
1102
|
+
});
|
|
1103
|
+
if (exitCode === import_js_controller_common.EXIT_CODES.NO_ERROR) {
|
|
1104
|
+
console.log("System successfully restored!");
|
|
1105
|
+
}
|
|
1106
|
+
return void callback(exitCode);
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
__name(processCommandRestore, "processCommandRestore");
|
|
1110
|
+
function processCommandBackup(options) {
|
|
1111
|
+
const { args, params, callback, cleanDatabase, restartController } = options;
|
|
1112
|
+
const name = args[0];
|
|
1113
|
+
(0, import_dbConnection.dbConnect)(params, async ({ states, objects }) => {
|
|
1114
|
+
const backup = new BackupRestore({
|
|
1115
|
+
states,
|
|
1116
|
+
objects,
|
|
1117
|
+
cleanDatabase,
|
|
1118
|
+
restartController,
|
|
1119
|
+
processExit: callback
|
|
1120
|
+
});
|
|
1121
|
+
try {
|
|
1122
|
+
const filePath = await backup.createBackup(name);
|
|
1123
|
+
console.log(`Backup created: ${filePath}`);
|
|
1124
|
+
console.log("This backup can only be restored with js-controller version 7.0 or higher");
|
|
1125
|
+
return void callback(import_js_controller_common.EXIT_CODES.NO_ERROR);
|
|
1126
|
+
} catch (e) {
|
|
1127
|
+
console.log(`Cannot create backup: ${e.message}`);
|
|
1128
|
+
return void callback(e instanceof import_customError.IoBrokerError ? e.code : import_js_controller_common.EXIT_CODES.CANNOT_EXTRACT_FROM_ZIP);
|
|
1129
|
+
}
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
__name(processCommandBackup, "processCommandBackup");
|
|
1133
|
+
function processCommandValidate(options) {
|
|
1134
|
+
const { args, params, callback, cleanDatabase, restartController } = options;
|
|
1135
|
+
const name = args[0];
|
|
1136
|
+
(0, import_dbConnection.dbConnect)(params, async ({ objects, states }) => {
|
|
1137
|
+
const backup = new BackupRestore({
|
|
1138
|
+
states,
|
|
1139
|
+
objects,
|
|
1140
|
+
cleanDatabase,
|
|
1141
|
+
restartController,
|
|
1142
|
+
processExit: callback
|
|
1143
|
+
});
|
|
1144
|
+
try {
|
|
1145
|
+
await backup.validateBackup(name);
|
|
1146
|
+
console.log("Backup OK");
|
|
1147
|
+
return void (0, import_dbConnection.exitApplicationSave)(0);
|
|
1148
|
+
} catch (e) {
|
|
1149
|
+
console.log(`Backup check failed: ${e.message}`);
|
|
1150
|
+
return void (0, import_dbConnection.exitApplicationSave)(e instanceof import_customError.IoBrokerError ? e.code : 1);
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
__name(processCommandValidate, "processCommandValidate");
|
|
1081
1155
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1082
1156
|
0 && (module.exports = {
|
|
1083
|
-
BackupRestore
|
|
1157
|
+
BackupRestore,
|
|
1158
|
+
processCommandBackup,
|
|
1159
|
+
processCommandRestore,
|
|
1160
|
+
processCommandValidate
|
|
1084
1161
|
});
|
|
1085
1162
|
//# sourceMappingURL=setupBackup.js.map
|