Skip to content

Commit 72e34be

Browse files
authored
[fix]: Prevent multiple publishes of alias states if subscribed more than once (#2757)
* Adde letsencrypt shim * exported session so adapters can use it like before after ESM port * prevent double publish * added test * make the le shim true instead of null * move stop in progress check up * rm test log * fix path on cmdExec * fix paths to iobroker.js
1 parent 8e069e4 commit 72e34be

File tree

4 files changed

+42
-12
lines changed

4 files changed

+42
-12
lines changed

packages/adapter/src/lib/adapter/adapter.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10969,11 +10969,22 @@ export class AdapterClass extends EventEmitter {
1096910969
}
1097010970
}
1097110971
}
10972-
} else if (this.adapterReady && this.aliases.has(id)) {
10972+
} else if (!this._stopInProgress && this.adapterReady && this.aliases.has(id)) {
1097310973
// If adapter is ready and for this ID exist some alias links
1097410974
const alias = this.aliases.get(id);
10975-
alias!.targets.forEach(target => {
10975+
/** Prevent multiple publishes if multiple pattern contain this alias id */
10976+
const uniqueTargets = new Set<string>();
10977+
10978+
for (const target of alias!.targets) {
10979+
const targetId = target.id;
10980+
if (uniqueTargets.has(targetId)) {
10981+
continue;
10982+
}
10983+
10984+
uniqueTargets.add(targetId);
10985+
1097610986
const source = alias!.source!;
10987+
1097710988
const aState = state
1097810989
? tools.formatAliasValue({
1097910990
sourceCommon: source,
@@ -10982,21 +10993,19 @@ export class AdapterClass extends EventEmitter {
1098210993
logger: this._logger,
1098310994
logNamespace: this.namespaceLog,
1098410995
sourceId: id,
10985-
targetId: target.id
10996+
targetId
1098610997
})
1098710998
: null;
1098810999

10989-
const targetId = target.id;
10990-
10991-
if (!this._stopInProgress && (aState || !state)) {
11000+
if (aState || !state) {
1099211001
if (typeof this._options.stateChange === 'function') {
1099311002
this._options.stateChange(targetId, aState);
1099411003
} else {
1099511004
// emit 'stateChange' event instantly
1099611005
setImmediate(() => this.emit('stateChange', targetId, aState));
1099711006
}
1099811007
}
10999-
});
11008+
}
1100011009
}
1100111010
},
1100211011
changeUser: (id, state) => {

packages/common/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ export * as constants from '@/lib/common/constants.js';
88
export { createAdapterStore as session } from '@/lib/common/session.js';
99

1010
/** This is a backward compatibility shim, if all adapters are on adapter-core 2.6.11 or 3.1.4 remove this */
11-
export const letsencrypt = null;
11+
export const letsencrypt = true;

packages/controller/src/main.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1996,7 +1996,7 @@ async function processMessage(msg: ioBroker.SendableMessage): Promise<null | voi
19961996
break;
19971997

19981998
case 'cmdExec': {
1999-
const mainFile = path.join(thisDir, '..', `${tools.appName.toLowerCase()}.js`);
1999+
const mainFile = path.join(tools.getControllerDir(), `${tools.appName.toLowerCase()}.js`);
20002000
const args = [...getDefaultNodeArgs(mainFile), mainFile];
20012001
if (!msg.message.data || typeof msg.message.data !== 'string') {
20022002
logger.warn(
@@ -3436,7 +3436,7 @@ function installAdapters(): void {
34363436
);
34373437
}
34383438

3439-
const mainFile = path.join(thisDir, '..', `${tools.appName.toLowerCase()}.js`);
3439+
const mainFile = path.join(tools.getControllerDir(), `${tools.appName.toLowerCase()}.js`);
34403440
const installArgs = [];
34413441
const installOptions = { windowsHide: true };
34423442
if (!task.rebuild && task.installedFrom && proc.downloadRetry < 3) {
@@ -3543,7 +3543,7 @@ function installAdapters(): void {
35433543
});
35443544
child.on('error', err => {
35453545
logger.error(
3546-
`${hostLogPrefix} Cannot execute "${thisDir}/${tools.appName.toLowerCase()}.js ${commandScope} ${name}: ${
3546+
`${hostLogPrefix} Cannot execute "${tools.getControllerDir()}/${tools.appName.toLowerCase()}.js ${commandScope} ${name}: ${
35473547
err.message
35483548
}`
35493549
);
@@ -3554,7 +3554,7 @@ function installAdapters(): void {
35543554
});
35553555
} catch (err) {
35563556
logger.error(
3557-
`${hostLogPrefix} Cannot execute "${thisDir}/${tools.appName.toLowerCase()}.js ${commandScope} ${name}: ${err}`
3557+
`${hostLogPrefix} Cannot execute "${tools.getControllerDir()}/${tools.appName.toLowerCase()}.js ${commandScope} ${name}: ${err}`
35583558
);
35593559
setTimeout(() => {
35603560
installQueue.shift();

packages/controller/test/lib/testAliases.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { TestContext } from '../_Types.js';
22
import type { Client as ObjectsInRedisClient } from '@iobroker/db-objects-redis';
33
import { PERMISSIONS } from './permissions.js';
4+
import { setTimeout as wait } from 'node:timers/promises';
45

56
async function prepareGroupsAndUsers(objects: ObjectsInRedisClient): Promise<void> {
67
await objects.setObject('system.group.userC', {
@@ -492,6 +493,26 @@ export function register(it: Mocha.TestFunction, expect: Chai.ExpectStatic, cont
492493
});
493494
}).timeout(3_000);
494495

496+
// Avoid Issue 2753
497+
it(testName + 'Test subscribe alias multiple times should only publish once', async () => {
498+
let noTriggered = 0;
499+
500+
context.onAdapterStateChanged = (id, state) => {
501+
if (id === gAliasID) {
502+
expect(state).to.be.ok;
503+
noTriggered++;
504+
}
505+
};
506+
507+
await context.adapter.subscribeForeignStatesAsync(gAliasID);
508+
await context.adapter.subscribeForeignStatesAsync(gAliasID);
509+
510+
await context.states.setState(gid, 10);
511+
await wait(500);
512+
513+
expect(noTriggered).to.equal(1);
514+
}).timeout(3_000);
515+
495516
it(testName + 'Test negative subscribe aliases regex', done => {
496517
const parts = gAliasID.split('.');
497518
parts.pop();

0 commit comments

Comments
 (0)