This commit is contained in:
ValueOn AG 2026-03-31 13:31:02 +02:00
parent 96819abcf2
commit 89e6d442ab

View file

@ -24,6 +24,8 @@ export class ChatProcedure {
private _botJoinedAtMs: number = 0;
private _recentMessageKeyTimestamps: Map<string, number> = new Map();
private _scanIntervalId: ReturnType<typeof setInterval> | null = null;
private _consecutiveOpenFailures: number = 0;
private static readonly _MAX_OPEN_FAILURES = 5;
constructor(
page: Page,
@ -116,10 +118,10 @@ export class ChatProcedure {
* In authenticated Teams, the chat panel may already be open (meeting loads
* from a chat thread). Clicking again would TOGGLE it closed.
*/
private async _openChatPanel(): Promise<void> {
private async _openChatPanel(): Promise<boolean> {
if (await this._isChatPanelOpen()) {
this._logger.info('Chat panel already open - skipping toggle');
return;
return true;
}
const chatButtonSelectors = [
@ -131,20 +133,15 @@ export class ChatProcedure {
'button[aria-label*="Meeting chat" i]',
];
// Poll for the chat button (toolbar renders asynchronously after join).
// IMPORTANT: click only ONCE per attempt, then wait for the panel to appear.
// Multiple clicks on the same toggle button would open/close/open/close.
const maxAttempts = 12;
const pollIntervalMs = 2000;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
// Check first - a previous click might have opened it by now
if (await this._isChatPanelOpen()) {
this._logger.info(`Chat panel detected as open (attempt ${attempt})`);
return;
return true;
}
// Try to find and click the button (only one click per attempt)
let clicked = false;
for (const selector of chatButtonSelectors) {
try {
@ -163,14 +160,11 @@ export class ChatProcedure {
}
if (clicked) {
// Wait for panel to render after click
await this._page.waitForTimeout(2500);
if (await this._isChatPanelOpen()) {
this._logger.info('Chat panel opened successfully');
return;
return true;
}
// Panel didn't open despite click - DON'T click again immediately,
// wait for next attempt cycle (avoids toggle oscillation)
this._logger.info('Chat button clicked but panel not detected yet, waiting before next attempt');
await this._page.waitForTimeout(pollIntervalMs);
} else {
@ -182,6 +176,7 @@ export class ChatProcedure {
}
this._logger.warn('Could not open chat panel after polling - chat will not work');
return false;
}
/**
@ -445,9 +440,31 @@ export class ChatProcedure {
if (!this._isSubscribed || !this._page) return;
try {
if (!(await this._isChatPanelOpen())) {
if (this._consecutiveOpenFailures >= ChatProcedure._MAX_OPEN_FAILURES) {
this._logger.warn(
`Chat panel failed to open ${this._consecutiveOpenFailures} consecutive times - ` +
'stopping periodic chat scan to avoid log noise',
);
if (this._scanIntervalId) {
clearInterval(this._scanIntervalId);
this._scanIntervalId = null;
}
return;
}
this._logger.info('Chat panel closed, reopening');
await this._openChatPanel();
const opened = await this._openChatPanel();
if (opened) {
this._consecutiveOpenFailures = 0;
} else {
this._consecutiveOpenFailures++;
this._logger.info(
`Chat reopen failed (${this._consecutiveOpenFailures}/${ChatProcedure._MAX_OPEN_FAILURES} before giving up)`,
);
return;
}
await this._page.waitForTimeout(1000);
} else {
this._consecutiveOpenFailures = 0;
}
const knownKeys = Array.from(this._recentMessageKeyTimestamps.keys());