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 _botJoinedAtMs: number = 0;
private _recentMessageKeyTimestamps: Map<string, number> = new Map(); private _recentMessageKeyTimestamps: Map<string, number> = new Map();
private _scanIntervalId: ReturnType<typeof setInterval> | null = null; private _scanIntervalId: ReturnType<typeof setInterval> | null = null;
private _consecutiveOpenFailures: number = 0;
private static readonly _MAX_OPEN_FAILURES = 5;
constructor( constructor(
page: Page, page: Page,
@ -116,10 +118,10 @@ export class ChatProcedure {
* In authenticated Teams, the chat panel may already be open (meeting loads * In authenticated Teams, the chat panel may already be open (meeting loads
* from a chat thread). Clicking again would TOGGLE it closed. * from a chat thread). Clicking again would TOGGLE it closed.
*/ */
private async _openChatPanel(): Promise<void> { private async _openChatPanel(): Promise<boolean> {
if (await this._isChatPanelOpen()) { if (await this._isChatPanelOpen()) {
this._logger.info('Chat panel already open - skipping toggle'); this._logger.info('Chat panel already open - skipping toggle');
return; return true;
} }
const chatButtonSelectors = [ const chatButtonSelectors = [
@ -131,20 +133,15 @@ export class ChatProcedure {
'button[aria-label*="Meeting chat" i]', '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 maxAttempts = 12;
const pollIntervalMs = 2000; const pollIntervalMs = 2000;
for (let attempt = 1; attempt <= maxAttempts; attempt++) { for (let attempt = 1; attempt <= maxAttempts; attempt++) {
// Check first - a previous click might have opened it by now
if (await this._isChatPanelOpen()) { if (await this._isChatPanelOpen()) {
this._logger.info(`Chat panel detected as open (attempt ${attempt})`); 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; let clicked = false;
for (const selector of chatButtonSelectors) { for (const selector of chatButtonSelectors) {
try { try {
@ -163,14 +160,11 @@ export class ChatProcedure {
} }
if (clicked) { if (clicked) {
// Wait for panel to render after click
await this._page.waitForTimeout(2500); await this._page.waitForTimeout(2500);
if (await this._isChatPanelOpen()) { if (await this._isChatPanelOpen()) {
this._logger.info('Chat panel opened successfully'); 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'); this._logger.info('Chat button clicked but panel not detected yet, waiting before next attempt');
await this._page.waitForTimeout(pollIntervalMs); await this._page.waitForTimeout(pollIntervalMs);
} else { } else {
@ -182,6 +176,7 @@ export class ChatProcedure {
} }
this._logger.warn('Could not open chat panel after polling - chat will not work'); 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; if (!this._isSubscribed || !this._page) return;
try { try {
if (!(await this._isChatPanelOpen())) { 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'); 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); await this._page.waitForTimeout(1000);
} else {
this._consecutiveOpenFailures = 0;
} }
const knownKeys = Array.from(this._recentMessageKeyTimestamps.keys()); const knownKeys = Array.from(this._recentMessageKeyTimestamps.keys());