iobroker.js-controller 7.2.3 → 8.0.0-alpha.1-20260921-e5941ca8a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/compactgroupController.js +1 -1
- package/build/cjs/compactgroupController.js.map +2 -2
- package/build/cjs/lib/adapterAutoUpgradeManager.d.ts +6 -0
- package/build/cjs/lib/adapterAutoUpgradeManager.js +8 -1
- package/build/cjs/lib/adapterAutoUpgradeManager.js.map +2 -2
- package/build/cjs/lib/adapterUpgradeManager.d.ts +15 -9
- package/build/cjs/lib/adapterUpgradeManager.js +19 -12
- package/build/cjs/lib/adapterUpgradeManager.js.map +2 -2
- package/build/cjs/lib/blocklistManager.d.ts +6 -0
- package/build/cjs/lib/blocklistManager.js +7 -0
- package/build/cjs/lib/blocklistManager.js.map +2 -2
- package/build/cjs/lib/multihostServer.d.ts +15 -0
- package/build/cjs/lib/multihostServer.js +20 -1
- package/build/cjs/lib/multihostServer.js.map +2 -2
- package/build/cjs/lib/objects.d.ts +1 -0
- package/build/cjs/lib/objects.js +2 -0
- package/build/cjs/lib/objects.js.map +2 -2
- package/build/cjs/lib/preinstallCheck.js +8 -1
- package/build/cjs/lib/preinstallCheck.js.map +2 -2
- package/build/cjs/lib/restart.js +3 -1
- package/build/cjs/lib/restart.js.map +2 -2
- package/build/cjs/lib/upgradeManager.d.ts +1 -1
- package/build/cjs/lib/upgradeManager.js +28 -17
- package/build/cjs/lib/upgradeManager.js.map +3 -3
- package/build/cjs/lib/utils.js +3 -0
- package/build/cjs/lib/utils.js.map +1 -1
- package/build/cjs/lib/vis/states.js +3 -0
- package/build/cjs/lib/vis/states.js.map +1 -1
- package/build/cjs/lib/vis/visUtils.js +8 -0
- package/build/cjs/lib/vis/visUtils.js.map +2 -2
- package/build/cjs/main.js +256 -173
- package/build/cjs/main.js.map +3 -3
- package/build/esm/compactgroupController.js +1 -1
- package/build/esm/compactgroupController.js.map +1 -1
- package/build/esm/lib/adapterAutoUpgradeManager.d.ts +6 -0
- package/build/esm/lib/adapterAutoUpgradeManager.d.ts.map +1 -1
- package/build/esm/lib/adapterAutoUpgradeManager.js +6 -0
- package/build/esm/lib/adapterAutoUpgradeManager.js.map +1 -1
- package/build/esm/lib/adapterUpgradeManager.d.ts +15 -9
- package/build/esm/lib/adapterUpgradeManager.d.ts.map +1 -1
- package/build/esm/lib/adapterUpgradeManager.js +16 -10
- package/build/esm/lib/adapterUpgradeManager.js.map +1 -1
- package/build/esm/lib/blocklistManager.d.ts +6 -0
- package/build/esm/lib/blocklistManager.d.ts.map +1 -1
- package/build/esm/lib/blocklistManager.js +6 -0
- package/build/esm/lib/blocklistManager.js.map +1 -1
- package/build/esm/lib/multihostServer.d.ts +15 -0
- package/build/esm/lib/multihostServer.d.ts.map +1 -1
- package/build/esm/lib/multihostServer.js +16 -1
- package/build/esm/lib/multihostServer.js.map +1 -1
- package/build/esm/lib/objects.d.ts +1 -0
- package/build/esm/lib/objects.d.ts.map +1 -1
- package/build/esm/lib/objects.js.map +1 -1
- package/build/esm/lib/preinstallCheck.js +10 -9
- package/build/esm/lib/preinstallCheck.js.map +1 -1
- package/build/esm/lib/restart.js +1 -1
- package/build/esm/lib/restart.js.map +1 -1
- package/build/esm/lib/upgradeManager.d.ts +1 -1
- package/build/esm/lib/upgradeManager.d.ts.map +1 -1
- package/build/esm/lib/upgradeManager.js +24 -18
- package/build/esm/lib/upgradeManager.js.map +1 -1
- package/build/esm/lib/vis/visUtils.d.ts.map +1 -1
- package/build/esm/lib/vis/visUtils.js.map +1 -1
- package/build/esm/main.d.ts.map +1 -1
- package/build/esm/main.js +252 -168
- package/build/esm/main.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/io-package.json +16 -2
- package/package.json +22 -22
|
@@ -5,5 +5,5 @@ if (isNaN(compactGroup) || compactGroup < 1) {
|
|
|
5
5
|
console.log(`Invalid compact group (${compactGroup}) as first parameter. Exit.`);
|
|
6
6
|
process.exit();
|
|
7
7
|
}
|
|
8
|
-
(0, import_main.init)(compactGroup);
|
|
8
|
+
(0, import_main.init)(compactGroup).catch((e) => console.error(`Cannot start compact group controller: ${e.message}`));
|
|
9
9
|
//# sourceMappingURL=compactgroupController.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/compactgroupController.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Controller process for Compact Groups\n *\n * Copyright 2018-2024 bluefox <dogafox@gmail.com>,\n * MIT License\n *\n */\nimport { init } from '@/main.js';\n\nconst compactGroup = parseInt(process.argv[2], 10);\nif (isNaN(compactGroup) || compactGroup < 1) {\n console.log(`Invalid compact group (${compactGroup}) as first parameter. Exit.`);\n process.exit();\n}\n\ninit(compactGroup);\n"],
|
|
5
|
-
"mappings": ";AAOA,kBAAqB;AAErB,MAAM,eAAe,SAAS,QAAQ,KAAK,CAAC,GAAG,EAAE;AACjD,IAAI,MAAM,YAAY,KAAK,eAAe,GAAG;AACzC,UAAQ,IAAI,0BAA0B,YAAY,6BAA6B;AAC/E,UAAQ,KAAI;AAChB;IAEA,kBAAK,YAAY;",
|
|
4
|
+
"sourcesContent": ["/**\n * Controller process for Compact Groups\n *\n * Copyright 2018-2024 bluefox <dogafox@gmail.com>,\n * MIT License\n *\n */\nimport { init } from '@/main.js';\n\nconst compactGroup = parseInt(process.argv[2], 10);\nif (isNaN(compactGroup) || compactGroup < 1) {\n console.log(`Invalid compact group (${compactGroup}) as first parameter. Exit.`);\n process.exit();\n}\n\ninit(compactGroup).catch(e => console.error(`Cannot start compact group controller: ${e.message}`));\n"],
|
|
5
|
+
"mappings": ";AAOA,kBAAqB;AAErB,MAAM,eAAe,SAAS,QAAQ,KAAK,CAAC,GAAG,EAAE;AACjD,IAAI,MAAM,YAAY,KAAK,eAAe,GAAG;AACzC,UAAQ,IAAI,0BAA0B,YAAY,6BAA6B;AAC/E,UAAQ,KAAI;AAChB;IAEA,kBAAK,YAAY,EAAE,MAAM,OAAK,QAAQ,MAAM,0CAA0C,EAAE,OAAO,EAAE,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -25,6 +25,9 @@ interface UpgradeAdaptersResult {
|
|
|
25
25
|
/** Adapters which were failed to upgrade */
|
|
26
26
|
failedAdapters: UpgradedAdapter[];
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Manages automatic upgrades of adapters based on the configured upgrade policy
|
|
30
|
+
*/
|
|
28
31
|
export declare class AdapterAutoUpgradeManager {
|
|
29
32
|
private readonly objects;
|
|
30
33
|
private readonly states;
|
|
@@ -34,6 +37,9 @@ export declare class AdapterAutoUpgradeManager {
|
|
|
34
37
|
private readonly logPrefix;
|
|
35
38
|
/** Logger which needs to be prefixed */
|
|
36
39
|
private logger;
|
|
40
|
+
/**
|
|
41
|
+
* @param options The objects/states clients, logger and log prefix
|
|
42
|
+
*/
|
|
37
43
|
constructor(options: AdapterAutoUpgradeOptions);
|
|
38
44
|
/**
|
|
39
45
|
* Checks if auto upgrade is enabled for the current configured repository
|
|
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
9
|
var __export = (target, all) => {
|
|
9
10
|
for (var name in all)
|
|
10
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -34,6 +35,9 @@ module.exports = __toCommonJS(adapterAutoUpgradeManager_exports);
|
|
|
34
35
|
var import_js_controller_cli = require("@iobroker/js-controller-cli");
|
|
35
36
|
var import_semver = __toESM(require("semver"), 1);
|
|
36
37
|
class AdapterAutoUpgradeManager {
|
|
38
|
+
static {
|
|
39
|
+
__name(this, "AdapterAutoUpgradeManager");
|
|
40
|
+
}
|
|
37
41
|
objects;
|
|
38
42
|
states;
|
|
39
43
|
/** Mapping from semver range to range identifier */
|
|
@@ -47,6 +51,9 @@ class AdapterAutoUpgradeManager {
|
|
|
47
51
|
logPrefix;
|
|
48
52
|
/** Logger which needs to be prefixed */
|
|
49
53
|
logger;
|
|
54
|
+
/**
|
|
55
|
+
* @param options The objects/states clients, logger and log prefix
|
|
56
|
+
*/
|
|
50
57
|
constructor(options) {
|
|
51
58
|
this.objects = options.objects;
|
|
52
59
|
this.states = options.states;
|
|
@@ -119,7 +126,7 @@ class AdapterAutoUpgradeManager {
|
|
|
119
126
|
objects: this.objects,
|
|
120
127
|
states: this.states,
|
|
121
128
|
params: {},
|
|
122
|
-
processExit: () => void 0
|
|
129
|
+
processExit: /* @__PURE__ */ __name(() => void 0, "processExit")
|
|
123
130
|
});
|
|
124
131
|
await upgrade.upgradeAdapter(repoName, `${name}@${version}`, false, true, false);
|
|
125
132
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/adapterAutoUpgradeManager.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport type { Client as StatesClient } from '@iobroker/db-states-redis';\nimport type { logger } from '@iobroker/js-controller-common';\nimport { Upgrade } from '@iobroker/js-controller-cli';\nimport semver from 'semver';\n\ninterface AdapterAutoUpgradeOptions {\n /** The objects DB client */\n objects: ObjectsClient;\n /** The states DB client */\n states: StatesClient;\n /** Logger which needs to be prefixed */\n logger: ReturnType<typeof logger>;\n /** Prefix for log messages */\n logPrefix: string;\n}\n\ninterface UpgradeAdapterOptions extends ioBroker.RepositoryJsonAdapterContent {\n /** Current active repository */\n repoName: string;\n}\n\ninterface UpgradedAdapter {\n /** Name of the adapter */\n name: string;\n /** Version before upgrade */\n oldVersion: string;\n /** Newly installed version */\n newVersion: string;\n}\n\ninterface UpgradeAdaptersResult {\n /** Adapters which were successfully upgraded */\n upgradedAdapters: UpgradedAdapter[];\n /** Adapters which were failed to upgrade */\n failedAdapters: UpgradedAdapter[];\n}\n\ninterface AdapterUpgradeConfiguration {\n /** Name of the adapter */\n name: string;\n /** Current installed version */\n version: string;\n /** Configured upgrade policy */\n upgradePolicy: ioBroker.AutoUpgradePolicy;\n}\n\nexport class AdapterAutoUpgradeManager {\n private readonly objects: ObjectsClient;\n private readonly states: StatesClient;\n /** Mapping from semver range to range identifier */\n private SEMVER_RANGE_MAPPING = {\n none: '',\n patch: '~',\n minor: '^',\n major: '>',\n } as const;\n /** Prefix for log messages */\n private readonly logPrefix: string;\n /** Logger which needs to be prefixed */\n private logger: ReturnType<typeof logger>;\n\n constructor(options: AdapterAutoUpgradeOptions) {\n this.objects = options.objects;\n this.states = options.states;\n this.logger = options.logger;\n this.logPrefix = options.logPrefix;\n }\n\n /**\n * Checks if auto upgrade is enabled for the current configured repository\n */\n async isAutoUpgradeEnabled(): Promise<boolean> {\n let sysConf: ioBroker.SystemConfigObject | null | undefined;\n\n try {\n sysConf = await this.objects.getObjectAsync('system.config');\n } catch {\n // ignore\n }\n\n if (!sysConf?.common.activeRepo?.length || !sysConf.common.adapterAutoUpgrade) {\n return false;\n }\n\n const activeRepo = sysConf.common.activeRepo[0];\n\n return sysConf.common.adapterAutoUpgrade.repositories[activeRepo];\n }\n\n /**\n * Checks the current `system.repositories` object and checks if one needs to be performed according to the adapter configuration\n */\n async upgradeAdapters(): Promise<UpgradeAdaptersResult> {\n this.logger.info(`${this.logPrefix} Check for available automatic adapter upgrades`);\n const upgradedAdapters: UpgradedAdapter[] = [];\n const failedAdapters: UpgradedAdapter[] = [];\n const repoName = await this.getConfiguredRepositoryName();\n const repoInformation = await this.getRepository(repoName);\n\n const installedAdaptersConfig = await this.getAutoUpdateConfiguration();\n\n for (const adapterConfig of installedAdaptersConfig) {\n const repoAdapterInfo = repoInformation[adapterConfig.name];\n if (!repoAdapterInfo) {\n continue;\n }\n\n if (semver.gte(adapterConfig.version, repoAdapterInfo.version)) {\n continue;\n }\n\n if (\n semver.satisfies(\n repoAdapterInfo.version,\n `${this.SEMVER_RANGE_MAPPING[adapterConfig.upgradePolicy]}${adapterConfig.version}`,\n { includePrerelease: true },\n )\n ) {\n try {\n await this.upgradeAdapter({ ...repoAdapterInfo, repoName });\n upgradedAdapters.push({\n name: repoAdapterInfo.name,\n newVersion: repoAdapterInfo.version,\n oldVersion: adapterConfig.version,\n });\n this.logger.info(\n `${this.logPrefix} Successfully upgraded adapter \"${repoAdapterInfo.name}\" to ${repoAdapterInfo.version}`,\n );\n } catch (e) {\n this.logger.error(\n `${this.logPrefix} Could not upgrade adapter \"${repoAdapterInfo.name}\" to ${repoAdapterInfo.version}: ${e.message}`,\n );\n failedAdapters.push({\n name: repoAdapterInfo.name,\n newVersion: repoAdapterInfo.version,\n oldVersion: adapterConfig.version,\n });\n }\n }\n }\n\n return { upgradedAdapters, failedAdapters };\n }\n\n /**\n * Upgrade specified adapter to given version\n *\n * @param options information of the adapter to install, e.g. version and name, sa well as active repo\n */\n private async upgradeAdapter(options: UpgradeAdapterOptions): Promise<void> {\n const { repoName, name, version } = options;\n\n this.logger.info(`${this.logPrefix} Upgrade adapter \"${name}\" to ${version}`);\n\n const upgrade = new Upgrade({\n objects: this.objects,\n states: this.states,\n params: {},\n processExit: () => undefined,\n });\n\n await upgrade.upgradeAdapter(repoName, `${name}@${version}`, false, true, false);\n }\n\n /**\n * Get the current active repository name\n */\n private async getConfiguredRepositoryName(): Promise<string> {\n const obj = await this.objects.getObjectAsync('system.config');\n\n if (!obj?.common?.activeRepo?.length) {\n throw new Error('Could not find an active repository');\n }\n\n return obj.common.activeRepo[0];\n }\n\n /**\n * Get the repository information for the given repository\n *\n * @param name Name of the repository\n */\n private async getRepository(name: string): Promise<Record<string, ioBroker.RepositoryJsonAdapterContent>> {\n const obj = await this.objects.getObjectAsync('system.repositories');\n\n const jsonContent:\n | (ioBroker.RepositoryJson & {\n _repoInfo?:
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport type { Client as StatesClient } from '@iobroker/db-states-redis';\nimport type { logger } from '@iobroker/js-controller-common';\nimport { Upgrade } from '@iobroker/js-controller-cli';\nimport semver from 'semver';\n\ninterface AdapterAutoUpgradeOptions {\n /** The objects DB client */\n objects: ObjectsClient;\n /** The states DB client */\n states: StatesClient;\n /** Logger which needs to be prefixed */\n logger: ReturnType<typeof logger>;\n /** Prefix for log messages */\n logPrefix: string;\n}\n\ninterface UpgradeAdapterOptions extends ioBroker.RepositoryJsonAdapterContent {\n /** Current active repository */\n repoName: string;\n}\n\ninterface UpgradedAdapter {\n /** Name of the adapter */\n name: string;\n /** Version before upgrade */\n oldVersion: string;\n /** Newly installed version */\n newVersion: string;\n}\n\ninterface UpgradeAdaptersResult {\n /** Adapters which were successfully upgraded */\n upgradedAdapters: UpgradedAdapter[];\n /** Adapters which were failed to upgrade */\n failedAdapters: UpgradedAdapter[];\n}\n\ninterface AdapterUpgradeConfiguration {\n /** Name of the adapter */\n name: string;\n /** Current installed version */\n version: string;\n /** Configured upgrade policy */\n upgradePolicy: ioBroker.AutoUpgradePolicy;\n}\n\n/**\n * Manages automatic upgrades of adapters based on the configured upgrade policy\n */\nexport class AdapterAutoUpgradeManager {\n private readonly objects: ObjectsClient;\n private readonly states: StatesClient;\n /** Mapping from semver range to range identifier */\n private SEMVER_RANGE_MAPPING = {\n none: '',\n patch: '~',\n minor: '^',\n major: '>',\n } as const;\n /** Prefix for log messages */\n private readonly logPrefix: string;\n /** Logger which needs to be prefixed */\n private logger: ReturnType<typeof logger>;\n\n /**\n * @param options The objects/states clients, logger and log prefix\n */\n constructor(options: AdapterAutoUpgradeOptions) {\n this.objects = options.objects;\n this.states = options.states;\n this.logger = options.logger;\n this.logPrefix = options.logPrefix;\n }\n\n /**\n * Checks if auto upgrade is enabled for the current configured repository\n */\n async isAutoUpgradeEnabled(): Promise<boolean> {\n let sysConf: ioBroker.SystemConfigObject | null | undefined;\n\n try {\n sysConf = await this.objects.getObjectAsync('system.config');\n } catch {\n // ignore\n }\n\n if (!sysConf?.common.activeRepo?.length || !sysConf.common.adapterAutoUpgrade) {\n return false;\n }\n\n const activeRepo = sysConf.common.activeRepo[0];\n\n return sysConf.common.adapterAutoUpgrade.repositories[activeRepo];\n }\n\n /**\n * Checks the current `system.repositories` object and checks if one needs to be performed according to the adapter configuration\n */\n async upgradeAdapters(): Promise<UpgradeAdaptersResult> {\n this.logger.info(`${this.logPrefix} Check for available automatic adapter upgrades`);\n const upgradedAdapters: UpgradedAdapter[] = [];\n const failedAdapters: UpgradedAdapter[] = [];\n const repoName = await this.getConfiguredRepositoryName();\n const repoInformation = await this.getRepository(repoName);\n\n const installedAdaptersConfig = await this.getAutoUpdateConfiguration();\n\n for (const adapterConfig of installedAdaptersConfig) {\n const repoAdapterInfo = repoInformation[adapterConfig.name];\n if (!repoAdapterInfo) {\n continue;\n }\n\n if (semver.gte(adapterConfig.version, repoAdapterInfo.version)) {\n continue;\n }\n\n if (\n semver.satisfies(\n repoAdapterInfo.version,\n `${this.SEMVER_RANGE_MAPPING[adapterConfig.upgradePolicy]}${adapterConfig.version}`,\n { includePrerelease: true },\n )\n ) {\n try {\n await this.upgradeAdapter({ ...repoAdapterInfo, repoName });\n upgradedAdapters.push({\n name: repoAdapterInfo.name,\n newVersion: repoAdapterInfo.version,\n oldVersion: adapterConfig.version,\n });\n this.logger.info(\n `${this.logPrefix} Successfully upgraded adapter \"${repoAdapterInfo.name}\" to ${repoAdapterInfo.version}`,\n );\n } catch (e) {\n this.logger.error(\n `${this.logPrefix} Could not upgrade adapter \"${repoAdapterInfo.name}\" to ${repoAdapterInfo.version}: ${e.message}`,\n );\n failedAdapters.push({\n name: repoAdapterInfo.name,\n newVersion: repoAdapterInfo.version,\n oldVersion: adapterConfig.version,\n });\n }\n }\n }\n\n return { upgradedAdapters, failedAdapters };\n }\n\n /**\n * Upgrade specified adapter to given version\n *\n * @param options information of the adapter to install, e.g. version and name, sa well as active repo\n */\n private async upgradeAdapter(options: UpgradeAdapterOptions): Promise<void> {\n const { repoName, name, version } = options;\n\n this.logger.info(`${this.logPrefix} Upgrade adapter \"${name}\" to ${version}`);\n\n const upgrade = new Upgrade({\n objects: this.objects,\n states: this.states,\n params: {},\n processExit: () => undefined,\n });\n\n await upgrade.upgradeAdapter(repoName, `${name}@${version}`, false, true, false);\n }\n\n /**\n * Get the current active repository name\n */\n private async getConfiguredRepositoryName(): Promise<string> {\n const obj = await this.objects.getObjectAsync('system.config');\n\n if (!obj?.common?.activeRepo?.length) {\n throw new Error('Could not find an active repository');\n }\n\n return obj.common.activeRepo[0];\n }\n\n /**\n * Get the repository information for the given repository\n *\n * @param name Name of the repository\n */\n private async getRepository(name: string): Promise<Record<string, ioBroker.RepositoryJsonAdapterContent>> {\n const obj = await this.objects.getObjectAsync('system.repositories');\n\n const jsonContent:\n | (Omit<ioBroker.RepositoryJson, '_repoInfo'> & {\n /** Additional internal repository metadata */\n _repoInfo?: ioBroker.RepoInfo;\n })\n | null\n | undefined = obj?.native?.repositories?.[name]?.json;\n\n if (!jsonContent) {\n throw new Error(`Could not get repository information for \"${name}\"`);\n }\n\n delete jsonContent._repoInfo;\n return jsonContent as Record<string, ioBroker.RepositoryJsonAdapterContent>;\n }\n\n /**\n * Get the auto upgrade configuration of all adapters\n */\n private async getAutoUpdateConfiguration(): Promise<AdapterUpgradeConfiguration[]> {\n const res = await this.objects.getObjectViewAsync('system', 'adapter', {\n startkey: 'system.adapter.',\n endkey: 'system.adapter.\\u9999',\n });\n\n if (!res) {\n throw new Error('Did not get information about installed adapters');\n }\n\n const defaultPolicy = await this.getDefaultUpgradePolicy();\n\n return res.rows\n .filter(\n row =>\n (defaultPolicy && defaultPolicy !== 'none') ||\n (row.value?.common.automaticUpgrade && row.value.common.automaticUpgrade !== 'none'),\n )\n .map(row => {\n return {\n // ts can not infer, that we filtered out falsy row.value entries\n name: row.value.common.name,\n version: row.value.common.version,\n upgradePolicy: row.value.common.automaticUpgrade! || defaultPolicy,\n };\n });\n }\n\n /**\n * Get the default upgrade policy from the system config\n */\n private async getDefaultUpgradePolicy(): Promise<ioBroker.AutoUpgradePolicy | undefined> {\n let sysConf: ioBroker.SystemConfigObject | null | undefined;\n\n try {\n sysConf = await this.objects.getObjectAsync('system.config');\n } catch {\n // ignore\n }\n\n return sysConf?.common.adapterAutoUpgrade?.defaultPolicy;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["semver"]
|
|
7
7
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import http from 'node:http';
|
|
2
2
|
import https from 'node:https';
|
|
3
|
+
import type { Logger } from 'winston';
|
|
3
4
|
import type { Client as ObjectsClient } from '@iobroker/db-objects-redis';
|
|
4
5
|
import type { Client as StatesClient } from '@iobroker/db-states-redis';
|
|
5
|
-
import type { Logger } from 'winston';
|
|
6
6
|
interface Certificates {
|
|
7
7
|
/** Public certificate */
|
|
8
8
|
certPublic: string;
|
|
@@ -39,6 +39,9 @@ interface GetCertificatesParams {
|
|
|
39
39
|
/** Name of the private certificate */
|
|
40
40
|
certPrivateName: string;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Manages the upgrade of a single adapter, including stopping it and serving a web UI for the upgrade progress
|
|
44
|
+
*/
|
|
42
45
|
export declare class AdapterUpgradeManager {
|
|
43
46
|
/** Wait ms until adapter is stopped */
|
|
44
47
|
private readonly STOP_TIMEOUT_MS;
|
|
@@ -52,7 +55,7 @@ export declare class AdapterUpgradeManager {
|
|
|
52
55
|
private readonly response;
|
|
53
56
|
/** Used to stop the stop shutdown timeout */
|
|
54
57
|
private shutdownAbortController?;
|
|
55
|
-
/** Logger to log to file and other transports */
|
|
58
|
+
/** Logger to log to a file and other transports */
|
|
56
59
|
private readonly logger;
|
|
57
60
|
/** The server used for communicating upgrade status */
|
|
58
61
|
private server?;
|
|
@@ -64,9 +67,9 @@ export declare class AdapterUpgradeManager {
|
|
|
64
67
|
private readonly objects;
|
|
65
68
|
/** The states DB client */
|
|
66
69
|
private readonly states;
|
|
67
|
-
/** List of instances
|
|
70
|
+
/** List of instances that have been stopped */
|
|
68
71
|
private stoppedInstances;
|
|
69
|
-
/** If webserver should be started with https */
|
|
72
|
+
/** If a webserver should be started with https */
|
|
70
73
|
private readonly useHttps;
|
|
71
74
|
/** Public certificate name if https is desired */
|
|
72
75
|
private readonly certPublicName?;
|
|
@@ -74,13 +77,16 @@ export declare class AdapterUpgradeManager {
|
|
|
74
77
|
private readonly certPrivateName?;
|
|
75
78
|
/** Port where the webserver should be running */
|
|
76
79
|
private readonly port;
|
|
80
|
+
/**
|
|
81
|
+
* @param options Adapter name, target version, logger and webserver options
|
|
82
|
+
*/
|
|
77
83
|
constructor(options: AdapterUpgradeManagerOptions);
|
|
78
84
|
/**
|
|
79
85
|
* Stops the adapter and returns ids of stopped instances
|
|
80
86
|
*/
|
|
81
87
|
stopAdapter(): Promise<void>;
|
|
82
88
|
/**
|
|
83
|
-
* Start all instances
|
|
89
|
+
* Start all instances that were enabled before the upgrade
|
|
84
90
|
*/
|
|
85
91
|
startAdapter(): Promise<void>;
|
|
86
92
|
/**
|
|
@@ -91,7 +97,7 @@ export declare class AdapterUpgradeManager {
|
|
|
91
97
|
*/
|
|
92
98
|
enableInstances(instances: string[], enabled: boolean): Promise<void>;
|
|
93
99
|
/**
|
|
94
|
-
* Install given version of adapter
|
|
100
|
+
* Install a given version of the adapter
|
|
95
101
|
*/
|
|
96
102
|
performUpgrade(): Promise<void>;
|
|
97
103
|
/**
|
|
@@ -103,7 +109,7 @@ export declare class AdapterUpgradeManager {
|
|
|
103
109
|
*/
|
|
104
110
|
shutdownServer(): void;
|
|
105
111
|
/**
|
|
106
|
-
* Destroy all sockets
|
|
112
|
+
* Destroy all sockets to prevent requests from keeping the server alive
|
|
107
113
|
*/
|
|
108
114
|
destroySockets(): void;
|
|
109
115
|
/**
|
|
@@ -149,11 +155,11 @@ export declare class AdapterUpgradeManager {
|
|
|
149
155
|
*/
|
|
150
156
|
getCertificates(params: GetCertificatesParams): Promise<Certificates>;
|
|
151
157
|
/**
|
|
152
|
-
* Tells the upgrade manager
|
|
158
|
+
* Tells the upgrade manager that the server can be shut down on the next response or on timeout
|
|
153
159
|
*/
|
|
154
160
|
private setFinished;
|
|
155
161
|
/**
|
|
156
|
-
* Start a timeout which starts adapter and shuts down the server if expired
|
|
162
|
+
* Start a timeout which starts the adapter and shuts down the server if expired
|
|
157
163
|
*/
|
|
158
164
|
startShutdownTimeout(): Promise<void>;
|
|
159
165
|
}
|
|
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
9
|
var __export = (target, all) => {
|
|
9
10
|
for (var name in all)
|
|
10
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -31,12 +32,15 @@ __export(adapterUpgradeManager_exports, {
|
|
|
31
32
|
AdapterUpgradeManager: () => AdapterUpgradeManager
|
|
32
33
|
});
|
|
33
34
|
module.exports = __toCommonJS(adapterUpgradeManager_exports);
|
|
34
|
-
var import_js_controller_common = require("@iobroker/js-controller-common");
|
|
35
35
|
var import_node_http = __toESM(require("node:http"), 1);
|
|
36
36
|
var import_node_https = __toESM(require("node:https"), 1);
|
|
37
37
|
var import_promises = require("node:timers/promises");
|
|
38
|
+
var import_js_controller_common = require("@iobroker/js-controller-common");
|
|
38
39
|
var import_js_controller_cli = require("@iobroker/js-controller-cli");
|
|
39
40
|
class AdapterUpgradeManager {
|
|
41
|
+
static {
|
|
42
|
+
__name(this, "AdapterUpgradeManager");
|
|
43
|
+
}
|
|
40
44
|
/** Wait ms until adapter is stopped */
|
|
41
45
|
STOP_TIMEOUT_MS = 3e3;
|
|
42
46
|
/** Wait ms for delivery of final response */
|
|
@@ -53,7 +57,7 @@ class AdapterUpgradeManager {
|
|
|
53
57
|
};
|
|
54
58
|
/** Used to stop the stop shutdown timeout */
|
|
55
59
|
shutdownAbortController;
|
|
56
|
-
/** Logger to log to file and other transports */
|
|
60
|
+
/** Logger to log to a file and other transports */
|
|
57
61
|
logger;
|
|
58
62
|
/** The server used for communicating upgrade status */
|
|
59
63
|
server;
|
|
@@ -65,9 +69,9 @@ class AdapterUpgradeManager {
|
|
|
65
69
|
objects;
|
|
66
70
|
/** The states DB client */
|
|
67
71
|
states;
|
|
68
|
-
/** List of instances
|
|
72
|
+
/** List of instances that have been stopped */
|
|
69
73
|
stoppedInstances = [];
|
|
70
|
-
/** If webserver should be started with https */
|
|
74
|
+
/** If a webserver should be started with https */
|
|
71
75
|
useHttps;
|
|
72
76
|
/** Public certificate name if https is desired */
|
|
73
77
|
certPublicName;
|
|
@@ -75,6 +79,9 @@ class AdapterUpgradeManager {
|
|
|
75
79
|
certPrivateName;
|
|
76
80
|
/** Port where the webserver should be running */
|
|
77
81
|
port;
|
|
82
|
+
/**
|
|
83
|
+
* @param options Adapter name, target version, logger and webserver options
|
|
84
|
+
*/
|
|
78
85
|
constructor(options) {
|
|
79
86
|
this.adapterName = options.adapterName;
|
|
80
87
|
this.version = options.version;
|
|
@@ -97,7 +104,7 @@ class AdapterUpgradeManager {
|
|
|
97
104
|
await (0, import_promises.setTimeout)(this.STOP_TIMEOUT_MS);
|
|
98
105
|
}
|
|
99
106
|
/**
|
|
100
|
-
* Start all instances
|
|
107
|
+
* Start all instances that were enabled before the upgrade
|
|
101
108
|
*/
|
|
102
109
|
async startAdapter() {
|
|
103
110
|
await this.enableInstances(this.stoppedInstances, true);
|
|
@@ -118,16 +125,16 @@ class AdapterUpgradeManager {
|
|
|
118
125
|
from: `system.host.${this.hostname}`,
|
|
119
126
|
ts
|
|
120
127
|
};
|
|
121
|
-
await this.objects.
|
|
128
|
+
await this.objects.extendObject(instance, updatedObj);
|
|
122
129
|
}
|
|
123
130
|
}
|
|
124
131
|
/**
|
|
125
|
-
* Install given version of adapter
|
|
132
|
+
* Install a given version of the adapter
|
|
126
133
|
*/
|
|
127
134
|
async performUpgrade() {
|
|
128
|
-
const processExitHandler = (exitCode) => {
|
|
135
|
+
const processExitHandler = /* @__PURE__ */ __name((exitCode) => {
|
|
129
136
|
this.log(`Upgrade process exited with code: ${exitCode}`, true);
|
|
130
|
-
};
|
|
137
|
+
}, "processExitHandler");
|
|
131
138
|
const upgrade = new import_js_controller_cli.Upgrade({
|
|
132
139
|
objects: this.objects,
|
|
133
140
|
processExit: processExitHandler,
|
|
@@ -176,7 +183,7 @@ class AdapterUpgradeManager {
|
|
|
176
183
|
});
|
|
177
184
|
}
|
|
178
185
|
/**
|
|
179
|
-
* Destroy all sockets
|
|
186
|
+
* Destroy all sockets to prevent requests from keeping the server alive
|
|
180
187
|
*/
|
|
181
188
|
destroySockets() {
|
|
182
189
|
for (const socket of this.sockets) {
|
|
@@ -284,14 +291,14 @@ class AdapterUpgradeManager {
|
|
|
284
291
|
return { certPrivate: certs[certPrivateName], certPublic: certs[certPublicName] };
|
|
285
292
|
}
|
|
286
293
|
/**
|
|
287
|
-
* Tells the upgrade manager
|
|
294
|
+
* Tells the upgrade manager that the server can be shut down on the next response or on timeout
|
|
288
295
|
*/
|
|
289
296
|
async setFinished() {
|
|
290
297
|
this.response.running = false;
|
|
291
298
|
await this.startShutdownTimeout();
|
|
292
299
|
}
|
|
293
300
|
/**
|
|
294
|
-
* Start a timeout which starts adapter and shuts down the server if expired
|
|
301
|
+
* Start a timeout which starts the adapter and shuts down the server if expired
|
|
295
302
|
*/
|
|
296
303
|
async startShutdownTimeout() {
|
|
297
304
|
this.shutdownAbortController = new AbortController();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/adapterUpgradeManager.ts"],
|
|
4
|
-
"sourcesContent": ["import { tools } from '@iobroker/js-controller-common';\nimport http from 'node:http';\nimport https from 'node:https';\nimport type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport type { Client as StatesClient } from '@iobroker/db-states-redis';\nimport { setTimeout as wait } from 'node:timers/promises';\nimport type { Logger } from 'winston';\nimport { Upgrade, type ProcessExitCallback } from '@iobroker/js-controller-cli';\nimport type { Socket } from 'node:net';\nimport type { Duplex } from 'node:stream';\n\ninterface Certificates {\n /** Public certificate */\n certPublic: string;\n /** Private certificate */\n certPrivate: string;\n}\n\ninterface InsecureWebServerParameters {\n /** if https should be used for the webserver */\n useHttps: false;\n /** port of the web server */\n port: number;\n}\n\ntype SecureWebServerParameters = Omit<InsecureWebServerParameters, 'useHttps'> & {\n useHttps: true;\n certPrivateName: string;\n certPublicName: string;\n};\ntype WebServerParameters = InsecureWebServerParameters | SecureWebServerParameters;\n\nexport type AdapterUpgradeManagerOptions = {\n /** Version of adapter to upgrade too */\n version: string;\n /** Name of the adapter to upgrade */\n adapterName: string;\n /** The objects DB client */\n objects: ObjectsClient;\n /** The states DB client */\n states: StatesClient;\n /** A logger instance */\n logger: Logger;\n} & WebServerParameters;\n\ninterface GetCertificatesParams {\n /** Name of the public certificate */\n certPublicName: string;\n /** Name of the private certificate */\n certPrivateName: string;\n}\n\ninterface ServerResponse {\n /** If the update is still running */\n running: boolean;\n stderr: string[];\n stdout: string[];\n /** if installation process succeeded */\n success?: boolean;\n}\n\nexport class AdapterUpgradeManager {\n /** Wait ms until adapter is stopped */\n private readonly STOP_TIMEOUT_MS = 3_000;\n /** Wait ms for delivery of final response */\n private readonly SHUTDOWN_TIMEOUT = 10_000;\n /** Name of the adapter to upgrade */\n private readonly adapterName: string;\n /** Desired adapter version */\n private readonly version: string;\n /** Response send by webserver */\n private readonly response: ServerResponse = {\n running: true,\n stderr: [],\n stdout: [],\n };\n /** Used to stop the stop shutdown timeout */\n private shutdownAbortController?: AbortController;\n /** Logger to log to file and other transports */\n private readonly logger: Logger;\n\n /** The server used for communicating upgrade status */\n private server?: https.Server | http.Server;\n /** All socket connections of the webserver */\n private sockets = new Set<Socket | Duplex>();\n /** Name of the host for logging purposes */\n private readonly hostname = tools.getHostName();\n /** The objects DB client */\n private readonly objects: ObjectsClient;\n /** The states DB client */\n private readonly states: StatesClient;\n /** List of instances which have been stopped */\n private stoppedInstances: string[] = [];\n /** If webserver should be started with https */\n private readonly useHttps: boolean;\n /** Public certificate name if https is desired */\n private readonly certPublicName?: string;\n /** Private certificate name if https is desired */\n private readonly certPrivateName?: string;\n /** Port where the webserver should be running */\n private readonly port: number;\n\n constructor(options: AdapterUpgradeManagerOptions) {\n this.adapterName = options.adapterName;\n this.version = options.version;\n this.logger = options.logger;\n this.objects = options.objects;\n this.states = options.states;\n this.useHttps = options.useHttps;\n this.port = options.port;\n\n if (options.useHttps) {\n this.certPublicName = options.certPublicName;\n this.certPrivateName = options.certPrivateName;\n }\n }\n\n /**\n * Stops the adapter and returns ids of stopped instances\n */\n async stopAdapter(): Promise<void> {\n this.stoppedInstances = await this.getAllEnabledInstances();\n await this.enableInstances(this.stoppedInstances, false);\n await wait(this.STOP_TIMEOUT_MS);\n }\n\n /**\n * Start all instances which were enabled before the upgrade\n */\n async startAdapter(): Promise<void> {\n await this.enableInstances(this.stoppedInstances, true);\n }\n\n /**\n * Start or stop given instances\n *\n * @param instances id of instances which will be stopped\n * @param enabled if enable or disable instances\n */\n async enableInstances(instances: string[], enabled: boolean): Promise<void> {\n const ts = Date.now();\n for (const instance of instances) {\n const updatedObj = {\n common: {\n enabled,\n },\n from: `system.host.${this.hostname}`,\n ts,\n } as Partial<ioBroker.InstanceObject>;\n\n await this.objects.extendObjectAsync(instance, updatedObj);\n }\n }\n\n /**\n * Install given version of adapter\n */\n async performUpgrade(): Promise<void> {\n const processExitHandler: ProcessExitCallback = exitCode => {\n this.log(`Upgrade process exited with code: ${exitCode}`, true);\n };\n\n const upgrade = new Upgrade({\n objects: this.objects,\n processExit: processExitHandler,\n states: this.states,\n params: {},\n });\n\n try {\n await upgrade.upgradeAdapter(undefined, `${this.adapterName}@${this.version}`, true, true, false);\n this.response.success = true;\n this.log(`Successfully upgraded ${this.adapterName} to version ${this.version}`);\n } catch (e) {\n this.log(e.message, true);\n this.response.success = false;\n }\n\n await this.setFinished();\n }\n\n /**\n * Starts the web server for admin communication either secure or insecure\n */\n async startWebServer(): Promise<void> {\n if (this.useHttps && this.certPublicName && this.certPrivateName) {\n await this.startSecureWebServer({\n certPublicName: this.certPublicName,\n certPrivateName: this.certPrivateName,\n port: this.port,\n useHttps: true,\n });\n } else {\n this.startInsecureWebServer({ port: this.port, useHttps: false });\n }\n }\n\n /**\n * Shuts down the server, restarts the adapter\n */\n shutdownServer(): void {\n if (this.shutdownAbortController) {\n this.shutdownAbortController.abort();\n }\n\n if (!this.server) {\n return;\n }\n\n this.destroySockets();\n\n this.server.close(async () => {\n await this.startAdapter();\n this.log('Successfully started adapter');\n });\n }\n\n /**\n * Destroy all sockets, to prevent requests from keeping server alive\n */\n destroySockets(): void {\n for (const socket of this.sockets) {\n socket.destroy();\n this.sockets.delete(socket);\n }\n }\n\n /**\n * This function is called when the webserver receives a message\n *\n * @param req received message\n * @param res server response\n */\n webServerCallback(req: http.IncomingMessage, res: http.ServerResponse): void {\n res.writeHead(200);\n res.end(JSON.stringify(this.response));\n\n if (!this.response.running) {\n this.log('Final information delivered');\n this.shutdownServer();\n }\n }\n\n /**\n * Get all instances of the adapter\n */\n async getAllEnabledInstances(): Promise<string[]> {\n const res = await this.objects.getObjectListAsync({\n startkey: `system.adapter.${this.adapterName}.`,\n endkey: `system.adapter.${this.adapterName}.\\u9999`,\n });\n\n let enabledInstances: string[] = [];\n\n enabledInstances = res.rows\n .filter(row => row.value.common.enabled && this.hostname === row.value.common.host)\n .map(row => row.value._id);\n\n return enabledInstances;\n }\n\n /**\n * Log via logger and provide the logs for the server too\n *\n * @param message the message which will be logged\n * @param error if it is an error\n */\n log(message: string, error = false): void {\n if (error) {\n this.logger.error(`host.${this.hostname} ${message}`);\n this.response.stderr.push(message);\n return;\n }\n\n this.logger.info(`host.${this.hostname} [WEBSERVER_UPGRADE] (${this.adapterName}) ${message}`);\n this.response.stdout.push(message);\n }\n\n /**\n * Start an insecure web server for admin communication\n *\n * @param params Web server configuration\n */\n startInsecureWebServer(params: InsecureWebServerParameters): void {\n const { port } = params;\n\n this.server = http.createServer((req, res) => {\n this.webServerCallback(req, res);\n });\n\n this.monitorSockets(this.server);\n\n this.server.listen(port, () => {\n this.log(`Server is running on http://localhost:${port}`);\n });\n }\n\n /**\n * Start a secure web server for admin communication\n *\n * @param params Web server configuration\n */\n async startSecureWebServer(params: SecureWebServerParameters): Promise<void> {\n const { port, certPublicName, certPrivateName } = params;\n\n const { certPublic, certPrivate } = await this.getCertificates({ certPublicName, certPrivateName });\n\n this.server = https.createServer({ key: certPrivate, cert: certPublic }, (req, res) => {\n this.webServerCallback(req, res);\n });\n\n this.monitorSockets(this.server);\n\n this.server.listen(port, () => {\n this.log(`Server is running on http://localhost:${port}`);\n });\n }\n\n /**\n * Keep track of all existing sockets\n *\n * @param server the webserver\n */\n monitorSockets(server: http.Server | https.Server): void {\n server.on('connection', socket => {\n this.sockets.add(socket);\n\n server.once('close', () => {\n this.sockets.delete(socket);\n });\n });\n }\n\n /**\n * Get certificates from the DB\n *\n * @param params certificate information\n */\n async getCertificates(params: GetCertificatesParams): Promise<Certificates> {\n const { certPublicName, certPrivateName } = params;\n\n const obj = await this.objects.getObjectAsync('system.certificates');\n\n if (!obj) {\n throw new Error('No certificates found');\n }\n\n const certs = obj.native.certificates;\n\n return { certPrivate: certs[certPrivateName], certPublic: certs[certPublicName] };\n }\n\n /**\n * Tells the upgrade manager, that server can be shut down on next response or on timeout\n */\n private async setFinished(): Promise<void> {\n this.response.running = false;\n\n await this.startShutdownTimeout();\n }\n\n /**\n * Start a timeout which starts adapter and shuts down the server if expired\n */\n async startShutdownTimeout(): Promise<void> {\n this.shutdownAbortController = new AbortController();\n try {\n await wait(this.SHUTDOWN_TIMEOUT, null, { signal: this.shutdownAbortController.signal });\n\n this.log('Timeout expired, initializing shutdown');\n this.shutdownServer();\n } catch (e) {\n if (e.code !== 'ABORT_ERR') {\n this.log(e.message, true);\n }\n }\n }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import http from 'node:http';\nimport https from 'node:https';\nimport { setTimeout as wait } from 'node:timers/promises';\nimport type { Socket } from 'node:net';\nimport type { Duplex } from 'node:stream';\nimport type { Logger } from 'winston';\n\nimport { tools } from '@iobroker/js-controller-common';\nimport type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport type { Client as StatesClient } from '@iobroker/db-states-redis';\nimport { Upgrade, type ProcessExitCallback } from '@iobroker/js-controller-cli';\n\ninterface Certificates {\n /** Public certificate */\n certPublic: string;\n /** Private certificate */\n certPrivate: string;\n}\n\ninterface InsecureWebServerParameters {\n /** if https should be used for the webserver */\n useHttps: false;\n /** port of the web server */\n port: number;\n}\n\ntype SecureWebServerParameters = Omit<InsecureWebServerParameters, 'useHttps'> & {\n useHttps: true;\n certPrivateName: string;\n certPublicName: string;\n};\ntype WebServerParameters = InsecureWebServerParameters | SecureWebServerParameters;\n\nexport type AdapterUpgradeManagerOptions = {\n /** Version of adapter to upgrade too */\n version: string;\n /** Name of the adapter to upgrade */\n adapterName: string;\n /** The objects DB client */\n objects: ObjectsClient;\n /** The states DB client */\n states: StatesClient;\n /** A logger instance */\n logger: Logger;\n} & WebServerParameters;\n\ninterface GetCertificatesParams {\n /** Name of the public certificate */\n certPublicName: string;\n /** Name of the private certificate */\n certPrivateName: string;\n}\n\ninterface ServerResponse {\n /** If the update is still running */\n running: boolean;\n stderr: string[];\n stdout: string[];\n /** if the installation process succeeded */\n success?: boolean;\n}\n\n/**\n * Manages the upgrade of a single adapter, including stopping it and serving a web UI for the upgrade progress\n */\nexport class AdapterUpgradeManager {\n /** Wait ms until adapter is stopped */\n private readonly STOP_TIMEOUT_MS = 3_000;\n /** Wait ms for delivery of final response */\n private readonly SHUTDOWN_TIMEOUT = 10_000;\n /** Name of the adapter to upgrade */\n private readonly adapterName: string;\n /** Desired adapter version */\n private readonly version: string;\n /** Response send by webserver */\n private readonly response: ServerResponse = {\n running: true,\n stderr: [],\n stdout: [],\n };\n /** Used to stop the stop shutdown timeout */\n private shutdownAbortController?: AbortController;\n /** Logger to log to a file and other transports */\n private readonly logger: Logger;\n\n /** The server used for communicating upgrade status */\n private server?: https.Server | http.Server;\n /** All socket connections of the webserver */\n private sockets = new Set<Socket | Duplex>();\n /** Name of the host for logging purposes */\n private readonly hostname = tools.getHostName();\n /** The objects DB client */\n private readonly objects: ObjectsClient;\n /** The states DB client */\n private readonly states: StatesClient;\n /** List of instances that have been stopped */\n private stoppedInstances: string[] = [];\n /** If a webserver should be started with https */\n private readonly useHttps: boolean;\n /** Public certificate name if https is desired */\n private readonly certPublicName?: string;\n /** Private certificate name if https is desired */\n private readonly certPrivateName?: string;\n /** Port where the webserver should be running */\n private readonly port: number;\n\n /**\n * @param options Adapter name, target version, logger and webserver options\n */\n constructor(options: AdapterUpgradeManagerOptions) {\n this.adapterName = options.adapterName;\n this.version = options.version;\n this.logger = options.logger;\n this.objects = options.objects;\n this.states = options.states;\n this.useHttps = options.useHttps;\n this.port = options.port;\n\n if (options.useHttps) {\n this.certPublicName = options.certPublicName;\n this.certPrivateName = options.certPrivateName;\n }\n }\n\n /**\n * Stops the adapter and returns ids of stopped instances\n */\n async stopAdapter(): Promise<void> {\n this.stoppedInstances = await this.getAllEnabledInstances();\n await this.enableInstances(this.stoppedInstances, false);\n await wait(this.STOP_TIMEOUT_MS);\n }\n\n /**\n * Start all instances that were enabled before the upgrade\n */\n async startAdapter(): Promise<void> {\n await this.enableInstances(this.stoppedInstances, true);\n }\n\n /**\n * Start or stop given instances\n *\n * @param instances id of instances which will be stopped\n * @param enabled if enable or disable instances\n */\n async enableInstances(instances: string[], enabled: boolean): Promise<void> {\n const ts = Date.now();\n for (const instance of instances) {\n const updatedObj = {\n common: {\n enabled,\n },\n from: `system.host.${this.hostname}`,\n ts,\n } as Partial<ioBroker.InstanceObject>;\n\n await this.objects.extendObject(instance, updatedObj);\n }\n }\n\n /**\n * Install a given version of the adapter\n */\n async performUpgrade(): Promise<void> {\n const processExitHandler: ProcessExitCallback = exitCode => {\n this.log(`Upgrade process exited with code: ${exitCode}`, true);\n };\n\n const upgrade = new Upgrade({\n objects: this.objects,\n processExit: processExitHandler,\n states: this.states,\n params: {},\n });\n\n try {\n await upgrade.upgradeAdapter(undefined, `${this.adapterName}@${this.version}`, true, true, false);\n this.response.success = true;\n this.log(`Successfully upgraded ${this.adapterName} to version ${this.version}`);\n } catch (e) {\n this.log(e.message, true);\n this.response.success = false;\n }\n\n await this.setFinished();\n }\n\n /**\n * Starts the web server for admin communication either secure or insecure\n */\n async startWebServer(): Promise<void> {\n if (this.useHttps && this.certPublicName && this.certPrivateName) {\n await this.startSecureWebServer({\n certPublicName: this.certPublicName,\n certPrivateName: this.certPrivateName,\n port: this.port,\n useHttps: true,\n });\n } else {\n this.startInsecureWebServer({ port: this.port, useHttps: false });\n }\n }\n\n /**\n * Shuts down the server, restarts the adapter\n */\n shutdownServer(): void {\n if (this.shutdownAbortController) {\n this.shutdownAbortController.abort();\n }\n\n if (!this.server) {\n return;\n }\n\n this.destroySockets();\n\n this.server.close(async () => {\n await this.startAdapter();\n this.log('Successfully started adapter');\n });\n }\n\n /**\n * Destroy all sockets to prevent requests from keeping the server alive\n */\n destroySockets(): void {\n for (const socket of this.sockets) {\n socket.destroy();\n this.sockets.delete(socket);\n }\n }\n\n /**\n * This function is called when the webserver receives a message\n *\n * @param req received message\n * @param res server response\n */\n webServerCallback(req: http.IncomingMessage, res: http.ServerResponse): void {\n res.writeHead(200);\n res.end(JSON.stringify(this.response));\n\n if (!this.response.running) {\n this.log('Final information delivered');\n this.shutdownServer();\n }\n }\n\n /**\n * Get all instances of the adapter\n */\n async getAllEnabledInstances(): Promise<string[]> {\n const res = await this.objects.getObjectListAsync({\n startkey: `system.adapter.${this.adapterName}.`,\n endkey: `system.adapter.${this.adapterName}.\\u9999`,\n });\n\n let enabledInstances: string[] = [];\n\n enabledInstances = res.rows\n .filter(row => row.value.common.enabled && this.hostname === row.value.common.host)\n .map(row => row.value._id);\n\n return enabledInstances;\n }\n\n /**\n * Log via logger and provide the logs for the server too\n *\n * @param message the message which will be logged\n * @param error if it is an error\n */\n log(message: string, error = false): void {\n if (error) {\n this.logger.error(`host.${this.hostname} ${message}`);\n this.response.stderr.push(message);\n return;\n }\n\n this.logger.info(`host.${this.hostname} [WEBSERVER_UPGRADE] (${this.adapterName}) ${message}`);\n this.response.stdout.push(message);\n }\n\n /**\n * Start an insecure web server for admin communication\n *\n * @param params Web server configuration\n */\n startInsecureWebServer(params: InsecureWebServerParameters): void {\n const { port } = params;\n\n this.server = http.createServer((req, res) => {\n this.webServerCallback(req, res);\n });\n\n this.monitorSockets(this.server);\n\n this.server.listen(port, () => {\n this.log(`Server is running on http://localhost:${port}`);\n });\n }\n\n /**\n * Start a secure web server for admin communication\n *\n * @param params Web server configuration\n */\n async startSecureWebServer(params: SecureWebServerParameters): Promise<void> {\n const { port, certPublicName, certPrivateName } = params;\n\n const { certPublic, certPrivate } = await this.getCertificates({ certPublicName, certPrivateName });\n\n this.server = https.createServer({ key: certPrivate, cert: certPublic }, (req, res) => {\n this.webServerCallback(req, res);\n });\n\n this.monitorSockets(this.server);\n\n this.server.listen(port, () => {\n this.log(`Server is running on http://localhost:${port}`);\n });\n }\n\n /**\n * Keep track of all existing sockets\n *\n * @param server the webserver\n */\n monitorSockets(server: http.Server | https.Server): void {\n server.on('connection', socket => {\n this.sockets.add(socket);\n\n server.once('close', () => {\n this.sockets.delete(socket);\n });\n });\n }\n\n /**\n * Get certificates from the DB\n *\n * @param params certificate information\n */\n async getCertificates(params: GetCertificatesParams): Promise<Certificates> {\n const { certPublicName, certPrivateName } = params;\n\n const obj = await this.objects.getObjectAsync('system.certificates');\n\n if (!obj) {\n throw new Error('No certificates found');\n }\n\n const certs = obj.native.certificates;\n\n return { certPrivate: certs[certPrivateName], certPublic: certs[certPublicName] };\n }\n\n /**\n * Tells the upgrade manager that the server can be shut down on the next response or on timeout\n */\n private async setFinished(): Promise<void> {\n this.response.running = false;\n\n await this.startShutdownTimeout();\n }\n\n /**\n * Start a timeout which starts the adapter and shuts down the server if expired\n */\n async startShutdownTimeout(): Promise<void> {\n this.shutdownAbortController = new AbortController();\n try {\n await wait(this.SHUTDOWN_TIMEOUT, null, { signal: this.shutdownAbortController.signal });\n\n this.log('Timeout expired, initializing shutdown');\n this.shutdownServer();\n } catch (e) {\n if (e.code !== 'ABORT_ERR') {\n this.log(e.message, true);\n }\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["wait", "http", "https"]
|
|
7
7
|
}
|
|
@@ -9,9 +9,15 @@ interface AdapterVersionBlockedOptions {
|
|
|
9
9
|
/** Name of the adapter */
|
|
10
10
|
adapterName: string;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Checks adapters and their versions against the configured block list
|
|
14
|
+
*/
|
|
12
15
|
export declare class BlocklistManager {
|
|
13
16
|
/** The objects client */
|
|
14
17
|
private readonly objects;
|
|
18
|
+
/**
|
|
19
|
+
* @param options The objects client used to read the block list
|
|
20
|
+
*/
|
|
15
21
|
constructor(options: BlocklistManagerOptions);
|
|
16
22
|
/**
|
|
17
23
|
* Iterates over all instances, disables blocklisted once if enabled
|
|
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
9
|
var __export = (target, all) => {
|
|
9
10
|
for (var name in all)
|
|
10
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -34,8 +35,14 @@ module.exports = __toCommonJS(blocklistManager_exports);
|
|
|
34
35
|
var import_constants = require("@iobroker/js-controller-common-db/constants");
|
|
35
36
|
var import_semver = __toESM(require("semver"), 1);
|
|
36
37
|
class BlocklistManager {
|
|
38
|
+
static {
|
|
39
|
+
__name(this, "BlocklistManager");
|
|
40
|
+
}
|
|
37
41
|
/** The objects client */
|
|
38
42
|
objects;
|
|
43
|
+
/**
|
|
44
|
+
* @param options The objects client used to read the block list
|
|
45
|
+
*/
|
|
39
46
|
constructor(options) {
|
|
40
47
|
this.objects = options.objects;
|
|
41
48
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/blocklistManager.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport {\n HIGHEST_UNICODE_SYMBOL,\n SYSTEM_ADAPTER_PREFIX,\n SYSTEM_CONFIG_ID,\n SYSTEM_REPOSITORIES_ID,\n} from '@iobroker/js-controller-common-db/constants';\nimport semver from 'semver';\n\ninterface BlocklistManagerOptions {\n /** The objects client */\n objects: ObjectsClient;\n}\n\ninterface AdapterVersionBlockedOptions {\n /** The version of the adapter instance */\n version: string;\n /** Name of the adapter */\n adapterName: string;\n}\n\ninterface InternalAdapterVersionBlockedOptions extends AdapterVersionBlockedOptions {\n /** The system repository object */\n systemRepoObj: ioBroker.RepositoryObject;\n /** The system config object */\n systemConfigObj: ioBroker.SystemConfigObject;\n}\n\nexport class BlocklistManager {\n /** The objects client */\n private readonly objects: ObjectsClient;\n\n constructor(options: BlocklistManagerOptions) {\n this.objects = options.objects;\n }\n\n /**\n * Iterates over all instances, disables blocklisted once if enabled\n *\n * @returns A list of disabled instances\n */\n async disableAllBlocklistedInstances(): Promise<ioBroker.InstanceObject[]> {\n /** List of instances which we have disabled */\n const disabledList: ioBroker.InstanceObject[] = [];\n\n const systemRepoObj = await this.objects.getObject(SYSTEM_REPOSITORIES_ID);\n const systemConfigObj = await this.objects.getObject(SYSTEM_CONFIG_ID);\n\n if (!systemConfigObj || !systemRepoObj) {\n return disabledList;\n }\n\n const instancesView = await this.objects.getObjectViewAsync('system', 'instance', {\n startkey: SYSTEM_ADAPTER_PREFIX,\n endkey: SYSTEM_ADAPTER_PREFIX + HIGHEST_UNICODE_SYMBOL,\n });\n\n for (const row of instancesView.rows) {\n const obj = row.value;\n\n if (!obj.common.enabled) {\n continue;\n }\n\n const isBlocked = this.internalIsAdapterVersionBlocked({\n systemConfigObj,\n systemRepoObj,\n adapterName: obj.common.name,\n version: obj.common.version,\n });\n\n if (!isBlocked) {\n continue;\n }\n\n obj.common.enabled = false;\n\n await this.objects.setObject(obj._id, obj);\n disabledList.push(row.value);\n }\n\n return disabledList;\n }\n\n /**\n * Check if version of a specific adapter is blocked\n *\n * @param options adapter version and name information\n * @returns A boolean indicating if the adapter version is blocked\n */\n async isAdapterVersionBlocked(options: AdapterVersionBlockedOptions): Promise<boolean> {\n const systemRepoObj = await this.objects.getObject(SYSTEM_REPOSITORIES_ID);\n const systemConfigObj = await this.objects.getObject(SYSTEM_CONFIG_ID);\n\n if (!systemConfigObj || !systemRepoObj) {\n return false;\n }\n\n return this.internalIsAdapterVersionBlocked({ ...options, systemRepoObj, systemConfigObj });\n }\n\n /**\n * Check if version of a specific adapter is blocked\n *\n * @param options information about adapter, version and cached objects\n * @returns A boolean indicating if the adapter version is blocked\n */\n private internalIsAdapterVersionBlocked(options: InternalAdapterVersionBlockedOptions): boolean {\n const { adapterName, version, systemRepoObj, systemConfigObj } = options;\n\n for (const activeRepoName of systemConfigObj.common.activeRepo) {\n if (!(activeRepoName in systemRepoObj.native.repositories)) {\n return false;\n }\n\n const repo = systemRepoObj.native.repositories[activeRepoName];\n const adapterEntry = repo.json?.[adapterName];\n\n if (!adapterEntry || !('blockedVersions' in adapterEntry)) {\n return false;\n }\n\n for (const blockedVersion of adapterEntry.blockedVersions) {\n if (semver.satisfies(version, blockedVersion, { includePrerelease: true })) {\n return true;\n }\n }\n }\n\n return false;\n }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import type { Client as ObjectsClient } from '@iobroker/db-objects-redis';\nimport {\n HIGHEST_UNICODE_SYMBOL,\n SYSTEM_ADAPTER_PREFIX,\n SYSTEM_CONFIG_ID,\n SYSTEM_REPOSITORIES_ID,\n} from '@iobroker/js-controller-common-db/constants';\nimport semver from 'semver';\n\ninterface BlocklistManagerOptions {\n /** The objects client */\n objects: ObjectsClient;\n}\n\ninterface AdapterVersionBlockedOptions {\n /** The version of the adapter instance */\n version: string;\n /** Name of the adapter */\n adapterName: string;\n}\n\ninterface InternalAdapterVersionBlockedOptions extends AdapterVersionBlockedOptions {\n /** The system repository object */\n systemRepoObj: ioBroker.RepositoryObject;\n /** The system config object */\n systemConfigObj: ioBroker.SystemConfigObject;\n}\n\n/**\n * Checks adapters and their versions against the configured block list\n */\nexport class BlocklistManager {\n /** The objects client */\n private readonly objects: ObjectsClient;\n\n /**\n * @param options The objects client used to read the block list\n */\n constructor(options: BlocklistManagerOptions) {\n this.objects = options.objects;\n }\n\n /**\n * Iterates over all instances, disables blocklisted once if enabled\n *\n * @returns A list of disabled instances\n */\n async disableAllBlocklistedInstances(): Promise<ioBroker.InstanceObject[]> {\n /** List of instances which we have disabled */\n const disabledList: ioBroker.InstanceObject[] = [];\n\n const systemRepoObj = await this.objects.getObject(SYSTEM_REPOSITORIES_ID);\n const systemConfigObj = await this.objects.getObject(SYSTEM_CONFIG_ID);\n\n if (!systemConfigObj || !systemRepoObj) {\n return disabledList;\n }\n\n const instancesView = await this.objects.getObjectViewAsync('system', 'instance', {\n startkey: SYSTEM_ADAPTER_PREFIX,\n endkey: SYSTEM_ADAPTER_PREFIX + HIGHEST_UNICODE_SYMBOL,\n });\n\n for (const row of instancesView.rows) {\n const obj = row.value;\n\n if (!obj.common.enabled) {\n continue;\n }\n\n const isBlocked = this.internalIsAdapterVersionBlocked({\n systemConfigObj,\n systemRepoObj,\n adapterName: obj.common.name,\n version: obj.common.version,\n });\n\n if (!isBlocked) {\n continue;\n }\n\n obj.common.enabled = false;\n\n await this.objects.setObject(obj._id, obj);\n disabledList.push(row.value);\n }\n\n return disabledList;\n }\n\n /**\n * Check if version of a specific adapter is blocked\n *\n * @param options adapter version and name information\n * @returns A boolean indicating if the adapter version is blocked\n */\n async isAdapterVersionBlocked(options: AdapterVersionBlockedOptions): Promise<boolean> {\n const systemRepoObj = await this.objects.getObject(SYSTEM_REPOSITORIES_ID);\n const systemConfigObj = await this.objects.getObject(SYSTEM_CONFIG_ID);\n\n if (!systemConfigObj || !systemRepoObj) {\n return false;\n }\n\n return this.internalIsAdapterVersionBlocked({ ...options, systemRepoObj, systemConfigObj });\n }\n\n /**\n * Check if version of a specific adapter is blocked\n *\n * @param options information about adapter, version and cached objects\n * @returns A boolean indicating if the adapter version is blocked\n */\n private internalIsAdapterVersionBlocked(options: InternalAdapterVersionBlockedOptions): boolean {\n const { adapterName, version, systemRepoObj, systemConfigObj } = options;\n\n for (const activeRepoName of systemConfigObj.common.activeRepo) {\n if (!(activeRepoName in systemRepoObj.native.repositories)) {\n return false;\n }\n\n const repo = systemRepoObj.native.repositories[activeRepoName];\n const adapterEntry = repo.json?.[adapterName];\n\n if (!adapterEntry || !('blockedVersions' in adapterEntry)) {\n return false;\n }\n\n for (const blockedVersion of adapterEntry.blockedVersions) {\n if (semver.satisfies(version, blockedVersion, { includePrerelease: true })) {\n return true;\n }\n }\n }\n\n return false;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA;;;;;AAAA,uBAKO;AACP,oBAAmB;AAwBb,MAAO,iBAAgB;EA9B7B,OA8B6B;;;;EAER;;;;EAKjB,YAAY,SAAgC;AACxC,SAAK,UAAU,QAAQ;EAC3B;;;;;;EAOA,MAAM,iCAA8B;AAEhC,UAAM,eAA0C,CAAA;AAEhD,UAAM,gBAAgB,MAAM,KAAK,QAAQ,UAAU,uCAAsB;AACzE,UAAM,kBAAkB,MAAM,KAAK,QAAQ,UAAU,iCAAgB;AAErE,QAAI,CAAC,mBAAmB,CAAC,eAAe;AACpC,aAAO;IACX;AAEA,UAAM,gBAAgB,MAAM,KAAK,QAAQ,mBAAmB,UAAU,YAAY;MAC9E,UAAU;MACV,QAAQ,yCAAwB;KACnC;AAED,eAAW,OAAO,cAAc,MAAM;AAClC,YAAM,MAAM,IAAI;AAEhB,UAAI,CAAC,IAAI,OAAO,SAAS;AACrB;MACJ;AAEA,YAAM,YAAY,KAAK,gCAAgC;QACnD;QACA;QACA,aAAa,IAAI,OAAO;QACxB,SAAS,IAAI,OAAO;OACvB;AAED,UAAI,CAAC,WAAW;AACZ;MACJ;AAEA,UAAI,OAAO,UAAU;AAErB,YAAM,KAAK,QAAQ,UAAU,IAAI,KAAK,GAAG;AACzC,mBAAa,KAAK,IAAI,KAAK;IAC/B;AAEA,WAAO;EACX;;;;;;;EAQA,MAAM,wBAAwB,SAAqC;AAC/D,UAAM,gBAAgB,MAAM,KAAK,QAAQ,UAAU,uCAAsB;AACzE,UAAM,kBAAkB,MAAM,KAAK,QAAQ,UAAU,iCAAgB;AAErE,QAAI,CAAC,mBAAmB,CAAC,eAAe;AACpC,aAAO;IACX;AAEA,WAAO,KAAK,gCAAgC,EAAE,GAAG,SAAS,eAAe,gBAAe,CAAE;EAC9F;;;;;;;EAQQ,gCAAgC,SAA6C;AACjF,UAAM,EAAE,aAAa,SAAS,eAAe,gBAAe,IAAK;AAEjE,eAAW,kBAAkB,gBAAgB,OAAO,YAAY;AAC5D,UAAI,EAAE,kBAAkB,cAAc,OAAO,eAAe;AACxD,eAAO;MACX;AAEA,YAAM,OAAO,cAAc,OAAO,aAAa,cAAc;AAC7D,YAAM,eAAe,KAAK,OAAO,WAAW;AAE5C,UAAI,CAAC,gBAAgB,EAAE,qBAAqB,eAAe;AACvD,eAAO;MACX;AAEA,iBAAW,kBAAkB,aAAa,iBAAiB;AACvD,YAAI,cAAAA,QAAO,UAAU,SAAS,gBAAgB,EAAE,mBAAmB,KAAI,CAAE,GAAG;AACxE,iBAAO;QACX;MACJ;IACJ;AAEA,WAAO;EACX;;",
|
|
6
6
|
"names": ["semver"]
|
|
7
7
|
}
|
|
@@ -38,12 +38,27 @@ export declare class MHServer {
|
|
|
38
38
|
private server;
|
|
39
39
|
private initTimer;
|
|
40
40
|
private stopped;
|
|
41
|
+
/**
|
|
42
|
+
* @param hostname The name of this host
|
|
43
|
+
* @param logger The logger instance
|
|
44
|
+
* @param config The ioBroker configuration
|
|
45
|
+
* @param info Multihost information such as the number of hosts
|
|
46
|
+
* @param secret Shared secret used for authentication, or false if authentication is disabled
|
|
47
|
+
*/
|
|
41
48
|
constructor(hostname: string, logger: InternalLogger, config: ioBroker.IoBrokerJson, info: MHInfo, secret: string | false);
|
|
42
49
|
private send;
|
|
43
50
|
private checkAuthList;
|
|
44
51
|
private sha;
|
|
45
52
|
private process;
|
|
53
|
+
/**
|
|
54
|
+
* Start the multihost discovery server and (re)initialize it
|
|
55
|
+
*/
|
|
46
56
|
init(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Stop the multihost server and release the socket
|
|
59
|
+
*
|
|
60
|
+
* @param callback Called once the server has been closed
|
|
61
|
+
*/
|
|
47
62
|
close(callback?: () => void): void;
|
|
48
63
|
}
|
|
49
64
|
export {};
|
|
@@ -5,6 +5,7 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
8
9
|
var __export = (target, all) => {
|
|
9
10
|
for (var name in all)
|
|
10
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -37,6 +38,9 @@ var import_js_controller_common = require("@iobroker/js-controller-common");
|
|
|
37
38
|
const PORT = 50005;
|
|
38
39
|
const MULTICAST_ADDR = "239.255.255.250";
|
|
39
40
|
class MHServer {
|
|
41
|
+
static {
|
|
42
|
+
__name(this, "MHServer");
|
|
43
|
+
}
|
|
40
44
|
count = 0;
|
|
41
45
|
buffer = {};
|
|
42
46
|
lastFrame = {};
|
|
@@ -49,6 +53,13 @@ class MHServer {
|
|
|
49
53
|
server = null;
|
|
50
54
|
initTimer = null;
|
|
51
55
|
stopped = false;
|
|
56
|
+
/**
|
|
57
|
+
* @param hostname The name of this host
|
|
58
|
+
* @param logger The logger instance
|
|
59
|
+
* @param config The ioBroker configuration
|
|
60
|
+
* @param info Multihost information such as the number of hosts
|
|
61
|
+
* @param secret Shared secret used for authentication, or false if authentication is disabled
|
|
62
|
+
*/
|
|
52
63
|
constructor(hostname, logger, config, info, secret) {
|
|
53
64
|
this.hostname = hostname;
|
|
54
65
|
this.config = config;
|
|
@@ -166,6 +177,9 @@ class MHServer {
|
|
|
166
177
|
break;
|
|
167
178
|
}
|
|
168
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Start the multihost discovery server and (re)initialize it
|
|
182
|
+
*/
|
|
169
183
|
init() {
|
|
170
184
|
this.stopped = false;
|
|
171
185
|
if (this.initTimer) {
|
|
@@ -219,7 +233,7 @@ class MHServer {
|
|
|
219
233
|
const data = JSON.parse(this.buffer[id]);
|
|
220
234
|
this.buffer[id] = "";
|
|
221
235
|
if (data) {
|
|
222
|
-
this.process(data, rinfo);
|
|
236
|
+
this.process(data, rinfo).catch((e) => this.logger.error(`Cannot process multihost message: ${e.message}`));
|
|
223
237
|
}
|
|
224
238
|
} catch {
|
|
225
239
|
}
|
|
@@ -237,6 +251,11 @@ class MHServer {
|
|
|
237
251
|
});
|
|
238
252
|
this.server.bind(PORT);
|
|
239
253
|
}
|
|
254
|
+
/**
|
|
255
|
+
* Stop the multihost server and release the socket
|
|
256
|
+
*
|
|
257
|
+
* @param callback Called once the server has been closed
|
|
258
|
+
*/
|
|
240
259
|
close(callback) {
|
|
241
260
|
this.stopped = true;
|
|
242
261
|
if (this.initTimer) {
|