@iobroker/js-controller-cli 8.0.0-alpha.1-20260921-e5941ca8a → 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/lib/setup/setupInstall.d.ts +15 -0
- package/build/cjs/lib/setup/setupInstall.js +70 -0
- package/build/cjs/lib/setup/setupInstall.js.map +2 -2
- package/build/esm/lib/setup/setupInstall.d.ts +15 -0
- package/build/esm/lib/setup/setupInstall.d.ts.map +1 -1
- package/build/esm/lib/setup/setupInstall.js +81 -0
- package/build/esm/lib/setup/setupInstall.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -211,6 +211,21 @@ export declare class Install {
|
|
|
211
211
|
* @param instance e.g. 1, if undefined deletes all instances
|
|
212
212
|
*/
|
|
213
213
|
deleteInstance(adapter: string, instance?: number): Promise<void | EXIT_CODES.CANNOT_DELETE_DEPENDENCY>;
|
|
214
|
+
/**
|
|
215
|
+
* Free all exclusive resources (serial ports, TCP/UDP ports, ...) the given instance(s) had registered.
|
|
216
|
+
*
|
|
217
|
+
* This is needed because an instance can be deleted via the CLI while a js-controller is not running: it
|
|
218
|
+
* cannot notice that the instance object disappeared, so its `system.host.<host>.usedResources.<type>`
|
|
219
|
+
* states would keep listing the resources of an instance that no longer exists.
|
|
220
|
+
*
|
|
221
|
+
* Hosts that are running are deliberately skipped. Such a host cleans its own registry up when it sees the
|
|
222
|
+
* instance object being deleted, and it holds the registry in memory: it rewrites the state from that copy
|
|
223
|
+
* on its next change, which would silently undo a write made here.
|
|
224
|
+
*
|
|
225
|
+
* @param adapter adapter name, e.g. "mqtt"
|
|
226
|
+
* @param instance instance number; if undefined, all instances of the adapter are freed
|
|
227
|
+
*/
|
|
228
|
+
private _freeUsedResources;
|
|
214
229
|
/**
|
|
215
230
|
* Remove all node modules that has been installed by this instance
|
|
216
231
|
*
|
|
@@ -1143,6 +1143,7 @@ class Install {
|
|
|
1143
1143
|
await this._deleteAdapterFiles(adapter, metaFilesToDelete);
|
|
1144
1144
|
await this._deleteAdapterObjects(knownObjectIDs);
|
|
1145
1145
|
await this._deleteAdapterStates(knownStateIDs);
|
|
1146
|
+
await this._freeUsedResources(adapter);
|
|
1146
1147
|
if (this.params.custom) {
|
|
1147
1148
|
await this._removeCustomFromObjects([...instances, adapter]);
|
|
1148
1149
|
}
|
|
@@ -1176,10 +1177,79 @@ class Install {
|
|
|
1176
1177
|
await this._enumerateAdapterDocs(knownObjectIDs, adapter, instance);
|
|
1177
1178
|
await this._deleteAdapterObjects(knownObjectIDs);
|
|
1178
1179
|
await this._deleteAdapterStates(knownStateIDs);
|
|
1180
|
+
await this._freeUsedResources(adapter, instance);
|
|
1179
1181
|
if (this.params.custom) {
|
|
1180
1182
|
await this._removeCustomFromObjects([`${adapter}.${instance}`]);
|
|
1181
1183
|
}
|
|
1182
1184
|
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Free all exclusive resources (serial ports, TCP/UDP ports, ...) the given instance(s) had registered.
|
|
1187
|
+
*
|
|
1188
|
+
* This is needed because an instance can be deleted via the CLI while a js-controller is not running: it
|
|
1189
|
+
* cannot notice that the instance object disappeared, so its `system.host.<host>.usedResources.<type>`
|
|
1190
|
+
* states would keep listing the resources of an instance that no longer exists.
|
|
1191
|
+
*
|
|
1192
|
+
* Hosts that are running are deliberately skipped. Such a host cleans its own registry up when it sees the
|
|
1193
|
+
* instance object being deleted, and it holds the registry in memory: it rewrites the state from that copy
|
|
1194
|
+
* on its next change, which would silently undo a write made here.
|
|
1195
|
+
*
|
|
1196
|
+
* @param adapter adapter name, e.g. "mqtt"
|
|
1197
|
+
* @param instance instance number; if undefined, all instances of the adapter are freed
|
|
1198
|
+
*/
|
|
1199
|
+
async _freeUsedResources(adapter, instance) {
|
|
1200
|
+
const matches = /* @__PURE__ */ __name((namespace) => instance !== void 0 ? namespace === `${adapter}.${instance}` : namespace.startsWith(`${adapter}.`), "matches");
|
|
1201
|
+
let keys;
|
|
1202
|
+
try {
|
|
1203
|
+
keys = await this.states.getKeys("system.host.*.usedResources.*");
|
|
1204
|
+
} catch (e) {
|
|
1205
|
+
console.warn(`Cannot read the used resources registry: ${e.message}`);
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
if (!keys?.length) {
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
const hostPrefix = "system.host.";
|
|
1212
|
+
const registryMarker = ".usedResources.";
|
|
1213
|
+
const hostIsRunning = /* @__PURE__ */ new Map();
|
|
1214
|
+
for (const id of keys) {
|
|
1215
|
+
const markerIndex = id.lastIndexOf(registryMarker);
|
|
1216
|
+
if (!id.startsWith(hostPrefix) || markerIndex <= hostPrefix.length) {
|
|
1217
|
+
continue;
|
|
1218
|
+
}
|
|
1219
|
+
const host = id.substring(hostPrefix.length, markerIndex);
|
|
1220
|
+
let isRunning = hostIsRunning.get(host);
|
|
1221
|
+
if (isRunning === void 0) {
|
|
1222
|
+
try {
|
|
1223
|
+
const aliveState = await this.states.getState(`${hostPrefix}${host}.alive`);
|
|
1224
|
+
isRunning = aliveState?.val === true;
|
|
1225
|
+
} catch (e) {
|
|
1226
|
+
console.warn(`Cannot check whether host "${host}" is running: ${e.message}`);
|
|
1227
|
+
isRunning = true;
|
|
1228
|
+
}
|
|
1229
|
+
hostIsRunning.set(host, isRunning);
|
|
1230
|
+
}
|
|
1231
|
+
if (isRunning) {
|
|
1232
|
+
continue;
|
|
1233
|
+
}
|
|
1234
|
+
try {
|
|
1235
|
+
const state = await this.states.getState(id);
|
|
1236
|
+
if (!state || typeof state.val !== "string" || !state.val) {
|
|
1237
|
+
continue;
|
|
1238
|
+
}
|
|
1239
|
+
const parsed = JSON.parse(state.val);
|
|
1240
|
+
if (!Array.isArray(parsed)) {
|
|
1241
|
+
continue;
|
|
1242
|
+
}
|
|
1243
|
+
const original = parsed;
|
|
1244
|
+
const filtered = original.filter((entry) => typeof entry?.instance !== "string" || !matches(entry.instance));
|
|
1245
|
+
if (filtered.length !== original.length) {
|
|
1246
|
+
await this.states.setStateAsync(id, { val: JSON.stringify(filtered), ack: true });
|
|
1247
|
+
}
|
|
1248
|
+
} catch (e) {
|
|
1249
|
+
console.warn(`Cannot free the used resources in "${id}": ${e.message}`);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1183
1253
|
/**
|
|
1184
1254
|
* Remove all node modules that has been installed by this instance
|
|
1185
1255
|
*
|