@iobroker/js-controller-cli 7.2.3 → 8.0.0-alpha.2-20260923-99da17fcc
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/index.js +3 -3
- package/build/cjs/lib/_Types.d.ts +8 -1
- package/build/cjs/lib/cli/cliCert.d.ts +7 -4
- package/build/cjs/lib/cli/cliCert.js +10 -6
- package/build/cjs/lib/cli/cliCert.js.map +2 -2
- package/build/cjs/lib/cli/cliCommand.d.ts +63 -15
- package/build/cjs/lib/cli/cliCommand.js +8 -1
- package/build/cjs/lib/cli/cliCommand.js.map +2 -2
- package/build/cjs/lib/cli/cliCompact.d.ts +5 -2
- package/build/cjs/lib/cli/cliCompact.js +9 -2
- package/build/cjs/lib/cli/cliCompact.js.map +2 -2
- package/build/cjs/lib/cli/cliDebug.d.ts +5 -2
- package/build/cjs/lib/cli/cliDebug.js +8 -1
- package/build/cjs/lib/cli/cliDebug.js.map +2 -2
- package/build/cjs/lib/cli/cliHost.d.ts +13 -10
- package/build/cjs/lib/cli/cliHost.js +13 -5
- package/build/cjs/lib/cli/cliHost.js.map +2 -2
- package/build/cjs/lib/cli/cliLogs.d.ts +9 -3
- package/build/cjs/lib/cli/cliLogs.js +12 -1
- package/build/cjs/lib/cli/cliLogs.js.map +2 -2
- package/build/cjs/lib/cli/cliMessage.d.ts +2 -1
- package/build/cjs/lib/cli/cliMessage.js +5 -0
- package/build/cjs/lib/cli/cliMessage.js.map +2 -2
- package/build/cjs/lib/cli/cliObjects.d.ts +21 -18
- package/build/cjs/lib/cli/cliObjects.js +51 -33
- package/build/cjs/lib/cli/cliObjects.js.map +2 -2
- package/build/cjs/lib/cli/cliPlugin.d.ts +3 -3
- package/build/cjs/lib/cli/cliPlugin.js +6 -0
- package/build/cjs/lib/cli/cliPlugin.js.map +2 -2
- package/build/cjs/lib/cli/cliProcess.d.ts +17 -7
- package/build/cjs/lib/cli/cliProcess.js +77 -24
- package/build/cjs/lib/cli/cliProcess.js.map +3 -3
- package/build/cjs/lib/cli/cliStates.d.ts +7 -4
- package/build/cjs/lib/cli/cliStates.js +14 -6
- package/build/cjs/lib/cli/cliStates.js.map +2 -2
- package/build/cjs/lib/cli/cliTools.js +11 -0
- package/build/cjs/lib/cli/cliTools.js.map +1 -1
- package/build/cjs/lib/cli/messages.js +47 -46
- package/build/cjs/lib/cli/messages.js.map +1 -1
- 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/customError.d.ts +4 -0
- package/build/cjs/lib/setup/customError.js +7 -0
- package/build/cjs/lib/setup/customError.js.map +2 -2
- package/build/cjs/lib/setup/dbConnection.js +69 -64
- package/build/cjs/lib/setup/dbConnection.js.map +3 -3
- package/build/cjs/lib/setup/formatters.d.ts +4 -4
- package/build/cjs/lib/setup/formatters.js +5 -0
- package/build/cjs/lib/setup/formatters.js.map +2 -2
- package/build/cjs/lib/setup/multihostClient.js +6 -2
- package/build/cjs/lib/setup/multihostClient.js.map +1 -1
- package/build/cjs/lib/setup/pluginInfos.d.ts +5 -0
- package/build/cjs/lib/setup/pluginInfos.js +2 -0
- package/build/cjs/lib/setup/pluginInfos.js.map +2 -2
- package/build/cjs/lib/setup/setupBackup.d.ts +53 -0
- package/build/cjs/lib/setup/setupBackup.js +125 -14
- package/build/cjs/lib/setup/setupBackup.js.map +3 -3
- package/build/cjs/lib/setup/setupInstall.d.ts +66 -15
- package/build/cjs/lib/setup/setupInstall.js +282 -28
- package/build/cjs/lib/setup/setupInstall.js.map +2 -2
- package/build/cjs/lib/setup/setupLicense.d.ts +13 -0
- package/build/cjs/lib/setup/setupLicense.js +33 -2
- package/build/cjs/lib/setup/setupLicense.js.map +2 -2
- package/build/cjs/lib/setup/setupList.d.ts +55 -1
- package/build/cjs/lib/setup/setupList.js +78 -24
- package/build/cjs/lib/setup/setupList.js.map +3 -3
- package/build/cjs/lib/setup/setupMultihost.d.ts +7 -0
- package/build/cjs/lib/setup/setupMultihost.js +78 -11
- package/build/cjs/lib/setup/setupMultihost.js.map +3 -3
- package/build/cjs/lib/setup/setupPacketManager.d.ts +10 -0
- package/build/cjs/lib/setup/setupPacketManager.js +16 -6
- package/build/cjs/lib/setup/setupPacketManager.js.map +2 -2
- package/build/cjs/lib/setup/setupRepo.d.ts +19 -0
- package/build/cjs/lib/setup/setupRepo.js +141 -13
- package/build/cjs/lib/setup/setupRepo.js.map +2 -2
- package/build/cjs/lib/setup/setupSetup.d.ts +34 -0
- package/build/cjs/lib/setup/setupSetup.js +209 -35
- package/build/cjs/lib/setup/setupSetup.js.map +3 -3
- package/build/cjs/lib/setup/setupUpgrade.d.ts +13 -2
- package/build/cjs/lib/setup/setupUpgrade.js +72 -12
- package/build/cjs/lib/setup/setupUpgrade.js.map +2 -2
- package/build/cjs/lib/setup/setupUpload.d.ts +77 -1
- package/build/cjs/lib/setup/setupUpload.js +152 -9
- package/build/cjs/lib/setup/setupUpload.js.map +2 -2
- package/build/cjs/lib/setup/setupUsers.d.ts +44 -14
- package/build/cjs/lib/setup/setupUsers.js +330 -17
- package/build/cjs/lib/setup/setupUsers.js.map +2 -2
- package/build/cjs/lib/setup/setupVendor.d.ts +14 -1
- package/build/cjs/lib/setup/setupVendor.js +40 -8
- package/build/cjs/lib/setup/setupVendor.js.map +2 -2
- package/build/cjs/lib/setup/setupVisDebug.d.ts +16 -2
- package/build/cjs/lib/setup/setupVisDebug.js +41 -17
- package/build/cjs/lib/setup/setupVisDebug.js.map +3 -3
- package/build/cjs/lib/setup/utils.d.ts +1 -1
- package/build/cjs/lib/setup/utils.js +13 -9
- package/build/cjs/lib/setup/utils.js.map +3 -3
- package/build/cjs/lib/setup.d.ts +1 -1
- package/build/cjs/lib/setup.js +858 -1758
- package/build/cjs/lib/setup.js.map +3 -3
- package/build/esm/lib/_Types.d.ts +8 -1
- package/build/esm/lib/_Types.d.ts.map +1 -1
- package/build/esm/lib/cli/cliCert.d.ts +7 -4
- package/build/esm/lib/cli/cliCert.d.ts.map +1 -1
- package/build/esm/lib/cli/cliCert.js +6 -6
- package/build/esm/lib/cli/cliCert.js.map +1 -1
- package/build/esm/lib/cli/cliCommand.d.ts +63 -15
- package/build/esm/lib/cli/cliCommand.d.ts.map +1 -1
- package/build/esm/lib/cli/cliCommand.js +4 -1
- package/build/esm/lib/cli/cliCommand.js.map +1 -1
- package/build/esm/lib/cli/cliCompact.d.ts +5 -2
- package/build/esm/lib/cli/cliCompact.d.ts.map +1 -1
- package/build/esm/lib/cli/cliCompact.js +5 -2
- package/build/esm/lib/cli/cliCompact.js.map +1 -1
- package/build/esm/lib/cli/cliDebug.d.ts +5 -2
- package/build/esm/lib/cli/cliDebug.d.ts.map +1 -1
- package/build/esm/lib/cli/cliDebug.js +4 -1
- package/build/esm/lib/cli/cliDebug.js.map +1 -1
- package/build/esm/lib/cli/cliHost.d.ts +13 -10
- package/build/esm/lib/cli/cliHost.d.ts.map +1 -1
- package/build/esm/lib/cli/cliHost.js +8 -5
- package/build/esm/lib/cli/cliHost.js.map +1 -1
- package/build/esm/lib/cli/cliLogs.d.ts +9 -3
- package/build/esm/lib/cli/cliLogs.d.ts.map +1 -1
- package/build/esm/lib/cli/cliLogs.js +8 -1
- package/build/esm/lib/cli/cliLogs.js.map +1 -1
- package/build/esm/lib/cli/cliMessage.d.ts +2 -1
- package/build/esm/lib/cli/cliMessage.d.ts.map +1 -1
- package/build/esm/lib/cli/cliMessage.js +1 -0
- package/build/esm/lib/cli/cliMessage.js.map +1 -1
- package/build/esm/lib/cli/cliObjects.d.ts +21 -18
- package/build/esm/lib/cli/cliObjects.d.ts.map +1 -1
- package/build/esm/lib/cli/cliObjects.js +44 -38
- package/build/esm/lib/cli/cliObjects.js.map +1 -1
- package/build/esm/lib/cli/cliPlugin.d.ts +3 -3
- package/build/esm/lib/cli/cliPlugin.d.ts.map +1 -1
- package/build/esm/lib/cli/cliPlugin.js +1 -1
- package/build/esm/lib/cli/cliPlugin.js.map +1 -1
- package/build/esm/lib/cli/cliProcess.d.ts +17 -7
- package/build/esm/lib/cli/cliProcess.d.ts.map +1 -1
- package/build/esm/lib/cli/cliProcess.js +73 -12
- package/build/esm/lib/cli/cliProcess.js.map +1 -1
- package/build/esm/lib/cli/cliStates.d.ts +7 -4
- package/build/esm/lib/cli/cliStates.d.ts.map +1 -1
- package/build/esm/lib/cli/cliStates.js +6 -2
- package/build/esm/lib/cli/cliStates.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/customError.d.ts +4 -0
- package/build/esm/lib/setup/customError.d.ts.map +1 -1
- package/build/esm/lib/setup/customError.js +3 -0
- package/build/esm/lib/setup/customError.js.map +1 -1
- package/build/esm/lib/setup/dbConnection.d.ts.map +1 -1
- package/build/esm/lib/setup/dbConnection.js +10 -13
- package/build/esm/lib/setup/dbConnection.js.map +1 -1
- package/build/esm/lib/setup/formatters.d.ts +4 -4
- package/build/esm/lib/setup/formatters.js +4 -4
- package/build/esm/lib/setup/pluginInfos.d.ts +5 -0
- package/build/esm/lib/setup/pluginInfos.d.ts.map +1 -1
- package/build/esm/lib/setup/pluginInfos.js +5 -0
- package/build/esm/lib/setup/pluginInfos.js.map +1 -1
- package/build/esm/lib/setup/setupBackup.d.ts +53 -0
- package/build/esm/lib/setup/setupBackup.d.ts.map +1 -1
- package/build/esm/lib/setup/setupBackup.js +132 -13
- package/build/esm/lib/setup/setupBackup.js.map +1 -1
- package/build/esm/lib/setup/setupInstall.d.ts +66 -15
- package/build/esm/lib/setup/setupInstall.d.ts.map +1 -1
- package/build/esm/lib/setup/setupInstall.js +309 -23
- package/build/esm/lib/setup/setupInstall.js.map +1 -1
- package/build/esm/lib/setup/setupLicense.d.ts +13 -0
- package/build/esm/lib/setup/setupLicense.d.ts.map +1 -1
- package/build/esm/lib/setup/setupLicense.js +31 -1
- package/build/esm/lib/setup/setupLicense.js.map +1 -1
- package/build/esm/lib/setup/setupList.d.ts +55 -1
- package/build/esm/lib/setup/setupList.d.ts.map +1 -1
- package/build/esm/lib/setup/setupList.js +61 -8
- package/build/esm/lib/setup/setupList.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 +85 -6
- package/build/esm/lib/setup/setupMultihost.js.map +1 -1
- package/build/esm/lib/setup/setupPacketManager.d.ts +10 -0
- package/build/esm/lib/setup/setupPacketManager.d.ts.map +1 -1
- package/build/esm/lib/setup/setupPacketManager.js +9 -0
- package/build/esm/lib/setup/setupPacketManager.js.map +1 -1
- package/build/esm/lib/setup/setupRepo.d.ts +19 -0
- package/build/esm/lib/setup/setupRepo.d.ts.map +1 -1
- package/build/esm/lib/setup/setupRepo.js +164 -14
- package/build/esm/lib/setup/setupRepo.js.map +1 -1
- package/build/esm/lib/setup/setupSetup.d.ts +34 -0
- package/build/esm/lib/setup/setupSetup.d.ts.map +1 -1
- package/build/esm/lib/setup/setupSetup.js +218 -21
- package/build/esm/lib/setup/setupSetup.js.map +1 -1
- package/build/esm/lib/setup/setupUpgrade.d.ts +13 -2
- package/build/esm/lib/setup/setupUpgrade.d.ts.map +1 -1
- package/build/esm/lib/setup/setupUpgrade.js +70 -6
- package/build/esm/lib/setup/setupUpgrade.js.map +1 -1
- package/build/esm/lib/setup/setupUpload.d.ts +77 -1
- package/build/esm/lib/setup/setupUpload.d.ts.map +1 -1
- package/build/esm/lib/setup/setupUpload.js +164 -7
- package/build/esm/lib/setup/setupUpload.js.map +1 -1
- package/build/esm/lib/setup/setupUsers.d.ts +44 -14
- package/build/esm/lib/setup/setupUsers.d.ts.map +1 -1
- package/build/esm/lib/setup/setupUsers.js +346 -14
- package/build/esm/lib/setup/setupUsers.js.map +1 -1
- package/build/esm/lib/setup/setupVendor.d.ts +14 -1
- package/build/esm/lib/setup/setupVendor.d.ts.map +1 -1
- package/build/esm/lib/setup/setupVendor.js +33 -2
- package/build/esm/lib/setup/setupVendor.js.map +1 -1
- package/build/esm/lib/setup/setupVisDebug.d.ts +16 -2
- package/build/esm/lib/setup/setupVisDebug.d.ts.map +1 -1
- package/build/esm/lib/setup/setupVisDebug.js +39 -14
- package/build/esm/lib/setup/setupVisDebug.js.map +1 -1
- package/build/esm/lib/setup/utils.d.ts +1 -1
- package/build/esm/lib/setup/utils.d.ts.map +1 -1
- package/build/esm/lib/setup/utils.js +2 -4
- package/build/esm/lib/setup/utils.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 +959 -1910
- package/build/esm/lib/setup.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +14 -14
package/build/esm/lib/setup.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
|
-
import { tools } from '@iobroker/js-controller-common';
|
|
3
|
-
import { EXIT_CODES } from '@iobroker/js-controller-common';
|
|
4
|
-
import deepClone from 'deep-clone';
|
|
5
|
-
import { isDeepStrictEqual } from 'node:util';
|
|
6
2
|
import Debug from 'debug';
|
|
7
|
-
import { objectsDbHasServer, isLocalObjectsDbServer, isLocalStatesDbServer } from '@iobroker/js-controller-common';
|
|
8
3
|
import path from 'node:path';
|
|
9
4
|
import yargs from 'yargs/yargs';
|
|
10
|
-
import * as
|
|
5
|
+
import * as url from 'node:url';
|
|
6
|
+
import * as events from 'node:events';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import { tools, EXIT_CODES, objectsDbHasServer } from '@iobroker/js-controller-common';
|
|
9
|
+
import { SYSTEM_CONFIG_ID, SYSTEM_REPOSITORIES_ID } from '@iobroker/js-controller-common-db/constants';
|
|
11
10
|
import { CLIHost } from '../lib/cli/cliHost.js';
|
|
12
11
|
import { CLIStates } from '../lib/cli/cliStates.js';
|
|
13
12
|
import { CLIDebug } from '../lib/cli/cliDebug.js';
|
|
@@ -19,15 +18,13 @@ import { CLIProcess } from '../lib/cli/cliProcess.js';
|
|
|
19
18
|
import { CLIMessage } from '../lib/cli/cliMessage.js';
|
|
20
19
|
import { CLIPlugin } from '../lib/cli/cliPlugin.js';
|
|
21
20
|
import { error as CLIError } from '../lib/cli/messages.js';
|
|
22
|
-
import {
|
|
21
|
+
import { ignoreVersion, recognizeVersion } from '../lib/setup/utils.js';
|
|
23
22
|
import { dbConnect, dbConnectAsync, exitApplicationSave } from '../lib/setup/dbConnection.js';
|
|
24
23
|
import { IoBrokerError } from '../lib/setup/customError.js';
|
|
25
|
-
import
|
|
26
|
-
import * as
|
|
24
|
+
import { List } from '../lib/setup/setupList.js';
|
|
25
|
+
import * as formatters from '../lib/setup/formatters.js';
|
|
27
26
|
// eslint-disable-next-line unicorn/prefer-module
|
|
28
27
|
const thisDir = url.fileURLToPath(new URL('.', import.meta.url || `file://${__filename}`));
|
|
29
|
-
import { createRequire } from 'node:module';
|
|
30
|
-
import { SYSTEM_CONFIG_ID, SYSTEM_REPOSITORIES_ID } from '@iobroker/js-controller-common-db/constants';
|
|
31
28
|
// eslint-disable-next-line unicorn/prefer-module
|
|
32
29
|
const require = createRequire(import.meta.url || `file://${__filename}`);
|
|
33
30
|
tools.ensureDNSOrder();
|
|
@@ -435,18 +432,27 @@ function showHelp() {
|
|
|
435
432
|
async function processCommand(command, args, params, callback) {
|
|
436
433
|
const commandContext = { dbConnect, callback, showHelp };
|
|
437
434
|
const commandOptions = { ...params, ...commandContext };
|
|
435
|
+
const options = {
|
|
436
|
+
command,
|
|
437
|
+
args,
|
|
438
|
+
params,
|
|
439
|
+
callback,
|
|
440
|
+
commandOptions,
|
|
441
|
+
cleanDatabase,
|
|
442
|
+
restartController,
|
|
443
|
+
};
|
|
438
444
|
debug(`commandOptions: ${JSON.stringify(commandOptions)}`);
|
|
439
445
|
debug(`args: ${JSON.stringify(args)}`);
|
|
440
446
|
switch (command) {
|
|
441
447
|
case 'start':
|
|
442
448
|
case 'stop': {
|
|
443
449
|
const procCommand = new CLIProcess(commandOptions);
|
|
444
|
-
procCommand[command](args);
|
|
450
|
+
procCommand[command](args).catch(e => console.error(`Cannot ${command}: ${e.message}`));
|
|
445
451
|
break;
|
|
446
452
|
}
|
|
447
453
|
case 'debug': {
|
|
448
454
|
const debugCommand = new CLIDebug(commandOptions);
|
|
449
|
-
debugCommand.execute(args);
|
|
455
|
+
debugCommand.execute(args).catch(e => console.error(`Cannot debug: ${e.message}`));
|
|
450
456
|
break;
|
|
451
457
|
}
|
|
452
458
|
case 'status':
|
|
@@ -458,537 +464,48 @@ async function processCommand(command, args, params, callback) {
|
|
|
458
464
|
case 'r':
|
|
459
465
|
case 'restart': {
|
|
460
466
|
const procCommand = new CLIProcess(commandOptions);
|
|
461
|
-
procCommand.restart(args);
|
|
467
|
+
procCommand.restart(args).catch(e => console.error(`Cannot restart: ${e.message}`));
|
|
462
468
|
break;
|
|
463
469
|
}
|
|
464
470
|
case '_restart':
|
|
465
|
-
restartController();
|
|
471
|
+
restartController().catch(e => console.error(`Cannot restart controller: ${e.message}`));
|
|
466
472
|
callback();
|
|
467
473
|
break;
|
|
468
474
|
case 'update': {
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
const { Repo } = await import('./setup/setupRepo.js');
|
|
472
|
-
const repo = new Repo({
|
|
473
|
-
objects,
|
|
474
|
-
states,
|
|
475
|
-
});
|
|
476
|
-
await repo.showRepo(repoUrl, params);
|
|
477
|
-
setTimeout(callback, 1_000);
|
|
478
|
-
});
|
|
479
|
-
break;
|
|
475
|
+
const { processCommandUpdate } = await import('../lib/setup/setupRepo.js');
|
|
476
|
+
return processCommandUpdate(options);
|
|
480
477
|
}
|
|
481
478
|
case 'setup': {
|
|
482
|
-
const {
|
|
483
|
-
|
|
484
|
-
processExit: callback,
|
|
485
|
-
cleanDatabase,
|
|
486
|
-
restartController,
|
|
487
|
-
params,
|
|
488
|
-
});
|
|
489
|
-
if (args[0] === 'custom' || params.custom) {
|
|
490
|
-
const exitCode = await setup.setupCustom();
|
|
491
|
-
callback(exitCode);
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
let isFirst = false;
|
|
495
|
-
let isRedis = false;
|
|
496
|
-
// we support "first" and "redis" without "--" flag
|
|
497
|
-
for (const arg of args) {
|
|
498
|
-
if (arg === 'first') {
|
|
499
|
-
isFirst = true;
|
|
500
|
-
}
|
|
501
|
-
else if (arg === 'redis') {
|
|
502
|
-
isRedis = true;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
// and as --flag
|
|
506
|
-
isRedis = params.redis || isRedis;
|
|
507
|
-
isFirst = params.first || isFirst;
|
|
508
|
-
setup.setup({
|
|
509
|
-
callback: async () => {
|
|
510
|
-
const { states, objects } = await dbConnectAsync(false, params);
|
|
511
|
-
if (isFirst) {
|
|
512
|
-
// Creates all instances that are needed on a fresh installation
|
|
513
|
-
const { Install } = await import('./setup/setupInstall.js');
|
|
514
|
-
const install = new Install({
|
|
515
|
-
objects,
|
|
516
|
-
states,
|
|
517
|
-
processExit: callback,
|
|
518
|
-
params,
|
|
519
|
-
});
|
|
520
|
-
// Define the necessary instances
|
|
521
|
-
const initialInstances = ['admin', 'discovery', 'backitup'];
|
|
522
|
-
// And try to install each of them
|
|
523
|
-
for (const instance of initialInstances) {
|
|
524
|
-
try {
|
|
525
|
-
const adapterInstalled = !!require.resolve(`${tools.appName.toLowerCase()}.${instance}`);
|
|
526
|
-
if (adapterInstalled) {
|
|
527
|
-
let otherInstanceExists = false;
|
|
528
|
-
try {
|
|
529
|
-
// check if another instance exists
|
|
530
|
-
const res = await objects.getObjectViewAsync('system', 'instance', {
|
|
531
|
-
startkey: `system.adapter.${instance}`,
|
|
532
|
-
endkey: `system.adapter.${instance}\u9999`,
|
|
533
|
-
});
|
|
534
|
-
otherInstanceExists = !!res.rows.length;
|
|
535
|
-
}
|
|
536
|
-
catch {
|
|
537
|
-
// ignore - on install we have no object views
|
|
538
|
-
}
|
|
539
|
-
if (!otherInstanceExists) {
|
|
540
|
-
await install.createInstance(instance, {
|
|
541
|
-
enabled: true,
|
|
542
|
-
ignoreIfExists: true,
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
catch {
|
|
548
|
-
// not found, just continue
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
await new Promise(resolve => {
|
|
552
|
-
// Creates a fresh certificate
|
|
553
|
-
// Create a new instance of the cert command,
|
|
554
|
-
// but use the resolve method as a callback
|
|
555
|
-
const cert = new CLICert({ ...commandOptions, callback: resolve });
|
|
556
|
-
cert.create();
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
// we update existing things, in first as well as normal setup
|
|
560
|
-
// Rename repositories
|
|
561
|
-
const { Repo } = await import('./setup/setupRepo.js');
|
|
562
|
-
const repo = new Repo({ objects, states });
|
|
563
|
-
try {
|
|
564
|
-
await repo.rename('default', 'stable', STABLE_REPO_URL);
|
|
565
|
-
await repo.rename('latest', 'beta', BETA_REPO_URL);
|
|
566
|
-
}
|
|
567
|
-
catch (err) {
|
|
568
|
-
console.warn(`Cannot rename: ${err.message}`);
|
|
569
|
-
}
|
|
570
|
-
// there has been a bug that user can upload js-controller
|
|
571
|
-
try {
|
|
572
|
-
await objects.delObjectAsync('system.adapter.js-controller');
|
|
573
|
-
}
|
|
574
|
-
catch {
|
|
575
|
-
// ignore
|
|
576
|
-
}
|
|
577
|
-
try {
|
|
578
|
-
const configFile = tools.getConfigFileName();
|
|
579
|
-
const configOrig = fs.readJSONSync(configFile);
|
|
580
|
-
const config = deepClone(configOrig);
|
|
581
|
-
config.objects.options = config.objects.options || {
|
|
582
|
-
auth_pass: null,
|
|
583
|
-
retry_max_delay: 5_000,
|
|
584
|
-
};
|
|
585
|
-
if (config.objects.options.retry_max_delay === 15_000 ||
|
|
586
|
-
!config.objects.options.retry_max_delay) {
|
|
587
|
-
config.objects.options.retry_max_delay = 5_000;
|
|
588
|
-
}
|
|
589
|
-
config.states.options = config.states.options || {
|
|
590
|
-
auth_pass: null,
|
|
591
|
-
retry_max_delay: 5_000,
|
|
592
|
-
};
|
|
593
|
-
if (config.states.options.retry_max_delay === 15_000 ||
|
|
594
|
-
!config.states.options.retry_max_delay) {
|
|
595
|
-
config.states.options.retry_max_delay = 5_000;
|
|
596
|
-
}
|
|
597
|
-
let migrated = '';
|
|
598
|
-
// We migrate file to jsonl
|
|
599
|
-
if (config.states.type === 'file') {
|
|
600
|
-
config.states.type = 'jsonl';
|
|
601
|
-
const hasLocalStatesServer = await isLocalStatesDbServer('file', config.states.host);
|
|
602
|
-
if (hasLocalStatesServer) {
|
|
603
|
-
// silent config change on secondaries
|
|
604
|
-
console.log('States DB type migrated from "file" to "jsonl"');
|
|
605
|
-
migrated += 'States';
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
if (config.objects.type === 'file') {
|
|
609
|
-
config.objects.type = 'jsonl';
|
|
610
|
-
const hasLocalObjectsServer = await isLocalObjectsDbServer('file', config.objects.host);
|
|
611
|
-
if (hasLocalObjectsServer) {
|
|
612
|
-
// silent config change on secondaries
|
|
613
|
-
console.log('Objects DB type migrated from "file" to "jsonl"');
|
|
614
|
-
migrated += migrated ? ' and Objects' : 'Objects';
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
if (migrated) {
|
|
618
|
-
const { NotificationHandler } = await import('@iobroker/js-controller-common');
|
|
619
|
-
const hostname = tools.getHostName();
|
|
620
|
-
const notificationSettings = {
|
|
621
|
-
states,
|
|
622
|
-
objects,
|
|
623
|
-
log: console,
|
|
624
|
-
logPrefix: '',
|
|
625
|
-
host: hostname,
|
|
626
|
-
};
|
|
627
|
-
const notificationHandler = new NotificationHandler(notificationSettings);
|
|
628
|
-
try {
|
|
629
|
-
const ioPackage = fs.readJsonSync(path.join(tools.getControllerDir(), 'io-package.json'));
|
|
630
|
-
await notificationHandler.addConfig(ioPackage.notifications);
|
|
631
|
-
await notificationHandler.addMessage({
|
|
632
|
-
scope: 'system',
|
|
633
|
-
category: 'fileToJsonl',
|
|
634
|
-
message: `Migrated: ${migrated}`,
|
|
635
|
-
instance: `system.host.${hostname}`,
|
|
636
|
-
});
|
|
637
|
-
notificationHandler.storeNotifications();
|
|
638
|
-
}
|
|
639
|
-
catch (e) {
|
|
640
|
-
console.warn(`Could not add File-to-JSONL notification: ${e.message}`);
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
if (!isDeepStrictEqual(config, configOrig)) {
|
|
644
|
-
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
645
|
-
console.log('ioBroker configuration updated');
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
catch (err) {
|
|
649
|
-
console.log(`Could not update ioBroker configuration: ${err.message}`);
|
|
650
|
-
}
|
|
651
|
-
return void callback();
|
|
652
|
-
},
|
|
653
|
-
ignoreIfExist: isFirst,
|
|
654
|
-
useRedis: isRedis,
|
|
655
|
-
});
|
|
656
|
-
break;
|
|
479
|
+
const { processCommandSetup } = await import('../lib/setup/setupSetup.js');
|
|
480
|
+
return processCommandSetup(options);
|
|
657
481
|
}
|
|
658
482
|
case 'url': {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
if (!url) {
|
|
662
|
-
console.log('Please provide a URL to install from and optionally a name of the adapter to install');
|
|
663
|
-
callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
664
|
-
}
|
|
665
|
-
if (url[0] === '"' && url[url.length - 1] === '"') {
|
|
666
|
-
url = url.substring(1, url.length - 1);
|
|
667
|
-
}
|
|
668
|
-
url = url.trim();
|
|
669
|
-
dbConnect(params, async ({ objects, states }) => {
|
|
670
|
-
const { Install } = await import('./setup/setupInstall.js');
|
|
671
|
-
const install = new Install({
|
|
672
|
-
objects,
|
|
673
|
-
states,
|
|
674
|
-
processExit: callback,
|
|
675
|
-
params,
|
|
676
|
-
});
|
|
677
|
-
try {
|
|
678
|
-
await install.installAdapterFromUrl(url, name);
|
|
679
|
-
return void callback(EXIT_CODES.NO_ERROR);
|
|
680
|
-
}
|
|
681
|
-
catch (e) {
|
|
682
|
-
console.error(`Could not install adapter from url: ${e.message}`);
|
|
683
|
-
return void callback(EXIT_CODES.CANNOT_INSTALL_NPM_PACKET);
|
|
684
|
-
}
|
|
685
|
-
});
|
|
686
|
-
break;
|
|
687
|
-
}
|
|
688
|
-
case 'info': {
|
|
689
|
-
dbConnect(params, async ({ objects }) => {
|
|
690
|
-
try {
|
|
691
|
-
const data = await tools.getHostInfo(objects);
|
|
692
|
-
const formatters = await import('./setup/formatters.js');
|
|
693
|
-
const formatInfo = {
|
|
694
|
-
Uptime: formatters.formatSeconds,
|
|
695
|
-
'System uptime': formatters.formatSeconds,
|
|
696
|
-
RAM: formatters.formatRam,
|
|
697
|
-
Speed: formatters.formatSpeed,
|
|
698
|
-
'Disk size': formatters.formatBytes,
|
|
699
|
-
'Disk free': formatters.formatBytes,
|
|
700
|
-
};
|
|
701
|
-
for (const attr of Object.keys(data)) {
|
|
702
|
-
console.log(`${attr}${attr.length < 16 ? new Array(16 - attr.length).join(' ') : ''}: ${
|
|
703
|
-
// @ts-expect-error todo would need checks
|
|
704
|
-
formatInfo[attr] ? formatInfo[attr](data[attr]) : data[attr] || ''}`);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
catch (err) {
|
|
708
|
-
console.error(`Cannot read host info: ${typeof err === 'object' ? JSON.stringify(err) : err}`);
|
|
709
|
-
return callback(EXIT_CODES.CANNOT_GET_HOST_INFO);
|
|
710
|
-
}
|
|
711
|
-
return void callback();
|
|
712
|
-
});
|
|
713
|
-
break;
|
|
483
|
+
const { processCommandUrl } = await import('../lib/setup/setupInstall.js');
|
|
484
|
+
return processCommandUrl(options);
|
|
714
485
|
}
|
|
486
|
+
case 'info':
|
|
487
|
+
return processCommandInfo(options);
|
|
715
488
|
case 'a':
|
|
716
489
|
case 'add':
|
|
717
490
|
case 'install':
|
|
718
491
|
case 'i': {
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
let repoUrl = args[2];
|
|
722
|
-
if (parseInt(instance, 10).toString() !== (instance || '').toString()) {
|
|
723
|
-
repoUrl = instance;
|
|
724
|
-
instance = undefined;
|
|
725
|
-
}
|
|
726
|
-
if (parseInt(repoUrl, 10).toString() === (repoUrl || '').toString()) {
|
|
727
|
-
const temp = instance;
|
|
728
|
-
instance = repoUrl;
|
|
729
|
-
repoUrl = temp;
|
|
730
|
-
}
|
|
731
|
-
if (instance && parseInt(instance, 10).toString() === (instance || '').toString()) {
|
|
732
|
-
params.instance = parseInt(instance, 10);
|
|
733
|
-
}
|
|
734
|
-
// If user accidentally wrote tools.appName.adapter => remove adapter
|
|
735
|
-
name = CLITools.normalizeAdapterName(name);
|
|
736
|
-
const parsedName = CLITools.splitAdapterOrInstanceIdentifierWithVersion(name);
|
|
737
|
-
if (!parsedName) {
|
|
738
|
-
console.log('Invalid adapter name for install');
|
|
739
|
-
showHelp();
|
|
740
|
-
return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
|
|
741
|
-
}
|
|
742
|
-
// split the adapter into its parts if necessary
|
|
743
|
-
if (parsedName.instance !== null) {
|
|
744
|
-
params.instance = parsedName.instance;
|
|
745
|
-
}
|
|
746
|
-
name = parsedName.name;
|
|
747
|
-
const installName = parsedName.nameWithVersion;
|
|
748
|
-
const adapterDir = tools.getAdapterDir(name);
|
|
749
|
-
dbConnect(params, async ({ objects, states }) => {
|
|
750
|
-
const { Install } = await import('./setup/setupInstall.js');
|
|
751
|
-
const install = new Install({
|
|
752
|
-
objects,
|
|
753
|
-
states,
|
|
754
|
-
processExit: callback,
|
|
755
|
-
params,
|
|
756
|
-
});
|
|
757
|
-
if (params.host && params.host !== tools.getHostName()) {
|
|
758
|
-
// if host argument provided we should check, that host actually exists in mh environment
|
|
759
|
-
let obj;
|
|
760
|
-
try {
|
|
761
|
-
obj = await objects.getObjectAsync(`system.host.${params.host}`);
|
|
762
|
-
}
|
|
763
|
-
catch (err) {
|
|
764
|
-
console.warn(`Could not check existence of host "${params.host}": ${err.message}`);
|
|
765
|
-
}
|
|
766
|
-
if (!obj) {
|
|
767
|
-
console.error(`Cannot add instance to non-existing host "${params.host}"`);
|
|
768
|
-
return void callback(EXIT_CODES.NON_EXISTING_HOST);
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
if (!adapterDir || !fs.existsSync(adapterDir)) {
|
|
772
|
-
try {
|
|
773
|
-
const { stoppedList } = await install.downloadPacket(repoUrl, installName);
|
|
774
|
-
await install.installAdapter(installName, repoUrl);
|
|
775
|
-
await install.enableInstances(stoppedList, true); // even if unlikely make sure to re-enable disabled instances
|
|
776
|
-
if (command !== 'install' && command !== 'i') {
|
|
777
|
-
await install.createInstance(name, params);
|
|
778
|
-
}
|
|
779
|
-
return void callback();
|
|
780
|
-
}
|
|
781
|
-
catch (e) {
|
|
782
|
-
console.error(`adapter "${name}" cannot be installed: ${e.message}`);
|
|
783
|
-
return void callback(e instanceof IoBrokerError ? e.code : EXIT_CODES.UNKNOWN_ERROR);
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
else if (command !== 'install' && command !== 'i') {
|
|
787
|
-
try {
|
|
788
|
-
await install.createInstance(name, params);
|
|
789
|
-
return void callback();
|
|
790
|
-
}
|
|
791
|
-
catch (err) {
|
|
792
|
-
console.error(`adapter "${name}" cannot be installed: ${err.message}`);
|
|
793
|
-
return void callback(EXIT_CODES.UNKNOWN_ERROR);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
console.log(`adapter "${name}" already installed. Use "upgrade" to upgrade to a newer version.`);
|
|
798
|
-
return void callback(EXIT_CODES.ADAPTER_ALREADY_INSTALLED);
|
|
799
|
-
}
|
|
800
|
-
});
|
|
801
|
-
break;
|
|
802
|
-
}
|
|
803
|
-
case 'rebuild': {
|
|
804
|
-
const options = { debug: process.argv.includes('--debug') };
|
|
805
|
-
if (commandOptions.path) {
|
|
806
|
-
if (path.isAbsolute(commandOptions.path)) {
|
|
807
|
-
options.cwd = commandOptions.path;
|
|
808
|
-
}
|
|
809
|
-
else {
|
|
810
|
-
console.log('Path argument needs to be an absolute path!');
|
|
811
|
-
return void exitApplicationSave(EXIT_CODES.INVALID_ARGUMENTS);
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
if (commandOptions.module) {
|
|
815
|
-
options.module = commandOptions.module;
|
|
816
|
-
console.log(`Rebuilding native module "${commandOptions.module}"${options.cwd ? ` in ${options.cwd}` : ''} ...`);
|
|
817
|
-
}
|
|
818
|
-
else {
|
|
819
|
-
console.log(`Rebuilding native modules${options.cwd ? ` in ${options.cwd}` : ''} ...`);
|
|
820
|
-
}
|
|
821
|
-
const result = await tools.rebuildNodeModules(options);
|
|
822
|
-
if (result.success) {
|
|
823
|
-
console.log();
|
|
824
|
-
console.log(`Rebuilding native modules done`);
|
|
825
|
-
return void callback();
|
|
826
|
-
}
|
|
827
|
-
console.error('Rebuilding native modules failed');
|
|
828
|
-
return void exitApplicationSave(result.exitCode);
|
|
492
|
+
const { processCommandInstall } = await import('../lib/setup/setupInstall.js');
|
|
493
|
+
return processCommandInstall(options);
|
|
829
494
|
}
|
|
495
|
+
case 'rebuild':
|
|
496
|
+
return processCommandRebuild(options);
|
|
830
497
|
case 'upload':
|
|
831
498
|
case 'u': {
|
|
832
|
-
const
|
|
833
|
-
|
|
834
|
-
if (name) {
|
|
835
|
-
dbConnect(params, async ({ objects, states }) => {
|
|
836
|
-
const { Upload } = await import('./setup/setupUpload.js');
|
|
837
|
-
const upload = new Upload({ states, objects });
|
|
838
|
-
if (name === 'all') {
|
|
839
|
-
try {
|
|
840
|
-
const objs = await objects.getObjectListAsync({
|
|
841
|
-
startkey: 'system.adapter.',
|
|
842
|
-
endkey: 'system.adapter.\u9999',
|
|
843
|
-
});
|
|
844
|
-
if (objs) {
|
|
845
|
-
const adapters = [];
|
|
846
|
-
for (const row of objs.rows) {
|
|
847
|
-
if (row.value.type !== 'adapter') {
|
|
848
|
-
continue;
|
|
849
|
-
}
|
|
850
|
-
adapters.push(tools.isObject(row.value.common.name)
|
|
851
|
-
? row.value.common.name.en
|
|
852
|
-
: row.value.common.name);
|
|
853
|
-
}
|
|
854
|
-
await upload.uploadAdapterFullAsync(adapters);
|
|
855
|
-
}
|
|
856
|
-
callback();
|
|
857
|
-
}
|
|
858
|
-
catch (err) {
|
|
859
|
-
console.error(`Cannot upload all adapters: ${err.message}`);
|
|
860
|
-
return void callback(EXIT_CODES.CANNOT_UPLOAD_DATA);
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
else {
|
|
864
|
-
// if upload of file
|
|
865
|
-
if (name.includes('.')) {
|
|
866
|
-
if (!subTree) {
|
|
867
|
-
console.log(`Please specify target name, like:\n${tools.appName} upload /file/picture.png /vis-2.0/main/img/picture.png`);
|
|
868
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
869
|
-
}
|
|
870
|
-
try {
|
|
871
|
-
const newName = await upload.uploadFile(name, subTree);
|
|
872
|
-
console.log(`File "${name}" is successfully saved under ${newName}`);
|
|
873
|
-
return void callback();
|
|
874
|
-
}
|
|
875
|
-
catch (err) {
|
|
876
|
-
console.error(`Cannot upload file "${name}": ${err.message}`);
|
|
877
|
-
return void callback(EXIT_CODES.CANNOT_UPLOAD_DATA);
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
else {
|
|
881
|
-
try {
|
|
882
|
-
if (subTree) {
|
|
883
|
-
await upload.uploadAdapter(name, false, true, subTree);
|
|
884
|
-
}
|
|
885
|
-
else {
|
|
886
|
-
await upload.uploadAdapterFullAsync([name]);
|
|
887
|
-
}
|
|
888
|
-
return void callback();
|
|
889
|
-
}
|
|
890
|
-
catch (err) {
|
|
891
|
-
console.error(`Cannot upload files "${name}": ${err.message}`);
|
|
892
|
-
return void callback(EXIT_CODES.CANNOT_UPLOAD_DATA);
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
});
|
|
897
|
-
}
|
|
898
|
-
else {
|
|
899
|
-
console.log('No adapter name found!');
|
|
900
|
-
showHelp();
|
|
901
|
-
return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
|
|
902
|
-
}
|
|
903
|
-
break;
|
|
499
|
+
const { processCommandUpload } = await import('../lib/setup/setupUpload.js');
|
|
500
|
+
return processCommandUpload(options);
|
|
904
501
|
}
|
|
905
502
|
case 'delete':
|
|
906
503
|
case 'del': {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
// The adapter argument is required
|
|
910
|
-
if (!adapter) {
|
|
911
|
-
showHelp();
|
|
912
|
-
return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
|
|
913
|
-
}
|
|
914
|
-
// If the user accidentally wrote <tools.appName>.adapter,
|
|
915
|
-
// remove <tools.appName> from the adapter name
|
|
916
|
-
adapter = CLITools.normalizeAdapterName(adapter);
|
|
917
|
-
// Avoid deleting stuff we don't want to delete
|
|
918
|
-
// e.g. `system.adapter.*`
|
|
919
|
-
if (!instance) {
|
|
920
|
-
// Ensure that adapter contains a valid adapter (without instance nr)
|
|
921
|
-
// or instance (with instance nr) identifier
|
|
922
|
-
if (!CLITools.validateAdapterOrInstanceIdentifier(adapter)) {
|
|
923
|
-
showHelp();
|
|
924
|
-
return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
|
|
925
|
-
}
|
|
926
|
-
// split the adapter into adapter + instance if necessary
|
|
927
|
-
if (adapter.indexOf('.') > -1) {
|
|
928
|
-
[adapter, instance] = adapter.split('.', 2);
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
else {
|
|
932
|
-
// ensure that adapter contains a valid adapter identifier
|
|
933
|
-
// and the instance is a number
|
|
934
|
-
if (!CLITools.validateAdapterIdentifier(adapter) || !/^\d+$/.test(instance)) {
|
|
935
|
-
showHelp();
|
|
936
|
-
return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
if (instance) {
|
|
940
|
-
dbConnect(params, async ({ objects, states }) => {
|
|
941
|
-
const { Install } = await import('../lib/setup/setupInstall.js');
|
|
942
|
-
const install = new Install({
|
|
943
|
-
objects,
|
|
944
|
-
states,
|
|
945
|
-
processExit: callback,
|
|
946
|
-
params,
|
|
947
|
-
});
|
|
948
|
-
console.log(`Delete instance "${adapter}.${instance}"`);
|
|
949
|
-
await install.deleteInstance(adapter, parseInt(instance));
|
|
950
|
-
callback();
|
|
951
|
-
});
|
|
952
|
-
}
|
|
953
|
-
else {
|
|
954
|
-
dbConnect(params, async ({ objects, states }) => {
|
|
955
|
-
const { Install } = await import('../lib/setup/setupInstall.js');
|
|
956
|
-
const install = new Install({
|
|
957
|
-
objects,
|
|
958
|
-
states,
|
|
959
|
-
processExit: callback,
|
|
960
|
-
params,
|
|
961
|
-
});
|
|
962
|
-
console.log(`Delete adapter "${adapter}"`);
|
|
963
|
-
const resultCode = await install.deleteAdapter(adapter);
|
|
964
|
-
callback(resultCode);
|
|
965
|
-
});
|
|
966
|
-
}
|
|
967
|
-
break;
|
|
968
|
-
}
|
|
969
|
-
case 'unsetup': {
|
|
970
|
-
const rl = (await import('node:readline')).createInterface({
|
|
971
|
-
input: process.stdin,
|
|
972
|
-
output: process.stdout,
|
|
973
|
-
});
|
|
974
|
-
if (params.yes || params.y || params.Y) {
|
|
975
|
-
unsetup(params, callback);
|
|
976
|
-
}
|
|
977
|
-
else {
|
|
978
|
-
rl.question('UUID will be deleted. Are you sure? [y/N]: ', answer => {
|
|
979
|
-
rl.close();
|
|
980
|
-
answer = answer.toLowerCase();
|
|
981
|
-
if (answer === 'y' || answer === 'yes' || answer === 'ja' || answer === 'j') {
|
|
982
|
-
unsetup(params, callback);
|
|
983
|
-
}
|
|
984
|
-
else {
|
|
985
|
-
console.log('Nothing deleted');
|
|
986
|
-
return void callback();
|
|
987
|
-
}
|
|
988
|
-
});
|
|
989
|
-
}
|
|
990
|
-
break;
|
|
504
|
+
const { processCommandDelete } = await import('../lib/setup/setupInstall.js');
|
|
505
|
+
return processCommandDelete(options);
|
|
991
506
|
}
|
|
507
|
+
case 'unsetup':
|
|
508
|
+
return processCommandUnsetup(options);
|
|
992
509
|
case 'o':
|
|
993
510
|
case 'object': {
|
|
994
511
|
const objectsCommand = new CLIObjects(commandOptions);
|
|
@@ -1013,159 +530,26 @@ async function processCommand(command, args, params, callback) {
|
|
|
1013
530
|
break;
|
|
1014
531
|
}
|
|
1015
532
|
case 'upgrade': {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
adapter = null;
|
|
1019
|
-
}
|
|
1020
|
-
dbConnect(params, async ({ objects, states }) => {
|
|
1021
|
-
const { Upgrade } = await import('./setup/setupUpgrade.js');
|
|
1022
|
-
const upgrade = new Upgrade({
|
|
1023
|
-
objects,
|
|
1024
|
-
states,
|
|
1025
|
-
params,
|
|
1026
|
-
processExit: callback,
|
|
1027
|
-
});
|
|
1028
|
-
if (adapter) {
|
|
1029
|
-
try {
|
|
1030
|
-
if (adapter.split('@')[0] === 'self') {
|
|
1031
|
-
const hostAlive = await states.getStateAsync(`system.host.${tools.getHostName()}.alive`);
|
|
1032
|
-
const version = adapter.split('@')[1];
|
|
1033
|
-
await upgrade.upgradeController({
|
|
1034
|
-
forceDowngrade: params.force || params.f,
|
|
1035
|
-
controllerRunning: !!hostAlive?.val,
|
|
1036
|
-
version,
|
|
1037
|
-
});
|
|
1038
|
-
}
|
|
1039
|
-
else {
|
|
1040
|
-
await upgrade.upgradeAdapter('', adapter, params.force || params.f, params.y || params.yes, false);
|
|
1041
|
-
}
|
|
1042
|
-
return void callback();
|
|
1043
|
-
}
|
|
1044
|
-
catch (err) {
|
|
1045
|
-
console.error(`Cannot upgrade: ${err.message}`);
|
|
1046
|
-
return void callback(EXIT_CODES.INVALID_REPO);
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
else {
|
|
1050
|
-
// upgrade all
|
|
1051
|
-
try {
|
|
1052
|
-
const links = await getRepository({ objects });
|
|
1053
|
-
if (!links) {
|
|
1054
|
-
return void callback(EXIT_CODES.INVALID_REPO);
|
|
1055
|
-
}
|
|
1056
|
-
await upgrade.upgradeAdapterHelper(links, Object.keys(links).sort(), false, params.y || params.yes);
|
|
1057
|
-
return void callback();
|
|
1058
|
-
}
|
|
1059
|
-
catch (e) {
|
|
1060
|
-
console.error(`Cannot upgrade: ${e.message}`);
|
|
1061
|
-
return void callback(e instanceof IoBrokerError ? e.code : EXIT_CODES.INVALID_REPO);
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
});
|
|
1065
|
-
break;
|
|
1066
|
-
}
|
|
1067
|
-
case 'clean': {
|
|
1068
|
-
const yes = args[0];
|
|
1069
|
-
if (yes !== 'yes') {
|
|
1070
|
-
console.log(`Command "clean" clears all Objects and States. To execute it write "${tools.appName} clean yes"`);
|
|
1071
|
-
}
|
|
1072
|
-
else {
|
|
1073
|
-
dbConnect(params, async ({ isOffline }) => {
|
|
1074
|
-
if (!isOffline) {
|
|
1075
|
-
console.error(`Stop ${tools.appName} first!`);
|
|
1076
|
-
return void callback(EXIT_CODES.CONTROLLER_RUNNING);
|
|
1077
|
-
}
|
|
1078
|
-
try {
|
|
1079
|
-
const count = await cleanDatabase(true);
|
|
1080
|
-
console.log(`Deleted ${count} states`);
|
|
1081
|
-
}
|
|
1082
|
-
catch {
|
|
1083
|
-
// ignore
|
|
1084
|
-
}
|
|
1085
|
-
restartController();
|
|
1086
|
-
console.log(`Restarting ${tools.appName}...`);
|
|
1087
|
-
callback();
|
|
1088
|
-
});
|
|
1089
|
-
}
|
|
1090
|
-
break;
|
|
533
|
+
const { processCommandUpgrade } = await import('../lib/setup/setupUpgrade.js');
|
|
534
|
+
return processCommandUpgrade(options);
|
|
1091
535
|
}
|
|
536
|
+
case 'clean':
|
|
537
|
+
return processCommandClean(options);
|
|
1092
538
|
case 'restore': {
|
|
1093
|
-
const {
|
|
1094
|
-
|
|
1095
|
-
if (!isOffline) {
|
|
1096
|
-
console.error(`Stop ${tools.appName} first!`);
|
|
1097
|
-
return void callback(EXIT_CODES.CONTROLLER_RUNNING);
|
|
1098
|
-
}
|
|
1099
|
-
const backup = new BackupRestore({
|
|
1100
|
-
states,
|
|
1101
|
-
objects,
|
|
1102
|
-
cleanDatabase,
|
|
1103
|
-
restartController,
|
|
1104
|
-
processExit: callback,
|
|
1105
|
-
});
|
|
1106
|
-
const { exitCode } = await backup.restoreBackup({
|
|
1107
|
-
name: args[0],
|
|
1108
|
-
force: !!params.force,
|
|
1109
|
-
dontDeleteAdapters: false,
|
|
1110
|
-
});
|
|
1111
|
-
if (exitCode === EXIT_CODES.NO_ERROR) {
|
|
1112
|
-
console.log('System successfully restored!');
|
|
1113
|
-
}
|
|
1114
|
-
return void callback(exitCode);
|
|
1115
|
-
});
|
|
1116
|
-
break;
|
|
539
|
+
const { processCommandRestore } = await import('../lib/setup/setupBackup.js');
|
|
540
|
+
return processCommandRestore(options);
|
|
1117
541
|
}
|
|
1118
542
|
case 'backup': {
|
|
1119
|
-
const
|
|
1120
|
-
|
|
1121
|
-
dbConnect(params, async ({ states, objects }) => {
|
|
1122
|
-
const backup = new BackupRestore({
|
|
1123
|
-
states,
|
|
1124
|
-
objects,
|
|
1125
|
-
cleanDatabase,
|
|
1126
|
-
restartController,
|
|
1127
|
-
processExit: callback,
|
|
1128
|
-
});
|
|
1129
|
-
try {
|
|
1130
|
-
const filePath = await backup.createBackup(name);
|
|
1131
|
-
console.log(`Backup created: ${filePath}`);
|
|
1132
|
-
console.log('This backup can only be restored with js-controller version 7.0 or higher');
|
|
1133
|
-
return void callback(EXIT_CODES.NO_ERROR);
|
|
1134
|
-
}
|
|
1135
|
-
catch (e) {
|
|
1136
|
-
console.log(`Cannot create backup: ${e.message}`);
|
|
1137
|
-
return void callback(e instanceof IoBrokerError ? e.code : EXIT_CODES.CANNOT_EXTRACT_FROM_ZIP);
|
|
1138
|
-
}
|
|
1139
|
-
});
|
|
1140
|
-
break;
|
|
543
|
+
const { processCommandBackup } = await import('../lib/setup/setupBackup.js');
|
|
544
|
+
return processCommandBackup(options);
|
|
1141
545
|
}
|
|
1142
546
|
case 'validate': {
|
|
1143
|
-
const
|
|
1144
|
-
|
|
1145
|
-
dbConnect(params, async ({ objects, states }) => {
|
|
1146
|
-
const backup = new BackupRestore({
|
|
1147
|
-
states,
|
|
1148
|
-
objects,
|
|
1149
|
-
cleanDatabase,
|
|
1150
|
-
restartController,
|
|
1151
|
-
processExit: callback,
|
|
1152
|
-
});
|
|
1153
|
-
try {
|
|
1154
|
-
await backup.validateBackup(name);
|
|
1155
|
-
console.log('Backup OK');
|
|
1156
|
-
return void exitApplicationSave(0);
|
|
1157
|
-
}
|
|
1158
|
-
catch (e) {
|
|
1159
|
-
console.log(`Backup check failed: ${e.message}`);
|
|
1160
|
-
return void exitApplicationSave(e instanceof IoBrokerError ? e.code : 1);
|
|
1161
|
-
}
|
|
1162
|
-
});
|
|
1163
|
-
break;
|
|
547
|
+
const { processCommandValidate } = await import('../lib/setup/setupBackup.js');
|
|
548
|
+
return processCommandValidate(options);
|
|
1164
549
|
}
|
|
1165
550
|
case 'l':
|
|
1166
551
|
case 'list': {
|
|
1167
|
-
dbConnect(params,
|
|
1168
|
-
const { List } = await import('./setup/setupList.js');
|
|
552
|
+
dbConnect(params, ({ objects, states }) => {
|
|
1169
553
|
const list = new List({
|
|
1170
554
|
states,
|
|
1171
555
|
objects,
|
|
@@ -1175,1343 +559,1011 @@ async function processCommand(command, args, params, callback) {
|
|
|
1175
559
|
});
|
|
1176
560
|
break;
|
|
1177
561
|
}
|
|
1178
|
-
case 'touch':
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
for (const file of files) {
|
|
1218
|
-
for (const processedFile of processed) {
|
|
1219
|
-
list.showFile(file.id, processedFile.path, processedFile);
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
setTimeout(callback, 1_000);
|
|
1223
|
-
}
|
|
1224
|
-
});
|
|
1225
|
-
}
|
|
1226
|
-
if (!count) {
|
|
1227
|
-
console.log('Nothing found');
|
|
1228
|
-
return void callback();
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
});
|
|
1232
|
-
}
|
|
1233
|
-
else {
|
|
1234
|
-
const parts = pattern.split('/');
|
|
1235
|
-
const id = parts.shift();
|
|
1236
|
-
const path = parts.join('/');
|
|
1237
|
-
// @ts-expect-error todo processed should not exist, how to proceed?
|
|
1238
|
-
objects.touch(id, path, { user: 'system.user.admin' }, async (err, processed) => {
|
|
1239
|
-
if (err) {
|
|
1240
|
-
console.error(err);
|
|
1241
|
-
}
|
|
1242
|
-
else {
|
|
1243
|
-
if (processed) {
|
|
1244
|
-
const { List } = await import('./setup/setupList.js');
|
|
1245
|
-
const list = new List({
|
|
1246
|
-
states,
|
|
1247
|
-
objects,
|
|
1248
|
-
processExit: callback,
|
|
1249
|
-
});
|
|
1250
|
-
for (const processedFile of processed) {
|
|
1251
|
-
list.showFile(id, processedFile.path, processedFile);
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
setTimeout(callback, 1_000);
|
|
1256
|
-
});
|
|
1257
|
-
}
|
|
1258
|
-
});
|
|
562
|
+
case 'touch':
|
|
563
|
+
return processCommandTouch(options);
|
|
564
|
+
case 'rm':
|
|
565
|
+
return processCommandRm(options);
|
|
566
|
+
case 'chmod':
|
|
567
|
+
return processCommandChmod(options);
|
|
568
|
+
case 'chown':
|
|
569
|
+
return processCommandChown(options);
|
|
570
|
+
case 'user': {
|
|
571
|
+
const { processCommandUser } = await import('../lib/setup/setupUsers.js');
|
|
572
|
+
return processCommandUser(options);
|
|
573
|
+
}
|
|
574
|
+
case 'g':
|
|
575
|
+
case 'group': {
|
|
576
|
+
const { processCommandGroup } = await import('../lib/setup/setupUsers.js');
|
|
577
|
+
return processCommandGroup(options);
|
|
578
|
+
}
|
|
579
|
+
case 'adduser': {
|
|
580
|
+
const { processCommandAddUser } = await import('../lib/setup/setupUsers.js');
|
|
581
|
+
return processCommandAddUser(options);
|
|
582
|
+
}
|
|
583
|
+
case 'passwd': {
|
|
584
|
+
const { processCommandPassword } = await import('../lib/setup/setupUsers.js');
|
|
585
|
+
return processCommandPassword(options);
|
|
586
|
+
}
|
|
587
|
+
case 'ud':
|
|
588
|
+
case 'udel':
|
|
589
|
+
case 'userdel':
|
|
590
|
+
case 'deluser': {
|
|
591
|
+
const { processCommandUserDel } = await import('../lib/setup/setupUsers.js');
|
|
592
|
+
return processCommandUserDel(options);
|
|
593
|
+
}
|
|
594
|
+
case 'package':
|
|
595
|
+
return processCommandPackage(options);
|
|
596
|
+
case 'set':
|
|
597
|
+
return processCommandSet(options);
|
|
598
|
+
case 'host': {
|
|
599
|
+
const hostCommand = new CLIHost(commandOptions);
|
|
600
|
+
hostCommand.execute(args);
|
|
1259
601
|
break;
|
|
1260
602
|
}
|
|
1261
|
-
case '
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
console.log('No file path found. Example: "touch /vis-2.0/main/*"');
|
|
1265
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1266
|
-
}
|
|
1267
|
-
dbConnect(params, ({ objects, states }) => {
|
|
1268
|
-
// extract id
|
|
1269
|
-
pattern = pattern.replace(/\\/g, '/');
|
|
1270
|
-
if (pattern[0] === '/') {
|
|
1271
|
-
pattern = pattern.substring(1);
|
|
1272
|
-
}
|
|
1273
|
-
if (pattern === '*') {
|
|
1274
|
-
objects.getObjectList({
|
|
1275
|
-
startkey: 'system.adapter.',
|
|
1276
|
-
endkey: 'system.adapter.\u9999',
|
|
1277
|
-
}, (err, arr) => {
|
|
1278
|
-
if (!err && arr?.rows) {
|
|
1279
|
-
const files = [];
|
|
1280
|
-
let count = 0;
|
|
1281
|
-
for (const row of arr.rows) {
|
|
1282
|
-
if (row.value.type !== 'adapter') {
|
|
1283
|
-
continue;
|
|
1284
|
-
}
|
|
1285
|
-
count++;
|
|
1286
|
-
objects.rm(row.value.common.name, '*', { user: 'system.user.admin' },
|
|
1287
|
-
// @ts-expect-error todo id should not exist according to types check it
|
|
1288
|
-
async (err, processed, _id) => {
|
|
1289
|
-
if (!err && processed) {
|
|
1290
|
-
files.push({ id: _id, processed: processed });
|
|
1291
|
-
}
|
|
1292
|
-
if (!--count) {
|
|
1293
|
-
const { List } = await import('./setup/setupList.js');
|
|
1294
|
-
const list = new List({
|
|
1295
|
-
states,
|
|
1296
|
-
objects,
|
|
1297
|
-
processExit: callback,
|
|
1298
|
-
});
|
|
1299
|
-
files.sort((a, b) => a.id.localeCompare(b.id));
|
|
1300
|
-
list.showFileHeader();
|
|
1301
|
-
for (const file of files) {
|
|
1302
|
-
for (const processedFile of processed) {
|
|
1303
|
-
list.showFile(file.id, processedFile.path, processedFile);
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
setTimeout(callback, 1_000);
|
|
1307
|
-
}
|
|
1308
|
-
});
|
|
1309
|
-
}
|
|
1310
|
-
if (!count) {
|
|
1311
|
-
console.log('Nothing found');
|
|
1312
|
-
return void callback();
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
else {
|
|
1318
|
-
const parts = pattern.split('/');
|
|
1319
|
-
const id = parts.shift();
|
|
1320
|
-
const path = parts.join('/');
|
|
1321
|
-
objects.rm(id, path, { user: 'system.user.admin' }, async (err, processed) => {
|
|
1322
|
-
if (err) {
|
|
1323
|
-
console.error(err);
|
|
1324
|
-
}
|
|
1325
|
-
else {
|
|
1326
|
-
if (processed) {
|
|
1327
|
-
const { List } = await import('./setup/setupList.js');
|
|
1328
|
-
const list = new List({
|
|
1329
|
-
states,
|
|
1330
|
-
objects,
|
|
1331
|
-
processExit: callback,
|
|
1332
|
-
});
|
|
1333
|
-
list.showFileHeader();
|
|
1334
|
-
for (const file of processed) {
|
|
1335
|
-
// @ts-expect-error todo types adjustment needed
|
|
1336
|
-
list.showFile(id, file.path, file);
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
setTimeout(callback, 1_000);
|
|
1341
|
-
});
|
|
1342
|
-
}
|
|
1343
|
-
});
|
|
1344
|
-
break;
|
|
603
|
+
case 'visdebug': {
|
|
604
|
+
const { processCommandVisDebug } = await import('../lib/setup/setupVisDebug.js');
|
|
605
|
+
return processCommandVisDebug(options);
|
|
1345
606
|
}
|
|
1346
|
-
case '
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
for (const row of arr.rows) {
|
|
1374
|
-
if (row.value.type !== 'adapter') {
|
|
1375
|
-
continue;
|
|
1376
|
-
}
|
|
1377
|
-
count++;
|
|
1378
|
-
objects.chmodFile(row.value.common.name, '*', {
|
|
1379
|
-
user: 'system.user.admin',
|
|
1380
|
-
mode,
|
|
1381
|
-
},
|
|
1382
|
-
// @ts-expect-error todo _id should not exist how to handle
|
|
1383
|
-
async (err, processed, _id) => {
|
|
1384
|
-
if (!err && processed) {
|
|
1385
|
-
files.push({ id: _id, processed: processed });
|
|
1386
|
-
}
|
|
1387
|
-
if (!--count) {
|
|
1388
|
-
const { List } = await import('./setup/setupList.js');
|
|
1389
|
-
const list = new List({
|
|
1390
|
-
states,
|
|
1391
|
-
objects,
|
|
1392
|
-
processExit: callback,
|
|
1393
|
-
});
|
|
1394
|
-
files.sort((a, b) => a.id.localeCompare(b.id));
|
|
1395
|
-
list.showFileHeader();
|
|
1396
|
-
for (const file of files) {
|
|
1397
|
-
for (const processedFile of file.processed) {
|
|
1398
|
-
list.showFile(file.id, processedFile.path, processedFile);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
setTimeout(callback, 1_000);
|
|
1402
|
-
}
|
|
1403
|
-
});
|
|
1404
|
-
}
|
|
1405
|
-
if (!count) {
|
|
1406
|
-
console.log('Nothing found');
|
|
1407
|
-
return void callback();
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1412
|
-
else {
|
|
1413
|
-
const parts = pattern.split('/');
|
|
1414
|
-
const id = parts.shift();
|
|
1415
|
-
const path = parts.join('/');
|
|
1416
|
-
objects.chmodFile(id, path, { user: 'system.user.admin', mode: mode }, async (err, processed) => {
|
|
1417
|
-
if (err) {
|
|
1418
|
-
console.error(err);
|
|
1419
|
-
}
|
|
1420
|
-
else {
|
|
1421
|
-
if (processed) {
|
|
1422
|
-
const { List } = await import('./setup/setupList.js');
|
|
1423
|
-
const list = new List({
|
|
1424
|
-
states,
|
|
1425
|
-
objects,
|
|
1426
|
-
processExit: callback,
|
|
1427
|
-
});
|
|
1428
|
-
list.showFileHeader();
|
|
1429
|
-
for (const file of processed) {
|
|
1430
|
-
// @ts-expect-error todo types adjustment needed
|
|
1431
|
-
list.showFile(id, file.path, file);
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
setTimeout(callback, 1_000);
|
|
1436
|
-
});
|
|
1437
|
-
}
|
|
1438
|
-
});
|
|
607
|
+
case 'file':
|
|
608
|
+
case 'f':
|
|
609
|
+
return processCommandFile(options);
|
|
610
|
+
case 'id':
|
|
611
|
+
case 'uuid':
|
|
612
|
+
return processCommandUuid(options);
|
|
613
|
+
case 'v':
|
|
614
|
+
case 'version':
|
|
615
|
+
return processCommandVersion(options);
|
|
616
|
+
case 'checklog':
|
|
617
|
+
return processCommandCheckLog(options);
|
|
618
|
+
case 'repo': {
|
|
619
|
+
const { processCommandRepo } = await import('../lib/setup/setupRepo.js');
|
|
620
|
+
return processCommandRepo(options);
|
|
621
|
+
}
|
|
622
|
+
case 'multihost':
|
|
623
|
+
case 'mh': {
|
|
624
|
+
const { processCommandMultihost } = await import('../lib/setup/setupMultihost.js');
|
|
625
|
+
return processCommandMultihost(options);
|
|
626
|
+
}
|
|
627
|
+
case 'vendor': {
|
|
628
|
+
const { processCommandVendor } = await import('../lib/setup/setupVendor.js');
|
|
629
|
+
return processCommandVendor(options);
|
|
630
|
+
}
|
|
631
|
+
case 'cert': {
|
|
632
|
+
const certCommand = new CLICert(commandOptions);
|
|
633
|
+
Promise.resolve(certCommand.execute(args)).catch(e => console.error(`Cannot execute cert command: ${e.message}`));
|
|
1439
634
|
break;
|
|
1440
635
|
}
|
|
1441
|
-
case '
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
let pattern = args[2];
|
|
1445
|
-
if (!pattern) {
|
|
1446
|
-
pattern = group;
|
|
1447
|
-
group = undefined;
|
|
1448
|
-
}
|
|
1449
|
-
if (!user) {
|
|
1450
|
-
CLIError.requiredArgumentMissing('user', 'chown user /vis-2.0/main/*');
|
|
1451
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1452
|
-
}
|
|
1453
|
-
else if (user.substring(12) !== 'system.user.') {
|
|
1454
|
-
user = `system.user.${user}`;
|
|
1455
|
-
}
|
|
1456
|
-
if (group && group.substring(13) !== 'system.group.') {
|
|
1457
|
-
group = `system.group.${group}`;
|
|
1458
|
-
}
|
|
1459
|
-
if (!pattern) {
|
|
1460
|
-
CLIError.requiredArgumentMissing('file path', 'chown user /vis-2.0/main/*');
|
|
1461
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1462
|
-
}
|
|
1463
|
-
dbConnect(params, ({ objects, states }) => {
|
|
1464
|
-
// extract id
|
|
1465
|
-
pattern = pattern.replace(/\\/g, '/');
|
|
1466
|
-
if (pattern[0] === '/') {
|
|
1467
|
-
pattern = pattern.substring(1);
|
|
1468
|
-
}
|
|
1469
|
-
if (pattern === '*') {
|
|
1470
|
-
objects.getObjectList({
|
|
1471
|
-
startkey: 'system.adapter.',
|
|
1472
|
-
endkey: 'system.adapter.\u9999',
|
|
1473
|
-
}, (err, arr) => {
|
|
1474
|
-
if (!err && arr?.rows) {
|
|
1475
|
-
const files = [];
|
|
1476
|
-
let count = 0;
|
|
1477
|
-
for (const row of arr.rows) {
|
|
1478
|
-
if (row.value.type !== 'adapter') {
|
|
1479
|
-
continue;
|
|
1480
|
-
}
|
|
1481
|
-
count++;
|
|
1482
|
-
objects.chownFile(row.value.common.name, '*', {
|
|
1483
|
-
user: 'system.user.admin',
|
|
1484
|
-
owner: user,
|
|
1485
|
-
ownerGroup: group,
|
|
1486
|
-
},
|
|
1487
|
-
// @ts-expect-error todo _id should not exist how to handle
|
|
1488
|
-
async (err, processed, _id) => {
|
|
1489
|
-
if (!err && processed) {
|
|
1490
|
-
files.push({ id: _id, processed: processed });
|
|
1491
|
-
}
|
|
1492
|
-
if (!--count) {
|
|
1493
|
-
const { List } = await import('./setup/setupList.js');
|
|
1494
|
-
const list = new List({
|
|
1495
|
-
states,
|
|
1496
|
-
objects,
|
|
1497
|
-
processExit: callback,
|
|
1498
|
-
});
|
|
1499
|
-
files.sort((a, b) => a.id.localeCompare(b.id));
|
|
1500
|
-
list.showFileHeader();
|
|
1501
|
-
for (let k = 0; k < files.length; k++) {
|
|
1502
|
-
for (let t = 0; t < files[k].processed.length; t++) {
|
|
1503
|
-
list.showFile(files[k].id, files[k].processed[t].path, files[k].processed[t]);
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
setTimeout(callback, 1_000);
|
|
1507
|
-
}
|
|
1508
|
-
});
|
|
1509
|
-
}
|
|
1510
|
-
if (!count) {
|
|
1511
|
-
console.log('Nothing found');
|
|
1512
|
-
return void callback();
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
});
|
|
1516
|
-
}
|
|
1517
|
-
else {
|
|
1518
|
-
const parts = pattern.split('/');
|
|
1519
|
-
const id = parts.shift();
|
|
1520
|
-
const path = parts.join('/');
|
|
1521
|
-
objects.chownFile(id, path, {
|
|
1522
|
-
user: 'system.user.admin',
|
|
1523
|
-
owner: user,
|
|
1524
|
-
ownerGroup: group,
|
|
1525
|
-
}, async (err, processed) => {
|
|
1526
|
-
if (err) {
|
|
1527
|
-
console.error(err);
|
|
1528
|
-
}
|
|
1529
|
-
else {
|
|
1530
|
-
// call here list
|
|
1531
|
-
if (processed) {
|
|
1532
|
-
const { List } = await import('./setup/setupList.js');
|
|
1533
|
-
const list = new List({
|
|
1534
|
-
states,
|
|
1535
|
-
objects,
|
|
1536
|
-
processExit: callback,
|
|
1537
|
-
});
|
|
1538
|
-
list.showFileHeader();
|
|
1539
|
-
for (const file of processed) {
|
|
1540
|
-
// @ts-expect-error todo types adjustment needed
|
|
1541
|
-
list.showFile(id, file.path, file);
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
setTimeout(callback, 1_000);
|
|
1546
|
-
});
|
|
1547
|
-
}
|
|
1548
|
-
});
|
|
636
|
+
case 'compact': {
|
|
637
|
+
const compactCommand = new CLICompact(commandOptions);
|
|
638
|
+
compactCommand.execute(args);
|
|
1549
639
|
break;
|
|
1550
640
|
}
|
|
1551
|
-
case '
|
|
1552
|
-
const
|
|
1553
|
-
|
|
1554
|
-
if (user && user.startsWith('system.user.')) {
|
|
1555
|
-
user = user.substring('system.user.'.length);
|
|
1556
|
-
}
|
|
1557
|
-
dbConnect(params, async ({ objects }) => {
|
|
1558
|
-
const { Users } = await import('./setup/setupUsers.js');
|
|
1559
|
-
const users = new Users({
|
|
1560
|
-
objects,
|
|
1561
|
-
processExit: callback,
|
|
1562
|
-
});
|
|
1563
|
-
const password = params.password;
|
|
1564
|
-
const group = params.ingroup || 'system.group.administrator';
|
|
1565
|
-
if (command === 'add') {
|
|
1566
|
-
users.addUserPrompt(user, group, password, (err) => {
|
|
1567
|
-
if (err) {
|
|
1568
|
-
console.error(err);
|
|
1569
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1570
|
-
}
|
|
1571
|
-
console.log(`User "${user}" created (Group: ${group.replace('system.group.', '')})`);
|
|
1572
|
-
return void callback();
|
|
1573
|
-
});
|
|
1574
|
-
}
|
|
1575
|
-
else if (command === 'del' || command === 'delete') {
|
|
1576
|
-
users.delUser(user, (err) => {
|
|
1577
|
-
if (err) {
|
|
1578
|
-
console.error(err);
|
|
1579
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1580
|
-
}
|
|
1581
|
-
console.log(`User "${user}" deleted`);
|
|
1582
|
-
return void callback();
|
|
1583
|
-
});
|
|
1584
|
-
}
|
|
1585
|
-
else if (command === 'check') {
|
|
1586
|
-
users.checkUserPassword(user, password, err => {
|
|
1587
|
-
if (err) {
|
|
1588
|
-
console.error(err.message);
|
|
1589
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1590
|
-
}
|
|
1591
|
-
console.log(`Password for user "${user}" matches.`);
|
|
1592
|
-
return void callback();
|
|
1593
|
-
});
|
|
1594
|
-
}
|
|
1595
|
-
else if (command === 'set' || command === 'passwd') {
|
|
1596
|
-
users.setUserPassword(user, password, err => {
|
|
1597
|
-
if (err) {
|
|
1598
|
-
console.error(err.message);
|
|
1599
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1600
|
-
}
|
|
1601
|
-
console.log(`Password for "${user}" was successfully set.`);
|
|
1602
|
-
return void callback();
|
|
1603
|
-
});
|
|
1604
|
-
}
|
|
1605
|
-
else if (command === 'enable' || command === 'e') {
|
|
1606
|
-
users.enableUser(user, true, err => {
|
|
1607
|
-
if (err) {
|
|
1608
|
-
console.error(err.message);
|
|
1609
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1610
|
-
}
|
|
1611
|
-
console.log(`User "${user}" was successfully enabled.`);
|
|
1612
|
-
return void callback();
|
|
1613
|
-
});
|
|
1614
|
-
}
|
|
1615
|
-
else if (command === 'disable' || command === 'd') {
|
|
1616
|
-
users.enableUser(user, false, err => {
|
|
1617
|
-
if (err) {
|
|
1618
|
-
console.error(err.message);
|
|
1619
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1620
|
-
}
|
|
1621
|
-
console.log(`User "${user}" was successfully disabled.`);
|
|
1622
|
-
return void callback();
|
|
1623
|
-
});
|
|
1624
|
-
}
|
|
1625
|
-
else if (command === 'get') {
|
|
1626
|
-
users.getUser(user, (err, isEnabled) => {
|
|
1627
|
-
if (err) {
|
|
1628
|
-
console.error(err.message);
|
|
1629
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1630
|
-
}
|
|
1631
|
-
console.log(`User "${user}" is ${isEnabled ? 'enabled' : 'disabled'}`);
|
|
1632
|
-
return void callback();
|
|
1633
|
-
});
|
|
1634
|
-
}
|
|
1635
|
-
else {
|
|
1636
|
-
console.warn(`Unknown command "${command}". Available commands are: add, del, passwd, enable, disable, check, get`);
|
|
1637
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1638
|
-
}
|
|
1639
|
-
});
|
|
641
|
+
case 'plugin': {
|
|
642
|
+
const pluginCommand = new CLIPlugin(commandOptions);
|
|
643
|
+
pluginCommand.execute(args);
|
|
1640
644
|
break;
|
|
1641
645
|
}
|
|
1642
|
-
case '
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
if (
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
if (user && user.startsWith('system.user.')) {
|
|
1651
|
-
user = user.substring('system.user.'.length);
|
|
1652
|
-
}
|
|
1653
|
-
if (!command) {
|
|
1654
|
-
console.warn(`Unknown command "${command}". Available commands are: add, del, passwd, enable, disable, list, get`);
|
|
1655
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1656
|
-
}
|
|
1657
|
-
if (!group) {
|
|
1658
|
-
console.warn(`Please define group name: group ${command} groupName`);
|
|
1659
|
-
return callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1660
|
-
}
|
|
1661
|
-
dbConnect(params, async ({ objects }) => {
|
|
1662
|
-
const { Users } = await import('./setup/setupUsers.js');
|
|
1663
|
-
const users = new Users({
|
|
1664
|
-
objects,
|
|
1665
|
-
processExit: callback,
|
|
1666
|
-
});
|
|
1667
|
-
if (command === 'useradd' || command === 'adduser') {
|
|
1668
|
-
if (!user) {
|
|
1669
|
-
console.warn('Please define user name: "group useradd groupName userName"');
|
|
1670
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1671
|
-
}
|
|
1672
|
-
users.addUserToGroup(user, group, (err) => {
|
|
1673
|
-
if (err) {
|
|
1674
|
-
console.error(err);
|
|
1675
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1676
|
-
}
|
|
1677
|
-
console.log(`User "${user}" was added to group "${group}"`);
|
|
1678
|
-
return void callback();
|
|
1679
|
-
});
|
|
1680
|
-
}
|
|
1681
|
-
else if (command === 'userdel' || command === 'deluser') {
|
|
1682
|
-
if (!user) {
|
|
1683
|
-
console.warn('Please define user name: "group userdel groupName userName"');
|
|
1684
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1685
|
-
}
|
|
1686
|
-
users.removeUserFromGroup(user, group, (err) => {
|
|
1687
|
-
if (err) {
|
|
1688
|
-
console.error(err);
|
|
1689
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1690
|
-
}
|
|
1691
|
-
console.log(`User "${user}" was deleted from group "${group}"`);
|
|
1692
|
-
return void callback();
|
|
1693
|
-
});
|
|
1694
|
-
}
|
|
1695
|
-
else if (command === 'add') {
|
|
646
|
+
case 'license': {
|
|
647
|
+
const { processCommandLicense } = await import('../lib/setup/setupLicense.js');
|
|
648
|
+
return processCommandLicense(options);
|
|
649
|
+
}
|
|
650
|
+
default: {
|
|
651
|
+
if (params.v || params.version) {
|
|
652
|
+
let pckg;
|
|
653
|
+
if (command) {
|
|
1696
654
|
try {
|
|
1697
|
-
|
|
1698
|
-
console.log(`Group "${group}" was created`);
|
|
1699
|
-
return void callback();
|
|
655
|
+
pckg = require(`${tools.appName.toLowerCase()}.${command}/package.json`);
|
|
1700
656
|
}
|
|
1701
657
|
catch {
|
|
1702
|
-
|
|
658
|
+
pckg = { version: `"${command}" not found` };
|
|
1703
659
|
}
|
|
1704
660
|
}
|
|
1705
|
-
else
|
|
1706
|
-
|
|
1707
|
-
if (err) {
|
|
1708
|
-
console.error(err);
|
|
1709
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1710
|
-
}
|
|
1711
|
-
console.log(`Group "${group}" was deleted`);
|
|
1712
|
-
return void callback();
|
|
1713
|
-
});
|
|
661
|
+
else {
|
|
662
|
+
pckg = require(`@iobroker/js-controller-common/package.json`);
|
|
1714
663
|
}
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
664
|
+
console.log(pckg.version);
|
|
665
|
+
}
|
|
666
|
+
else {
|
|
667
|
+
showHelp();
|
|
668
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
669
|
+
}
|
|
670
|
+
return void callback();
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Process the `info` CLI command: print host information
|
|
676
|
+
*
|
|
677
|
+
* @param options command options provided by the dispatcher
|
|
678
|
+
*/
|
|
679
|
+
function processCommandInfo(options) {
|
|
680
|
+
const { params, callback } = options;
|
|
681
|
+
dbConnect(params, async ({ objects }) => {
|
|
682
|
+
try {
|
|
683
|
+
const data = await tools.getHostInfo(objects);
|
|
684
|
+
for (const attr in data) {
|
|
685
|
+
let info;
|
|
686
|
+
if (attr === 'Uptime' || attr === 'System uptime') {
|
|
687
|
+
info = formatters.formatSeconds(data[attr]);
|
|
1729
688
|
}
|
|
1730
|
-
else if (
|
|
1731
|
-
|
|
1732
|
-
if (err) {
|
|
1733
|
-
console.error(err);
|
|
1734
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1735
|
-
}
|
|
1736
|
-
console.log(`Group "${group}" was successfully enabled.`);
|
|
1737
|
-
return void callback();
|
|
1738
|
-
});
|
|
689
|
+
else if (attr === 'RAM') {
|
|
690
|
+
info = formatters.formatRam(data[attr]);
|
|
1739
691
|
}
|
|
1740
|
-
else if (
|
|
1741
|
-
|
|
1742
|
-
if (err) {
|
|
1743
|
-
console.error(err);
|
|
1744
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1745
|
-
}
|
|
1746
|
-
console.log(`Group "${group}" was successfully disabled.`);
|
|
1747
|
-
return void callback();
|
|
1748
|
-
});
|
|
692
|
+
else if (attr === 'Speed') {
|
|
693
|
+
info = formatters.formatSpeed(data[attr]);
|
|
1749
694
|
}
|
|
1750
|
-
else if (
|
|
1751
|
-
|
|
1752
|
-
if (err) {
|
|
1753
|
-
console.error(err);
|
|
1754
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1755
|
-
}
|
|
1756
|
-
console.log(`Group "${group}" is ${isEnabled ? 'enabled' : 'disabled'}`);
|
|
1757
|
-
return void callback();
|
|
1758
|
-
});
|
|
695
|
+
else if (attr === 'Disk size' || attr === 'Disk free') {
|
|
696
|
+
info = formatters.formatBytes(data[attr]);
|
|
1759
697
|
}
|
|
1760
698
|
else {
|
|
1761
|
-
|
|
1762
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
699
|
+
info = data[attr];
|
|
1763
700
|
}
|
|
1764
|
-
|
|
1765
|
-
|
|
701
|
+
console.log(`${attr}${attr.length < 16 ? new Array(16 - attr.length).join(' ') : ''}: ${info || ''}`);
|
|
702
|
+
}
|
|
1766
703
|
}
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
const password = params.password;
|
|
1771
|
-
dbConnect(params, async ({ objects }) => {
|
|
1772
|
-
const { Users } = await import('./setup/setupUsers.js');
|
|
1773
|
-
const users = new Users({
|
|
1774
|
-
objects,
|
|
1775
|
-
processExit: callback,
|
|
1776
|
-
});
|
|
1777
|
-
users.addUserPrompt(user, group, password, (err) => {
|
|
1778
|
-
if (err) {
|
|
1779
|
-
console.error(err);
|
|
1780
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
1781
|
-
}
|
|
1782
|
-
console.log(`User "${user}" created (Group: ${group.replace('system.group.', '')})`);
|
|
1783
|
-
return void callback();
|
|
1784
|
-
});
|
|
1785
|
-
});
|
|
1786
|
-
break;
|
|
704
|
+
catch (err) {
|
|
705
|
+
console.error(`Cannot read host info: ${typeof err === 'object' ? JSON.stringify(err) : err}`);
|
|
706
|
+
return callback(EXIT_CODES.CANNOT_GET_HOST_INFO);
|
|
1787
707
|
}
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
console.log(`Password for "${user}" was successfully set.`);
|
|
1803
|
-
return void callback();
|
|
1804
|
-
});
|
|
1805
|
-
});
|
|
1806
|
-
break;
|
|
708
|
+
return void callback();
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Process the `rebuild` CLI command: rebuild all native modules or a single native module
|
|
713
|
+
*
|
|
714
|
+
* @param options command options provided by the dispatcher
|
|
715
|
+
*/
|
|
716
|
+
async function processCommandRebuild(options) {
|
|
717
|
+
const { callback, commandOptions } = options;
|
|
718
|
+
const rebuildOptions = { debug: process.argv.includes('--debug') };
|
|
719
|
+
if (commandOptions.path) {
|
|
720
|
+
if (path.isAbsolute(commandOptions.path)) {
|
|
721
|
+
rebuildOptions.cwd = commandOptions.path;
|
|
1807
722
|
}
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
723
|
+
else {
|
|
724
|
+
console.log('Path argument needs to be an absolute path!');
|
|
725
|
+
return void exitApplicationSave(EXIT_CODES.INVALID_ARGUMENTS);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
if (commandOptions.module) {
|
|
729
|
+
rebuildOptions.module = commandOptions.module;
|
|
730
|
+
console.log(`Rebuilding native module "${commandOptions.module}"${rebuildOptions.cwd ? ` in ${rebuildOptions.cwd}` : ''} ...`);
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
console.log(`Rebuilding native modules${rebuildOptions.cwd ? ` in ${rebuildOptions.cwd}` : ''} ...`);
|
|
734
|
+
}
|
|
735
|
+
const result = await tools.rebuildNodeModules(rebuildOptions);
|
|
736
|
+
if (result.success) {
|
|
737
|
+
console.log();
|
|
738
|
+
console.log(`Rebuilding native modules done`);
|
|
739
|
+
return void callback();
|
|
740
|
+
}
|
|
741
|
+
console.error('Rebuilding native modules failed');
|
|
742
|
+
return void exitApplicationSave(result.exitCode);
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Process the `unsetup` CLI command: delete the installation UUID after confirmation
|
|
746
|
+
*
|
|
747
|
+
* @param options command options provided by the dispatcher
|
|
748
|
+
*/
|
|
749
|
+
async function processCommandUnsetup(options) {
|
|
750
|
+
const { params, callback } = options;
|
|
751
|
+
const rl = (await import('node:readline')).createInterface({
|
|
752
|
+
input: process.stdin,
|
|
753
|
+
output: process.stdout,
|
|
754
|
+
});
|
|
755
|
+
if (params.yes || params.y || params.Y) {
|
|
756
|
+
unsetup(params, callback).catch(e => console.error(`Cannot unsetup: ${e.message}`));
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
rl.question('UUID will be deleted. Are you sure? [y/N]: ', answer => {
|
|
760
|
+
rl.close();
|
|
761
|
+
answer = answer.toLowerCase();
|
|
762
|
+
if (answer === 'y' || answer === 'yes' || answer === 'ja' || answer === 'j') {
|
|
763
|
+
unsetup(params, callback).catch(e => console.error(`Cannot unsetup: ${e.message}`));
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
console.log('Nothing deleted');
|
|
767
|
+
return void callback();
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Process the `clean` CLI command: clear all objects and states
|
|
773
|
+
*
|
|
774
|
+
* @param options command options provided by the dispatcher
|
|
775
|
+
*/
|
|
776
|
+
function processCommandClean(options) {
|
|
777
|
+
const { args, params, callback } = options;
|
|
778
|
+
const yes = args[0];
|
|
779
|
+
if (yes !== 'yes') {
|
|
780
|
+
console.log(`Command "clean" clears all Objects and States. To execute it write "${tools.appName} clean yes"`);
|
|
781
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
782
|
+
}
|
|
783
|
+
dbConnect(params, async ({ isOffline }) => {
|
|
784
|
+
if (!isOffline) {
|
|
785
|
+
console.error(`Stop ${tools.appName} first!`);
|
|
786
|
+
return void callback(EXIT_CODES.CONTROLLER_RUNNING);
|
|
787
|
+
}
|
|
788
|
+
try {
|
|
789
|
+
const count = await cleanDatabase(true);
|
|
790
|
+
console.log(`Deleted ${count} states`);
|
|
791
|
+
}
|
|
792
|
+
catch {
|
|
793
|
+
// ignore
|
|
1829
794
|
}
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
795
|
+
restartController().catch(e => console.error(`Cannot restart controller: ${e.message}`));
|
|
796
|
+
console.log(`Restarting ${tools.appName}...`);
|
|
797
|
+
callback();
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Process the `touch` CLI command: touch files matching the given pattern
|
|
802
|
+
*
|
|
803
|
+
* @param options command options provided by the dispatcher
|
|
804
|
+
*/
|
|
805
|
+
function processCommandTouch(options) {
|
|
806
|
+
const { args, params, callback } = options;
|
|
807
|
+
let pattern = args[0];
|
|
808
|
+
if (!pattern) {
|
|
809
|
+
console.log('No file path found. Example: "touch /vis-2.0/main/*"');
|
|
810
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
811
|
+
}
|
|
812
|
+
dbConnect(params, ({ objects }) => {
|
|
813
|
+
// extract id
|
|
814
|
+
pattern = pattern.replace(/\\/g, '/');
|
|
815
|
+
if (pattern[0] === '/') {
|
|
816
|
+
pattern = pattern.substring(1);
|
|
817
|
+
}
|
|
818
|
+
if (pattern === '*') {
|
|
819
|
+
objects.getObjectList({
|
|
820
|
+
startkey: 'system.adapter.',
|
|
821
|
+
endkey: 'system.adapter.\u9999',
|
|
822
|
+
}, async (err, arr) => {
|
|
823
|
+
if (!err && arr?.rows) {
|
|
824
|
+
const files = [];
|
|
825
|
+
for (const row of arr.rows) {
|
|
826
|
+
const rowTyped = row.value;
|
|
827
|
+
if (rowTyped.type !== 'adapter') {
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
await new Promise(resolve => objects.touch(rowTyped.common.name, '*', { user: 'system.user.admin' }, err => {
|
|
831
|
+
if (!err) {
|
|
832
|
+
files.push(rowTyped.common.name);
|
|
1853
833
|
}
|
|
1854
834
|
else {
|
|
1855
|
-
|
|
1856
|
-
json.optionalDependencies[`${tools.appName}.${s}`] = '*';
|
|
1857
|
-
}
|
|
835
|
+
console.warn(`Cannot touch file ${rowTyped.common.name}`);
|
|
1858
836
|
}
|
|
1859
|
-
|
|
837
|
+
resolve();
|
|
838
|
+
}));
|
|
1860
839
|
}
|
|
840
|
+
files.sort((a, b) => a.localeCompare(b));
|
|
841
|
+
for (const file of files) {
|
|
842
|
+
console.log(`Touched ${file}`);
|
|
843
|
+
}
|
|
844
|
+
setTimeout(callback, 1_000);
|
|
1861
845
|
}
|
|
1862
|
-
fs.writeFileSync(path.join(tools.getRootDir(), 'package.json'), JSON.stringify(json, null, 2));
|
|
1863
|
-
return void callback();
|
|
1864
846
|
});
|
|
1865
|
-
break;
|
|
1866
847
|
}
|
|
1867
|
-
|
|
1868
|
-
const
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
obj.native[parts[0]][parts[1]] = val;
|
|
1913
|
-
console.log(`New ${attr} for "${instance}" is: ${val}`);
|
|
1914
|
-
}
|
|
848
|
+
else {
|
|
849
|
+
const parts = pattern.split('/');
|
|
850
|
+
const id = parts.shift();
|
|
851
|
+
const path = parts.join('/');
|
|
852
|
+
objects.touch(id, path, { user: 'system.user.admin' }, err => {
|
|
853
|
+
if (err) {
|
|
854
|
+
console.error(err);
|
|
855
|
+
}
|
|
856
|
+
else {
|
|
857
|
+
console.log(`Touched ${id}/${path}`);
|
|
858
|
+
}
|
|
859
|
+
setTimeout(callback, 1_000);
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Process the `rm` CLI command: remove files matching the given pattern
|
|
866
|
+
*
|
|
867
|
+
* @param options command options provided by the dispatcher
|
|
868
|
+
*/
|
|
869
|
+
function processCommandRm(options) {
|
|
870
|
+
const { args, params, callback } = options;
|
|
871
|
+
let pattern = args[0];
|
|
872
|
+
if (!pattern) {
|
|
873
|
+
console.log('No file path found. Example: "touch /vis-2.0/main/*"');
|
|
874
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
875
|
+
}
|
|
876
|
+
dbConnect(params, ({ objects }) => {
|
|
877
|
+
// extract id
|
|
878
|
+
pattern = pattern.replace(/\\/g, '/');
|
|
879
|
+
if (pattern[0] === '/') {
|
|
880
|
+
pattern = pattern.substring(1);
|
|
881
|
+
}
|
|
882
|
+
if (pattern === '*') {
|
|
883
|
+
objects.getObjectList({
|
|
884
|
+
startkey: 'system.adapter.',
|
|
885
|
+
endkey: 'system.adapter.\u9999',
|
|
886
|
+
}, async (err, arr) => {
|
|
887
|
+
if (!err && arr?.rows) {
|
|
888
|
+
const files = [];
|
|
889
|
+
for (const row of arr.rows) {
|
|
890
|
+
const rowTyped = row.value;
|
|
891
|
+
if (rowTyped.type !== 'adapter') {
|
|
892
|
+
continue;
|
|
1915
893
|
}
|
|
1916
|
-
|
|
1917
|
-
if (
|
|
1918
|
-
|
|
1919
|
-
}
|
|
1920
|
-
else {
|
|
1921
|
-
changed = true;
|
|
1922
|
-
obj.native[attr] = val;
|
|
1923
|
-
console.log(`New ${attr} for "${instance}" is: ${val}`);
|
|
894
|
+
await new Promise(resolve => objects.rm(rowTyped.common.name, '*', { user: 'system.user.admin' }, (err, processed) => {
|
|
895
|
+
if (!err && processed) {
|
|
896
|
+
files.push({ id: rowTyped.common.name, processed });
|
|
1924
897
|
}
|
|
898
|
+
resolve();
|
|
899
|
+
}));
|
|
900
|
+
}
|
|
901
|
+
files.sort((a, b) => a.id.localeCompare(b.id));
|
|
902
|
+
for (const file of files) {
|
|
903
|
+
for (const processedFile of file.processed) {
|
|
904
|
+
console.log(`Removed ${processedFile.path}/${processedFile.file}`);
|
|
1925
905
|
}
|
|
1926
|
-
a++;
|
|
1927
906
|
}
|
|
907
|
+
setTimeout(callback, 1_000);
|
|
1928
908
|
}
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
909
|
+
});
|
|
910
|
+
}
|
|
911
|
+
else {
|
|
912
|
+
const parts = pattern.split('/');
|
|
913
|
+
const id = parts.shift();
|
|
914
|
+
const path = parts.join('/');
|
|
915
|
+
objects.rm(id, path, { user: 'system.user.admin' }, (err, processed) => {
|
|
916
|
+
if (err) {
|
|
917
|
+
console.error(err);
|
|
1936
918
|
}
|
|
1937
919
|
else {
|
|
1938
|
-
|
|
1939
|
-
|
|
920
|
+
if (processed) {
|
|
921
|
+
for (const file of processed) {
|
|
922
|
+
console.log(`Removed ${file.path}/${file.file}`);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
1940
925
|
}
|
|
1941
|
-
|
|
1942
|
-
else {
|
|
1943
|
-
CLIError.invalidInstance(instance);
|
|
1944
|
-
return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
|
|
1945
|
-
}
|
|
1946
|
-
break;
|
|
1947
|
-
}
|
|
1948
|
-
case 'host': {
|
|
1949
|
-
const hostCommand = new CLIHost(commandOptions);
|
|
1950
|
-
hostCommand.execute(args);
|
|
1951
|
-
break;
|
|
1952
|
-
}
|
|
1953
|
-
case 'visdebug': {
|
|
1954
|
-
let widgetset = args[0];
|
|
1955
|
-
if (widgetset && widgetset.startsWith('vis-')) {
|
|
1956
|
-
widgetset = widgetset.substring(4);
|
|
1957
|
-
}
|
|
1958
|
-
const { VisDebug } = await import('./setup/setupVisDebug.js');
|
|
1959
|
-
dbConnect(params, ({ objects }) => {
|
|
1960
|
-
const visDebug = new VisDebug({
|
|
1961
|
-
objects,
|
|
1962
|
-
processExit: callback,
|
|
1963
|
-
});
|
|
1964
|
-
visDebug.enableDebug(widgetset);
|
|
926
|
+
setTimeout(callback, 1_000);
|
|
1965
927
|
});
|
|
1966
|
-
break;
|
|
1967
928
|
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Process the `chmod` CLI command: change file rights for files matching the given pattern
|
|
933
|
+
*
|
|
934
|
+
* @param options command options provided by the dispatcher
|
|
935
|
+
*/
|
|
936
|
+
function processCommandChmod(options) {
|
|
937
|
+
const { args, params, callback } = options;
|
|
938
|
+
let mode = args[0];
|
|
939
|
+
let pattern = args[1];
|
|
940
|
+
if (!mode) {
|
|
941
|
+
CLIError.requiredArgumentMissing('mode', 'chmod 777 /vis-2.0/main/*');
|
|
942
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
943
|
+
}
|
|
944
|
+
// yargs has converted it to number
|
|
945
|
+
mode = parseInt(mode.toString(), 16);
|
|
946
|
+
if (!pattern) {
|
|
947
|
+
CLIError.requiredArgumentMissing('file path', 'chmod 777 /vis-2.0/main/*');
|
|
948
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
949
|
+
}
|
|
950
|
+
dbConnect(params, ({ objects, states }) => {
|
|
951
|
+
// extract id
|
|
952
|
+
pattern = pattern.replace(/\\/g, '/');
|
|
953
|
+
if (pattern[0] === '/') {
|
|
954
|
+
pattern = pattern.substring(1);
|
|
955
|
+
}
|
|
956
|
+
if (pattern === '*') {
|
|
957
|
+
objects.getObjectList({
|
|
958
|
+
startkey: 'system.adapter.',
|
|
959
|
+
endkey: 'system.adapter.\u9999',
|
|
960
|
+
}, async (err, arr) => {
|
|
961
|
+
if (!err && arr?.rows) {
|
|
962
|
+
const files = [];
|
|
963
|
+
for (const row of arr.rows) {
|
|
964
|
+
const rowTyped = row.value;
|
|
965
|
+
if (rowTyped.type !== 'adapter') {
|
|
966
|
+
continue;
|
|
2002
967
|
}
|
|
968
|
+
await new Promise(resolve => objects.chmodFile(rowTyped.common.name, '*', {
|
|
969
|
+
user: 'system.user.admin',
|
|
970
|
+
mode,
|
|
971
|
+
}, (err, processed) => {
|
|
972
|
+
if (!err && processed) {
|
|
973
|
+
files.push({ id: rowTyped.common.name, processed });
|
|
974
|
+
}
|
|
975
|
+
resolve();
|
|
976
|
+
}));
|
|
2003
977
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
}
|
|
2009
|
-
if (!adapt) {
|
|
2010
|
-
console.log(`Invalid parameters: adapter cannot be found!`);
|
|
2011
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2012
|
-
}
|
|
2013
|
-
if (!parts.length) {
|
|
2014
|
-
console.log('Invalid parameters: file cannot be found: file not provided');
|
|
2015
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2016
|
-
}
|
|
2017
|
-
objects.readFile(adapt, parts.join('/'), null, (err, data) => {
|
|
2018
|
-
err && console.error(err);
|
|
2019
|
-
if (data) {
|
|
2020
|
-
const destFilename = path.join('/');
|
|
2021
|
-
fs.writeFileSync(destFilename, data);
|
|
2022
|
-
console.log(`File "${toRead}" stored as "${destFilename}"`);
|
|
2023
|
-
}
|
|
2024
|
-
return void callback(EXIT_CODES.NO_ERROR);
|
|
978
|
+
const list = new List({
|
|
979
|
+
states,
|
|
980
|
+
objects,
|
|
981
|
+
processExit: callback,
|
|
2025
982
|
});
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
const
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
let adapt = path.shift();
|
|
2032
|
-
if (!adapt) {
|
|
2033
|
-
adapt = path.shift();
|
|
2034
|
-
}
|
|
2035
|
-
if (!path.length) {
|
|
2036
|
-
path.push('');
|
|
2037
|
-
}
|
|
2038
|
-
const fileSrc = parts[parts.length - 1];
|
|
2039
|
-
let fileDest = path[path.length - 1];
|
|
2040
|
-
if (!fileDest || !fileDest.match(/\.[a-zA-Z0-9]+$/)) {
|
|
2041
|
-
// last portion of destination has no extension, consider being a directory
|
|
2042
|
-
fileDest = '';
|
|
2043
|
-
}
|
|
2044
|
-
if (!fileSrc || !fs.existsSync(toRead)) {
|
|
2045
|
-
console.log(`Please provide a valid file name as source file: "file write /opt/SOURCE/script.js /vis-2/DESTINATION/script.js"`);
|
|
2046
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2047
|
-
}
|
|
2048
|
-
const srcStat = fs.statSync(toRead);
|
|
2049
|
-
if (!srcStat.isFile()) {
|
|
2050
|
-
console.log(`Please provide a valid file name as source file: "file write /opt/SOURCE/script.js /vis-2/DESTINATION/script.js"`);
|
|
2051
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2052
|
-
}
|
|
2053
|
-
if (!fileDest) {
|
|
2054
|
-
// destination filename is not given, use same name as source file
|
|
2055
|
-
fileDest = fileSrc;
|
|
2056
|
-
}
|
|
2057
|
-
if (fileDest !== path[path.length - 1]) {
|
|
2058
|
-
// if last part of path is different then filename, add filename
|
|
2059
|
-
if (path[path.length - 1] !== '') {
|
|
2060
|
-
path.push(fileDest);
|
|
2061
|
-
}
|
|
2062
|
-
else {
|
|
2063
|
-
// trailing slash
|
|
2064
|
-
path[path.length - 1] = fileDest;
|
|
983
|
+
files.sort((a, b) => a.id.localeCompare(b.id));
|
|
984
|
+
list.showFileHeader();
|
|
985
|
+
for (const file of files) {
|
|
986
|
+
for (const processedFile of file.processed) {
|
|
987
|
+
list.showFile(file.id, processedFile.path, processedFile);
|
|
2065
988
|
}
|
|
2066
989
|
}
|
|
2067
|
-
|
|
2068
|
-
const data = fs.readFileSync(toRead);
|
|
2069
|
-
if (!adapt) {
|
|
2070
|
-
console.log('Invalid parameters: destination adapter cannot be found!');
|
|
2071
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2072
|
-
}
|
|
2073
|
-
objects.writeFile(adapt, destFilename, data, _err => {
|
|
2074
|
-
console.log(`File "${toRead}" stored as "${destFilename}"`);
|
|
2075
|
-
return void callback(EXIT_CODES.NO_ERROR);
|
|
2076
|
-
});
|
|
990
|
+
setTimeout(callback, 1_000);
|
|
2077
991
|
}
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
console.log('Invalid parameters: adapter cannot be found!');
|
|
2088
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2089
|
-
}
|
|
2090
|
-
if (!parts.length) {
|
|
2091
|
-
console.log('Invalid parameters: file cannot be found: file not provided');
|
|
2092
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2093
|
-
}
|
|
2094
|
-
objects.unlink(adapt, parts.join('/'), null, err => {
|
|
2095
|
-
err && console.error(err);
|
|
2096
|
-
!err && console.log(`File "${toDelete}" was deleted`);
|
|
2097
|
-
return void callback(EXIT_CODES.NO_ERROR);
|
|
2098
|
-
});
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
else {
|
|
995
|
+
const parts = pattern.split('/');
|
|
996
|
+
const id = parts.shift();
|
|
997
|
+
const path = parts.join('/');
|
|
998
|
+
objects.chmodFile(id, path, { user: 'system.user.admin', mode: mode }, (err, processed) => {
|
|
999
|
+
if (err) {
|
|
1000
|
+
console.error(err);
|
|
2099
1001
|
}
|
|
2100
|
-
else
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
1002
|
+
else {
|
|
1003
|
+
if (processed) {
|
|
1004
|
+
const list = new List({
|
|
1005
|
+
states,
|
|
1006
|
+
objects,
|
|
1007
|
+
processExit: callback,
|
|
1008
|
+
});
|
|
1009
|
+
list.showFileHeader();
|
|
1010
|
+
for (const file of processed) {
|
|
1011
|
+
list.showFile(id, file.path, file);
|
|
1012
|
+
}
|
|
2111
1013
|
}
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
1014
|
+
}
|
|
1015
|
+
setTimeout(callback, 1_000);
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Process the `chown` CLI command: change file ownership for files matching the given pattern
|
|
1022
|
+
*
|
|
1023
|
+
* @param options command options provided by the dispatcher
|
|
1024
|
+
*/
|
|
1025
|
+
function processCommandChown(options) {
|
|
1026
|
+
const { args, params, callback } = options;
|
|
1027
|
+
let user = args[0];
|
|
1028
|
+
let group = args[1];
|
|
1029
|
+
let pattern = args[2];
|
|
1030
|
+
if (!pattern) {
|
|
1031
|
+
pattern = group;
|
|
1032
|
+
group = undefined;
|
|
1033
|
+
}
|
|
1034
|
+
if (!user) {
|
|
1035
|
+
CLIError.requiredArgumentMissing('user', 'chown user /vis-2.0/main/*');
|
|
1036
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1037
|
+
}
|
|
1038
|
+
if (!user.startsWith('system.user.')) {
|
|
1039
|
+
user = `system.user.${user}`;
|
|
1040
|
+
}
|
|
1041
|
+
if (group && !group.startsWith('system.group.')) {
|
|
1042
|
+
group = `system.group.${group}`;
|
|
1043
|
+
}
|
|
1044
|
+
if (!pattern) {
|
|
1045
|
+
CLIError.requiredArgumentMissing('file path', 'chown user /vis-2.0/main/*');
|
|
1046
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1047
|
+
}
|
|
1048
|
+
dbConnect(params, ({ objects, states }) => {
|
|
1049
|
+
// extract id
|
|
1050
|
+
pattern = pattern.replace(/\\/g, '/');
|
|
1051
|
+
if (pattern[0] === '/') {
|
|
1052
|
+
pattern = pattern.substring(1);
|
|
1053
|
+
}
|
|
1054
|
+
if (pattern === '*') {
|
|
1055
|
+
objects.getObjectList({
|
|
1056
|
+
startkey: 'system.adapter.',
|
|
1057
|
+
endkey: 'system.adapter.\u9999',
|
|
1058
|
+
}, async (err, arr) => {
|
|
1059
|
+
if (!err && arr?.rows) {
|
|
1060
|
+
const files = [];
|
|
1061
|
+
for (const row of arr.rows) {
|
|
1062
|
+
const rowTyped = row.value;
|
|
1063
|
+
if (rowTyped.type !== 'adapter') {
|
|
1064
|
+
continue;
|
|
2124
1065
|
}
|
|
1066
|
+
await new Promise(resolve => objects.chownFile(rowTyped.common.name, '*', {
|
|
1067
|
+
user: 'system.user.admin',
|
|
1068
|
+
owner: user,
|
|
1069
|
+
ownerGroup: group,
|
|
1070
|
+
}, (err, processed) => {
|
|
1071
|
+
if (!err && processed) {
|
|
1072
|
+
files.push({ id: rowTyped.common.name, processed });
|
|
1073
|
+
}
|
|
1074
|
+
resolve();
|
|
1075
|
+
}));
|
|
2125
1076
|
}
|
|
2126
|
-
|
|
2127
|
-
console.
|
|
1077
|
+
if (!files.length) {
|
|
1078
|
+
console.log('Nothing found');
|
|
1079
|
+
return void callback();
|
|
2128
1080
|
}
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
1081
|
+
const list = new List({
|
|
1082
|
+
states,
|
|
1083
|
+
objects,
|
|
1084
|
+
processExit: callback,
|
|
1085
|
+
});
|
|
1086
|
+
files.sort((a, b) => a.id.localeCompare(b.id));
|
|
1087
|
+
list.showFileHeader();
|
|
1088
|
+
for (let k = 0; k < files.length; k++) {
|
|
1089
|
+
for (let t = 0; t < files[k].processed.length; t++) {
|
|
1090
|
+
list.showFile(files[k].id, files[k].processed[t].path, files[k].processed[t]);
|
|
2137
1091
|
}
|
|
2138
|
-
return void callback(EXIT_CODES.NO_ERROR);
|
|
2139
|
-
}
|
|
2140
|
-
catch (err) {
|
|
2141
|
-
console.error(`Error on sync: ${err.message}. Partial content might have been synced.`);
|
|
2142
|
-
return void callback(EXIT_CODES.CANNOT_SYNC_FILES);
|
|
2143
1092
|
}
|
|
1093
|
+
setTimeout(callback, 1_000);
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
else {
|
|
1098
|
+
const parts = pattern.split('/');
|
|
1099
|
+
const id = parts.shift();
|
|
1100
|
+
const path = parts.join('/');
|
|
1101
|
+
objects.chownFile(id, path, {
|
|
1102
|
+
user: 'system.user.admin',
|
|
1103
|
+
owner: user,
|
|
1104
|
+
ownerGroup: group,
|
|
1105
|
+
}, (err, processed) => {
|
|
1106
|
+
if (err) {
|
|
1107
|
+
console.error(err);
|
|
2144
1108
|
}
|
|
2145
1109
|
else {
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
1110
|
+
// call here list
|
|
1111
|
+
if (processed) {
|
|
1112
|
+
const list = new List({
|
|
1113
|
+
states,
|
|
1114
|
+
objects,
|
|
1115
|
+
processExit: callback,
|
|
1116
|
+
});
|
|
1117
|
+
list.showFileHeader();
|
|
1118
|
+
for (const file of processed) {
|
|
1119
|
+
list.showFile(id, file.path, file);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
2150
1122
|
}
|
|
1123
|
+
setTimeout(callback, 1_000);
|
|
2151
1124
|
});
|
|
2152
|
-
break;
|
|
2153
1125
|
}
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Process the `package` CLI command: create the package.json for the ioBroker installation
|
|
1130
|
+
*
|
|
1131
|
+
* @param options command options provided by the dispatcher
|
|
1132
|
+
*/
|
|
1133
|
+
async function processCommandPackage(options) {
|
|
1134
|
+
const { callback } = options;
|
|
1135
|
+
// Create package.json in /opt/' + tools.appName + '
|
|
1136
|
+
const json = {
|
|
1137
|
+
name: tools.appName,
|
|
1138
|
+
engines: {
|
|
1139
|
+
node: '>=22',
|
|
1140
|
+
},
|
|
1141
|
+
optionalDependencies: {},
|
|
1142
|
+
dependencies: {
|
|
1143
|
+
[`${tools.appName.toLowerCase()}.js-controller`]: '*',
|
|
1144
|
+
[`${tools.appName.toLowerCase()}.admin`]: '*',
|
|
1145
|
+
},
|
|
1146
|
+
author: 'bluefox <dogafox@gmail.com>',
|
|
1147
|
+
};
|
|
1148
|
+
try {
|
|
1149
|
+
const sources = await tools.getRepositoryFile();
|
|
1150
|
+
if (sources) {
|
|
1151
|
+
for (const s in sources) {
|
|
1152
|
+
if (Object.prototype.hasOwnProperty.call(sources, s)) {
|
|
1153
|
+
if (sources[s].url) {
|
|
1154
|
+
if (!json.dependencies[`${tools.appName}.${s}`]) {
|
|
1155
|
+
json.optionalDependencies[`${tools.appName}.${s}`] = sources[s].url;
|
|
1156
|
+
}
|
|
2161
1157
|
}
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
1158
|
+
else {
|
|
1159
|
+
if (!json.dependencies[`${tools.appName}.${s}`]) {
|
|
1160
|
+
json.optionalDependencies[`${tools.appName}.${s}`] = '*';
|
|
1161
|
+
}
|
|
2165
1162
|
}
|
|
2166
|
-
console.error('Error: no UUID found');
|
|
2167
|
-
return void callback(EXIT_CODES.CANNOT_GET_UUID);
|
|
2168
|
-
});
|
|
2169
|
-
});
|
|
2170
|
-
break;
|
|
2171
|
-
}
|
|
2172
|
-
case 'v':
|
|
2173
|
-
case 'version': {
|
|
2174
|
-
const adapter = params.adapter;
|
|
2175
|
-
if (params.ignore) {
|
|
2176
|
-
try {
|
|
2177
|
-
const { objects } = await dbConnectAsync(false, params);
|
|
2178
|
-
await ignoreVersion({ adapterName: adapter, version: params.ignore, objects });
|
|
2179
|
-
}
|
|
2180
|
-
catch (e) {
|
|
2181
|
-
console.error(e.message);
|
|
2182
|
-
callback(e instanceof IoBrokerError ? e.code : EXIT_CODES.UNKNOWN_ERROR);
|
|
2183
|
-
return;
|
|
2184
|
-
}
|
|
2185
|
-
console.log(`Successfully ignored version "${params.ignore}" of adapter "${params.adapter}"!`);
|
|
2186
|
-
callback();
|
|
2187
|
-
return;
|
|
2188
|
-
}
|
|
2189
|
-
if (params.recognize) {
|
|
2190
|
-
try {
|
|
2191
|
-
const { objects } = await dbConnectAsync(false, params);
|
|
2192
|
-
await recognizeVersion({ adapterName: adapter, objects });
|
|
2193
|
-
}
|
|
2194
|
-
catch (e) {
|
|
2195
|
-
console.error(e.message);
|
|
2196
|
-
callback(e instanceof IoBrokerError ? e.code : EXIT_CODES.UNKNOWN_ERROR);
|
|
2197
|
-
}
|
|
2198
|
-
console.log(`Successfully recognized all versions of adapter "${params.adapter}" again!`);
|
|
2199
|
-
callback();
|
|
2200
|
-
return;
|
|
2201
|
-
}
|
|
2202
|
-
let packJson;
|
|
2203
|
-
if (adapter) {
|
|
2204
|
-
try {
|
|
2205
|
-
packJson = require(`${tools.appName.toLowerCase()}.${adapter}/package.json`);
|
|
2206
|
-
}
|
|
2207
|
-
catch {
|
|
2208
|
-
packJson = { version: `"${adapter}" not found` };
|
|
2209
1163
|
}
|
|
2210
1164
|
}
|
|
2211
|
-
else {
|
|
2212
|
-
packJson = require(`@iobroker/js-controller-common/package.json`);
|
|
2213
|
-
}
|
|
2214
|
-
console.log(packJson.version);
|
|
2215
|
-
return void callback();
|
|
2216
|
-
}
|
|
2217
|
-
case 'checklog': {
|
|
2218
|
-
dbConnect(params, async ({ objects, states, isOffline, objectsDBType }) => {
|
|
2219
|
-
const hasLocalObjectsServer = await objectsDbHasServer(objectsDBType);
|
|
2220
|
-
if (isOffline && hasLocalObjectsServer) {
|
|
2221
|
-
console.log(`${tools.appName} is not running`);
|
|
2222
|
-
return void callback(EXIT_CODES.CONTROLLER_NOT_RUNNING);
|
|
2223
|
-
}
|
|
2224
|
-
console.log(`${tools.appName} is running`);
|
|
2225
|
-
objects.getObjectList({
|
|
2226
|
-
startkey: 'system.host.',
|
|
2227
|
-
endkey: `system.host.\u9999`,
|
|
2228
|
-
}, null, (err, res) => {
|
|
2229
|
-
if (!err && res?.rows.length) {
|
|
2230
|
-
for (const row of res.rows) {
|
|
2231
|
-
const parts = row.id.split('.');
|
|
2232
|
-
// ignore system.host.name.alive and so on
|
|
2233
|
-
if (parts.length === 3) {
|
|
2234
|
-
states.pushMessage(row.id, {
|
|
2235
|
-
command: 'checkLogging',
|
|
2236
|
-
message: null,
|
|
2237
|
-
from: 'console',
|
|
2238
|
-
});
|
|
2239
|
-
}
|
|
2240
|
-
}
|
|
2241
|
-
}
|
|
2242
|
-
setTimeout(callback, 200);
|
|
2243
|
-
});
|
|
2244
|
-
});
|
|
2245
|
-
break;
|
|
2246
1165
|
}
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
1166
|
+
fs.writeFileSync(path.join(tools.getRootDir(), 'package.json'), JSON.stringify(json, null, 2));
|
|
1167
|
+
return void callback();
|
|
1168
|
+
}
|
|
1169
|
+
catch (e) {
|
|
1170
|
+
console.error(`Cannot read repository file: ${e}`);
|
|
1171
|
+
return void callback(EXIT_CODES.UNKNOWN_ERROR);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Process the `set` CLI command: change settings of an adapter instance config
|
|
1176
|
+
*
|
|
1177
|
+
* @param options command options provided by the dispatcher
|
|
1178
|
+
*/
|
|
1179
|
+
async function processCommandSet(options) {
|
|
1180
|
+
const { args, params, callback } = options;
|
|
1181
|
+
const instance = args[0];
|
|
1182
|
+
if (!instance) {
|
|
1183
|
+
console.warn('please specify instance.');
|
|
1184
|
+
return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
|
|
1185
|
+
}
|
|
1186
|
+
if (!instance.includes('.')) {
|
|
1187
|
+
console.warn(`please specify instance, like "${instance}.0"`);
|
|
1188
|
+
return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
|
|
1189
|
+
}
|
|
1190
|
+
const { objects } = await dbConnectAsync(false, params);
|
|
1191
|
+
let obj;
|
|
1192
|
+
try {
|
|
1193
|
+
obj = await objects.getObjectAsync(`system.adapter.${instance}`);
|
|
1194
|
+
}
|
|
1195
|
+
catch {
|
|
1196
|
+
// ignore
|
|
1197
|
+
}
|
|
1198
|
+
if (obj) {
|
|
1199
|
+
let changed = false;
|
|
1200
|
+
for (let a = 0; a < process.argv.length; a++) {
|
|
1201
|
+
if (process.argv[a].startsWith('--') && process.argv[a + 1] && !process.argv[a + 1].startsWith('--')) {
|
|
1202
|
+
const attr = process.argv[a].substring(2);
|
|
1203
|
+
let val = process.argv[a + 1];
|
|
1204
|
+
if (val === '__EMPTY__') {
|
|
1205
|
+
val = '';
|
|
2274
1206
|
}
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
repoUrlOrCommand === 'del' ||
|
|
2278
|
-
repoUrlOrCommand === 'set' ||
|
|
2279
|
-
repoUrlOrCommand === 'addset' ||
|
|
2280
|
-
repoUrlOrCommand === 'unset') {
|
|
2281
|
-
if (!repoName || !repoName.match(/[-_\w]+/)) {
|
|
2282
|
-
console.error(`Invalid repository name: "${repoName}"`);
|
|
2283
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1207
|
+
else if (val === 'true') {
|
|
1208
|
+
val = true;
|
|
2284
1209
|
}
|
|
2285
|
-
if (
|
|
2286
|
-
|
|
2287
|
-
repoName = await repo.getNameByIndex(parseInt(repoName));
|
|
2288
|
-
}
|
|
2289
|
-
catch (e) {
|
|
2290
|
-
console.error(e.message);
|
|
2291
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2292
|
-
}
|
|
1210
|
+
else if (val === 'false') {
|
|
1211
|
+
val = false;
|
|
2293
1212
|
}
|
|
2294
|
-
if (
|
|
2295
|
-
|
|
2296
|
-
console.warn(`Please define repository URL or path: ${tools.appName.toLowerCase()} add <repoName> <repoUrlOrPath>`);
|
|
2297
|
-
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2298
|
-
}
|
|
2299
|
-
try {
|
|
2300
|
-
await repo.add(repoName, repoUrl);
|
|
2301
|
-
if (repoUrlOrCommand === 'addset') {
|
|
2302
|
-
await repo.setActive(repoName);
|
|
2303
|
-
console.log(`Repository "${repoName}" set as active: "${repoUrl}"`);
|
|
2304
|
-
await repo.showRepoStatus();
|
|
2305
|
-
return void callback();
|
|
2306
|
-
}
|
|
2307
|
-
console.log(`Repository "${repoName}" added as "${repoUrl}"`);
|
|
2308
|
-
await repo.showRepoStatus();
|
|
2309
|
-
return void callback();
|
|
2310
|
-
}
|
|
2311
|
-
catch (e) {
|
|
2312
|
-
console.error(`Cannot add repository location: ${e.message}`);
|
|
2313
|
-
return void callback(EXIT_CODES.INVALID_REPO);
|
|
2314
|
-
}
|
|
1213
|
+
else if (parseFloat(val).toString() === val) {
|
|
1214
|
+
val = parseFloat(val);
|
|
2315
1215
|
}
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
console.
|
|
2320
|
-
await repo.showRepoStatus();
|
|
2321
|
-
return void callback();
|
|
1216
|
+
if (attr.indexOf('.') !== -1) {
|
|
1217
|
+
const parts = attr.split('.');
|
|
1218
|
+
if (!obj.native[parts[0]] || obj.native[parts[0]][parts[1]] === undefined) {
|
|
1219
|
+
console.warn(`Adapter "${instance}" has no setting "${attr}".`);
|
|
2322
1220
|
}
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
1221
|
+
else {
|
|
1222
|
+
changed = true;
|
|
1223
|
+
obj.native[parts[0]][parts[1]] = val;
|
|
1224
|
+
console.log(`New ${attr} for "${instance}" is: ${val}`);
|
|
2326
1225
|
}
|
|
2327
1226
|
}
|
|
2328
|
-
else
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
console.log(`Repository "${repoName}" deleted.`);
|
|
2332
|
-
await repo.showRepoStatus();
|
|
2333
|
-
return void callback();
|
|
1227
|
+
else {
|
|
1228
|
+
if (obj.native[attr] === undefined) {
|
|
1229
|
+
console.warn(`Adapter "${instance}" has no setting "${attr}".`);
|
|
2334
1230
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
1231
|
+
else {
|
|
1232
|
+
changed = true;
|
|
1233
|
+
obj.native[attr] = val;
|
|
1234
|
+
console.log(`New ${attr} for "${instance}" is: ${val}`);
|
|
2338
1235
|
}
|
|
2339
1236
|
}
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
1237
|
+
a++;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
if (changed) {
|
|
1241
|
+
obj.from = `system.host.${tools.getHostName()}.cli`;
|
|
1242
|
+
obj.ts = new Date().getTime();
|
|
1243
|
+
objects.setObject(`system.adapter.${instance}`, obj, () => {
|
|
1244
|
+
console.log(`Instance settings for "${instance}" are changed.`);
|
|
1245
|
+
return void callback();
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
else {
|
|
1249
|
+
console.log('No parameters set.');
|
|
1250
|
+
return void callback();
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
else {
|
|
1254
|
+
CLIError.invalidInstance(instance);
|
|
1255
|
+
return void callback(EXIT_CODES.INVALID_ADAPTER_ID);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Process the `file` CLI command: read, write, delete or sync files in the objects DB
|
|
1260
|
+
*
|
|
1261
|
+
* @param options command options provided by the dispatcher
|
|
1262
|
+
*/
|
|
1263
|
+
function processCommandFile(options) {
|
|
1264
|
+
const { args, params, callback } = options;
|
|
1265
|
+
const cmd = args[0];
|
|
1266
|
+
if (cmd !== 'read' &&
|
|
1267
|
+
cmd !== 'r' &&
|
|
1268
|
+
cmd !== 'w' &&
|
|
1269
|
+
cmd !== 'write' &&
|
|
1270
|
+
cmd !== 'sync' &&
|
|
1271
|
+
cmd !== 'rm' &&
|
|
1272
|
+
cmd !== 'unlink' &&
|
|
1273
|
+
cmd !== 'del') {
|
|
1274
|
+
console.log('Invalid parameters: write "file read /vis-2.0/main/img/picture.png /opt/picture/image.png" to read the file');
|
|
1275
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1276
|
+
}
|
|
1277
|
+
if (cmd !== 'sync' && !args[1]) {
|
|
1278
|
+
console.log('Invalid parameters: write "file read /vis-2.0/main/img/picture.png /opt/picture/image.png" to read the file from DB and store it on disk');
|
|
1279
|
+
console.log('or "file write /opt/SOURCE/image.png /vis-2.0/main/DESTINATION/picture.png" to write the file into DB from disk');
|
|
1280
|
+
console.log('or "file rm /vis-2.0/main/img/picture.png" to delete the file in DB');
|
|
1281
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1282
|
+
}
|
|
1283
|
+
dbConnect(params, async ({ objects, objectsDBType }) => {
|
|
1284
|
+
if (cmd === 'read' || cmd === 'r') {
|
|
1285
|
+
const toRead = args[1];
|
|
1286
|
+
const parts = toRead.replace(/\\/g, '/').split('/');
|
|
1287
|
+
const path = (args[2] || process.cwd()).replace(/\\/g, '/').split('/');
|
|
1288
|
+
const file = path[path.length - 1];
|
|
1289
|
+
if (!file.match(/\.[a-zA-Z0-9]+$/)) {
|
|
1290
|
+
// If destination location seems to be a directory, add filename
|
|
1291
|
+
if (file !== '') {
|
|
1292
|
+
path.push(parts[parts.length - 1]);
|
|
2351
1293
|
}
|
|
2352
1294
|
else {
|
|
2353
|
-
|
|
2354
|
-
|
|
1295
|
+
// trailing slash
|
|
1296
|
+
path[path.length - 1] = parts[parts.length - 1];
|
|
2355
1297
|
}
|
|
2356
1298
|
}
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
if (
|
|
2363
|
-
|
|
2364
|
-
cmd !== 's' &&
|
|
2365
|
-
cmd !== 'status' &&
|
|
2366
|
-
cmd !== 'b' &&
|
|
2367
|
-
cmd !== 'browse' &&
|
|
2368
|
-
cmd !== 'e' &&
|
|
2369
|
-
cmd !== 'enable' &&
|
|
2370
|
-
cmd !== 'd' &&
|
|
2371
|
-
cmd !== 'disable') {
|
|
2372
|
-
console.log('Invalid parameters. Following is possible: enable, browse, connect, status');
|
|
1299
|
+
let adapt = parts.shift();
|
|
1300
|
+
if (!adapt) {
|
|
1301
|
+
// leading slash
|
|
1302
|
+
adapt = parts.shift();
|
|
1303
|
+
}
|
|
1304
|
+
if (!adapt) {
|
|
1305
|
+
console.log(`Invalid parameters: adapter cannot be found!`);
|
|
2373
1306
|
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2374
1307
|
}
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
mh.status();
|
|
2383
|
-
return void callback();
|
|
2384
|
-
}
|
|
2385
|
-
else if (cmd === 'b' || cmd === 'browse') {
|
|
2386
|
-
try {
|
|
2387
|
-
const list = await mh.browse();
|
|
2388
|
-
mh.showHosts(list);
|
|
2389
|
-
return void callback();
|
|
2390
|
-
}
|
|
2391
|
-
catch (e) {
|
|
2392
|
-
console.error(e.message);
|
|
2393
|
-
return void callback(EXIT_CODES.CANNOT_CREATE_USER_OR_GROUP);
|
|
2394
|
-
}
|
|
2395
|
-
}
|
|
2396
|
-
else if (cmd === 'e' || cmd === 'enable') {
|
|
2397
|
-
mh.enable(true, async (err) => {
|
|
2398
|
-
if (err) {
|
|
2399
|
-
console.error(err);
|
|
2400
|
-
return void callback(EXIT_CODES.CANNOT_ENABLE_MULTIHOST);
|
|
2401
|
-
}
|
|
2402
|
-
await states.pushMessage(`system.host.${tools.getHostName()}`, {
|
|
2403
|
-
command: 'updateMultihost',
|
|
2404
|
-
message: null,
|
|
2405
|
-
from: 'setup',
|
|
2406
|
-
});
|
|
2407
|
-
callback();
|
|
2408
|
-
});
|
|
2409
|
-
}
|
|
2410
|
-
else if (cmd === 'd' || cmd === 'disable') {
|
|
2411
|
-
mh.enable(false, async (err) => {
|
|
2412
|
-
if (err) {
|
|
2413
|
-
console.error(err);
|
|
2414
|
-
return void callback(EXIT_CODES.CANNOT_ENABLE_MULTIHOST);
|
|
2415
|
-
}
|
|
2416
|
-
await states.pushMessage(`system.host.${tools.getHostName()}`, {
|
|
2417
|
-
command: 'updateMultihost',
|
|
2418
|
-
message: null,
|
|
2419
|
-
from: 'setup',
|
|
2420
|
-
});
|
|
2421
|
-
callback();
|
|
2422
|
-
});
|
|
1308
|
+
if (!parts.length) {
|
|
1309
|
+
console.log('Invalid parameters: file cannot be found: file not provided');
|
|
1310
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1311
|
+
}
|
|
1312
|
+
objects.readFile(adapt, parts.join('/'), null, (err, data) => {
|
|
1313
|
+
if (err) {
|
|
1314
|
+
console.error(err);
|
|
2423
1315
|
}
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
}
|
|
2429
|
-
return void callback(err ? 1 : 0);
|
|
2430
|
-
});
|
|
1316
|
+
if (data) {
|
|
1317
|
+
const destFilename = path.join('/');
|
|
1318
|
+
fs.writeFileSync(destFilename, data);
|
|
1319
|
+
console.log(`File "${toRead}" stored as "${destFilename}"`);
|
|
2431
1320
|
}
|
|
1321
|
+
return void callback(EXIT_CODES.NO_ERROR);
|
|
2432
1322
|
});
|
|
2433
|
-
break;
|
|
2434
1323
|
}
|
|
2435
|
-
|
|
2436
|
-
const
|
|
2437
|
-
const
|
|
2438
|
-
const
|
|
2439
|
-
|
|
2440
|
-
|
|
1324
|
+
else if (cmd === 'write' || cmd === 'w') {
|
|
1325
|
+
const toRead = args[1] || '';
|
|
1326
|
+
const parts = toRead.replace(/\\/g, '/').split('/');
|
|
1327
|
+
const path = (args[2] || '').replace(/\\/g, '/').split('/');
|
|
1328
|
+
let adapt = path.shift();
|
|
1329
|
+
if (!adapt) {
|
|
1330
|
+
adapt = path.shift();
|
|
1331
|
+
}
|
|
1332
|
+
if (!path.length) {
|
|
1333
|
+
path.push('');
|
|
1334
|
+
}
|
|
1335
|
+
const fileSrc = parts[parts.length - 1];
|
|
1336
|
+
let fileDest = path[path.length - 1];
|
|
1337
|
+
if (!fileDest || !fileDest.match(/\.[a-zA-Z0-9]+$/)) {
|
|
1338
|
+
// last portion of destination has no extension, consider being a directory
|
|
1339
|
+
fileDest = '';
|
|
1340
|
+
}
|
|
1341
|
+
if (!fileSrc || !fs.existsSync(toRead)) {
|
|
1342
|
+
console.log(`Please provide a valid file name as source file: "file write /opt/SOURCE/script.js /vis-2/DESTINATION/script.js"`);
|
|
2441
1343
|
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2442
1344
|
}
|
|
2443
|
-
const
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
await vendor.checkVendor(file, password, javascriptPassword);
|
|
2448
|
-
console.log(`Synchronised vendor information.`);
|
|
2449
|
-
return void callback();
|
|
1345
|
+
const srcStat = fs.statSync(toRead);
|
|
1346
|
+
if (!srcStat.isFile()) {
|
|
1347
|
+
console.log(`Please provide a valid file name as source file: "file write /opt/SOURCE/script.js /vis-2/DESTINATION/script.js"`);
|
|
1348
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2450
1349
|
}
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
1350
|
+
if (!fileDest) {
|
|
1351
|
+
// destination filename is not given, use same name as source file
|
|
1352
|
+
fileDest = fileSrc;
|
|
2454
1353
|
}
|
|
1354
|
+
if (fileDest !== path[path.length - 1]) {
|
|
1355
|
+
// if last part of path is different then filename, add filename
|
|
1356
|
+
if (path[path.length - 1] !== '') {
|
|
1357
|
+
path.push(fileDest);
|
|
1358
|
+
}
|
|
1359
|
+
else {
|
|
1360
|
+
// trailing slash
|
|
1361
|
+
path[path.length - 1] = fileDest;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
const destFilename = path.length ? path.join('/') : '/';
|
|
1365
|
+
if (!fs.existsSync(toRead)) {
|
|
1366
|
+
console.log('Invalid parameters: file does not exist!');
|
|
1367
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1368
|
+
}
|
|
1369
|
+
const data = fs.readFileSync(toRead);
|
|
1370
|
+
if (!adapt) {
|
|
1371
|
+
console.log('Invalid parameters: destination adapter cannot be found!');
|
|
1372
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1373
|
+
}
|
|
1374
|
+
objects
|
|
1375
|
+
.writeFile(adapt, destFilename, data, _err => {
|
|
1376
|
+
console.log(`File "${toRead}" stored as "${destFilename}"`);
|
|
1377
|
+
return void callback(EXIT_CODES.NO_ERROR);
|
|
1378
|
+
})
|
|
1379
|
+
.catch(e => console.error(`Cannot write file: ${e.message}`));
|
|
2455
1380
|
}
|
|
2456
|
-
|
|
2457
|
-
const
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
case 'plugin': {
|
|
2467
|
-
const pluginCommand = new CLIPlugin(commandOptions);
|
|
2468
|
-
pluginCommand.execute(args);
|
|
2469
|
-
break;
|
|
2470
|
-
}
|
|
2471
|
-
case 'license': {
|
|
2472
|
-
const file = args[0];
|
|
2473
|
-
if (!file) {
|
|
2474
|
-
console.warn(`Please specify the path to the license file or place license text directly!\n${tools.appName.toLowerCase()} license <license.file or license.text>`);
|
|
1381
|
+
else if (cmd === 'del' || cmd === 'rm' || cmd === 'unlink') {
|
|
1382
|
+
const toDelete = args[1];
|
|
1383
|
+
const parts = toDelete.replace(/\\/g, '/').split('/');
|
|
1384
|
+
let adapt = parts.shift();
|
|
1385
|
+
if (!adapt) {
|
|
1386
|
+
// leading slash
|
|
1387
|
+
adapt = parts.shift();
|
|
1388
|
+
}
|
|
1389
|
+
if (!adapt) {
|
|
1390
|
+
console.log('Invalid parameters: adapter cannot be found!');
|
|
2475
1391
|
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
2476
1392
|
}
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
1393
|
+
if (!parts.length) {
|
|
1394
|
+
console.log('Invalid parameters: file cannot be found: file not provided');
|
|
1395
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1396
|
+
}
|
|
1397
|
+
objects.unlink(adapt, parts.join('/'), null, err => {
|
|
1398
|
+
if (err) {
|
|
1399
|
+
console.error(err);
|
|
2484
1400
|
}
|
|
2485
|
-
|
|
2486
|
-
console.
|
|
2487
|
-
return void callback(EXIT_CODES.CANNOT_UPDATE_LICENSE);
|
|
1401
|
+
else {
|
|
1402
|
+
console.log(`File "${toDelete}" was deleted`);
|
|
2488
1403
|
}
|
|
1404
|
+
return void callback(EXIT_CODES.NO_ERROR);
|
|
2489
1405
|
});
|
|
2490
|
-
break;
|
|
2491
1406
|
}
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
1407
|
+
else if (cmd === 'sync') {
|
|
1408
|
+
// Sync
|
|
1409
|
+
if (objectsDBType === 'redis') {
|
|
1410
|
+
console.log('File Sync is not available when database type "redis" is used.');
|
|
1411
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1412
|
+
}
|
|
1413
|
+
// @ts-expect-error todo look in depth how to handle
|
|
1414
|
+
if (!objects.syncFileDirectory || !objects.dirExists) {
|
|
1415
|
+
// functionality only exists in server class
|
|
1416
|
+
console.log('Please stop ioBroker before syncing files and only use this command on the ioBroker master host!');
|
|
1417
|
+
return void callback(EXIT_CODES.CONTROLLER_RUNNING);
|
|
1418
|
+
}
|
|
1419
|
+
// check meta.user
|
|
1420
|
+
try {
|
|
1421
|
+
const objExists = await objects.objectExists('meta.user');
|
|
1422
|
+
if (objExists) {
|
|
1423
|
+
// check if dir is missing
|
|
1424
|
+
// @ts-expect-error todo look in depth how to handle
|
|
1425
|
+
const dirExists = objects.dirExists('meta.user');
|
|
1426
|
+
if (!dirExists) {
|
|
1427
|
+
// create meta.user, so users see them as upload target
|
|
1428
|
+
await objects.mkdirAsync('meta.user');
|
|
1429
|
+
console.log('Successfully created "meta.user" directory');
|
|
2501
1430
|
}
|
|
2502
1431
|
}
|
|
2503
|
-
|
|
2504
|
-
|
|
1432
|
+
}
|
|
1433
|
+
catch (err) {
|
|
1434
|
+
console.warn(`Could not create directory "meta.user": ${err.message}`);
|
|
1435
|
+
}
|
|
1436
|
+
try {
|
|
1437
|
+
// @ts-expect-error todo types needed for this one? but only exists sometimes..
|
|
1438
|
+
const { numberSuccess, notifications } = objects.syncFileDirectory(args[1]);
|
|
1439
|
+
console.log(`${numberSuccess} file(s) successfully synchronized with ioBroker storage`);
|
|
1440
|
+
if (notifications.length) {
|
|
1441
|
+
console.log('\nThe following notifications happened during sync: ');
|
|
1442
|
+
notifications.forEach((el) => console.log(`- ${el}`));
|
|
2505
1443
|
}
|
|
2506
|
-
|
|
1444
|
+
return void callback(EXIT_CODES.NO_ERROR);
|
|
2507
1445
|
}
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
return void callback(EXIT_CODES.
|
|
1446
|
+
catch (err) {
|
|
1447
|
+
console.error(`Error on sync: ${err.message}. Partial content might have been synced.`);
|
|
1448
|
+
return void callback(EXIT_CODES.CANNOT_SYNC_FILES);
|
|
2511
1449
|
}
|
|
2512
|
-
|
|
1450
|
+
}
|
|
1451
|
+
else {
|
|
1452
|
+
console.log('Invalid parameters: write "file read /vis-2.0/main/img/picture.png /opt/picture/image.png" to read the file from DB and store it on disk');
|
|
1453
|
+
console.log('or "file write /opt/SOURCE/image.png /vis-2.0/main/DESTINATION/picture.png" to write the file into DB from disk');
|
|
1454
|
+
console.log('or "file rm /vis-2.0/main/img/picture.png" to delete the file in DB');
|
|
1455
|
+
return void callback(EXIT_CODES.INVALID_ARGUMENTS);
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* Process the `uuid` CLI command: print the installation UUID
|
|
1461
|
+
*
|
|
1462
|
+
* @param options command options provided by the dispatcher
|
|
1463
|
+
*/
|
|
1464
|
+
function processCommandUuid(options) {
|
|
1465
|
+
const { params, callback } = options;
|
|
1466
|
+
dbConnect(params, ({ objects }) => {
|
|
1467
|
+
objects.getObject('system.meta.uuid', (err, obj) => {
|
|
1468
|
+
if (err) {
|
|
1469
|
+
console.error(`Error: ${err.message}`);
|
|
1470
|
+
return void callback(EXIT_CODES.CANNOT_GET_UUID);
|
|
1471
|
+
}
|
|
1472
|
+
if (obj?.native) {
|
|
1473
|
+
console.log(obj.native.uuid);
|
|
1474
|
+
return void callback();
|
|
1475
|
+
}
|
|
1476
|
+
console.error('Error: no UUID found');
|
|
1477
|
+
return void callback(EXIT_CODES.CANNOT_GET_UUID);
|
|
1478
|
+
});
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Process the `version` CLI command: show version of js-controller or a specified adapter
|
|
1483
|
+
*
|
|
1484
|
+
* @param options command options provided by the dispatcher
|
|
1485
|
+
*/
|
|
1486
|
+
async function processCommandVersion(options) {
|
|
1487
|
+
const { params, callback } = options;
|
|
1488
|
+
const adapter = params.adapter;
|
|
1489
|
+
if (params.ignore) {
|
|
1490
|
+
try {
|
|
1491
|
+
const { objects } = await dbConnectAsync(false, params);
|
|
1492
|
+
await ignoreVersion({ adapterName: adapter, version: params.ignore, objects });
|
|
1493
|
+
}
|
|
1494
|
+
catch (e) {
|
|
1495
|
+
console.error(e.message);
|
|
1496
|
+
callback(e instanceof IoBrokerError ? e.code : EXIT_CODES.UNKNOWN_ERROR);
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
console.log(`Successfully ignored version "${params.ignore}" of adapter "${params.adapter}"!`);
|
|
1500
|
+
callback();
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
if (params.recognize) {
|
|
1504
|
+
try {
|
|
1505
|
+
const { objects } = await dbConnectAsync(false, params);
|
|
1506
|
+
await recognizeVersion({ adapterName: adapter, objects });
|
|
1507
|
+
}
|
|
1508
|
+
catch (e) {
|
|
1509
|
+
console.error(e.message);
|
|
1510
|
+
callback(e instanceof IoBrokerError ? e.code : EXIT_CODES.UNKNOWN_ERROR);
|
|
1511
|
+
}
|
|
1512
|
+
console.log(`Successfully recognized all versions of adapter "${params.adapter}" again!`);
|
|
1513
|
+
callback();
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
let packJson;
|
|
1517
|
+
if (adapter) {
|
|
1518
|
+
try {
|
|
1519
|
+
packJson = require(`${tools.appName.toLowerCase()}.${adapter}/package.json`);
|
|
1520
|
+
}
|
|
1521
|
+
catch {
|
|
1522
|
+
packJson = { version: `"${adapter}" not found` };
|
|
2513
1523
|
}
|
|
2514
1524
|
}
|
|
1525
|
+
else {
|
|
1526
|
+
packJson = require(`@iobroker/js-controller-common/package.json`);
|
|
1527
|
+
}
|
|
1528
|
+
console.log(packJson.version);
|
|
1529
|
+
return void callback();
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* Process the `checklog` CLI command: trigger a logging check on all hosts
|
|
1533
|
+
*
|
|
1534
|
+
* @param options command options provided by the dispatcher
|
|
1535
|
+
*/
|
|
1536
|
+
function processCommandCheckLog(options) {
|
|
1537
|
+
const { params, callback } = options;
|
|
1538
|
+
dbConnect(params, async ({ objects, states, isOffline, objectsDBType }) => {
|
|
1539
|
+
const hasLocalObjectsServer = await objectsDbHasServer(objectsDBType);
|
|
1540
|
+
if (isOffline && hasLocalObjectsServer) {
|
|
1541
|
+
console.log(`${tools.appName} is not running`);
|
|
1542
|
+
return void callback(EXIT_CODES.CONTROLLER_NOT_RUNNING);
|
|
1543
|
+
}
|
|
1544
|
+
console.log(`${tools.appName} is running`);
|
|
1545
|
+
objects.getObjectList({
|
|
1546
|
+
startkey: 'system.host.',
|
|
1547
|
+
endkey: `system.host.\u9999`,
|
|
1548
|
+
}, null, (err, res) => {
|
|
1549
|
+
if (!err && res?.rows.length) {
|
|
1550
|
+
for (const row of res.rows) {
|
|
1551
|
+
const parts = row.id.split('.');
|
|
1552
|
+
// ignore system.host.name.alive and so on
|
|
1553
|
+
if (parts.length === 3) {
|
|
1554
|
+
states
|
|
1555
|
+
.pushMessage(row.id, {
|
|
1556
|
+
command: 'checkLogging',
|
|
1557
|
+
message: null,
|
|
1558
|
+
from: 'console',
|
|
1559
|
+
})
|
|
1560
|
+
.catch(e => console.error(`Cannot push checkLogging message: ${e.message}`));
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
setTimeout(callback, 200);
|
|
1565
|
+
});
|
|
1566
|
+
});
|
|
2515
1567
|
}
|
|
2516
1568
|
const OBJECTS_THAT_CANNOT_BE_DELETED = [
|
|
2517
1569
|
'0_userdata.0',
|
|
@@ -2572,9 +1624,8 @@ async function cleanDatabase(isDeleteDb) {
|
|
|
2572
1624
|
const { objects } = await dbConnectAsync(false);
|
|
2573
1625
|
if (isDeleteDb) {
|
|
2574
1626
|
await objects.destroyDBAsync();
|
|
2575
|
-
// Clean up states
|
|
2576
|
-
|
|
2577
|
-
return keysCount;
|
|
1627
|
+
// Clean up states and return keys count
|
|
1628
|
+
return await delStates();
|
|
2578
1629
|
}
|
|
2579
1630
|
// Clean only objects, not the views
|
|
2580
1631
|
let ids = [];
|
|
@@ -2589,9 +1640,8 @@ async function cleanDatabase(isDeleteDb) {
|
|
|
2589
1640
|
// ignore
|
|
2590
1641
|
}
|
|
2591
1642
|
await delObjects(ids);
|
|
2592
|
-
// Clean up states
|
|
2593
|
-
|
|
2594
|
-
return keysCount;
|
|
1643
|
+
// Clean up states and return the key count
|
|
1644
|
+
return await delStates();
|
|
2595
1645
|
}
|
|
2596
1646
|
async function unsetup(params, callback) {
|
|
2597
1647
|
const { objects } = await dbConnectAsync(false, params);
|
|
@@ -2645,12 +1695,11 @@ async function restartController() {
|
|
|
2645
1695
|
child.unref();
|
|
2646
1696
|
}
|
|
2647
1697
|
/**
|
|
2648
|
-
* Method
|
|
1698
|
+
* Method that should be called from CLI to initialize the handling of all args
|
|
2649
1699
|
*/
|
|
2650
1700
|
export function execute() {
|
|
2651
1701
|
// direct call
|
|
2652
1702
|
const _yargs = initYargs();
|
|
2653
|
-
// @ts-expect-error todo fix it
|
|
2654
1703
|
const command = _yargs.argv._[0];
|
|
2655
1704
|
const args = [];
|
|
2656
1705
|
// skip interpreter, filename and command
|
|
@@ -2661,10 +1710,10 @@ export function execute() {
|
|
|
2661
1710
|
}
|
|
2662
1711
|
args.push(process.argv[i]);
|
|
2663
1712
|
}
|
|
2664
|
-
processCommand(command, args, _yargs.argv, exitApplicationSave);
|
|
1713
|
+
processCommand(command, args, _yargs.argv, exitApplicationSave).catch(e => console.error(`Cannot process command: ${e.message}`));
|
|
2665
1714
|
}
|
|
2666
1715
|
process.on('unhandledRejection', (e) => {
|
|
2667
1716
|
console.error(`Uncaught Rejection: ${e.stack || e}`);
|
|
2668
|
-
exitApplicationSave(EXIT_CODES.UNCAUGHT_EXCEPTION);
|
|
1717
|
+
return exitApplicationSave(EXIT_CODES.UNCAUGHT_EXCEPTION);
|
|
2669
1718
|
});
|
|
2670
1719
|
//# sourceMappingURL=setup.js.map
|