зеркало из
1
0
Форкнуть 0

[bugfix] Safely subscribe to on stateChanged events to prevent related events from failing if listeners throw an error (#5165)

* Safely subscribe to on stateChanged events to prevent related events from failing if listeners throw an error

* Ensure anonymous function can be subscribed and unsubscribed

* Resolve linter issues

* Update unsubscription calls

* Resolve linter issues

* Update CallErrorTarget

* Change files
This commit is contained in:
edwardlee-msft 2024-09-18 15:20:11 -07:00 коммит произвёл GitHub
Родитель bbc495137c
Коммит 39e34af998
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 52 добавлений и 10 удалений

Просмотреть файл

@ -0,0 +1,9 @@
{
"type": "patch",
"area": "fix",
"workstream": "CallSubscriber",
"comment": "Safely subscribe to on stateChanged events to prevent related events from failing if listeners throw an error",
"packageName": "@azure/communication-react",
"email": "edwardlee@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -0,0 +1,9 @@
{
"type": "patch",
"area": "fix",
"workstream": "CallSubscriber",
"comment": "Safely subscribe to on stateChanged events to prevent related events from failing if listeners throw an error",
"packageName": "@azure/communication-react",
"email": "edwardlee@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -123,12 +123,25 @@ export class CallSubscriber {
this.subscribe();
}
private _safeSubscribeInitCaptionSubscriber = (): void => {
this._safeSubscribe(this.initCaptionSubscriber);
};
private _safeSubscribeInitTeamsMeetingConference = (): void => {
this._safeSubscribe(this.initTeamsMeetingConference);
};
/* @conditional-compile-remove(local-recording-notification) */
private _safeSubscribeInitLocalRecordingNotificationSubscriber = (): void => {
this._safeSubscribe(this.initLocalRecordingNotificationSubscriber);
};
private subscribe = (): void => {
this._call.on('stateChanged', this.stateChanged);
this._call.on('stateChanged', this.initCaptionSubscriber);
this._call.on('stateChanged', this.initTeamsMeetingConference);
this._call.on('stateChanged', this._safeSubscribeInitCaptionSubscriber);
this._call.on('stateChanged', this._safeSubscribeInitTeamsMeetingConference);
/* @conditional-compile-remove(local-recording-notification) */
this._call.on('stateChanged', this.initLocalRecordingNotificationSubscriber);
this._call.on('stateChanged', this._safeSubscribeInitLocalRecordingNotificationSubscriber);
this._call.on('idChanged', this.idChanged);
this._call.on('isScreenSharingOnChanged', this.isScreenSharingOnChanged);
this._call.on('remoteParticipantsUpdated', this.remoteParticipantsUpdated);
@ -166,11 +179,10 @@ export class CallSubscriber {
public unsubscribe = (): void => {
this._call.off('stateChanged', this.stateChanged);
this._call.off('stateChanged', this.initCaptionSubscriber);
this._call.off('stateChanged', this._safeSubscribeInitCaptionSubscriber);
this._call.off('stateChanged', this._safeSubscribeInitTeamsMeetingConference);
/* @conditional-compile-remove(local-recording-notification) */
this._call.off('stateChanged', this.initLocalRecordingNotificationSubscriber);
this._call.off('stateChanged', this.initTeamsMeetingConference);
this._call.off('stateChanged', this._safeSubscribeInitLocalRecordingNotificationSubscriber);
this._call.off('idChanged', this.idChanged);
this._call.off('isScreenSharingOnChanged', this.isScreenSharingOnChanged);
this._call.off('remoteParticipantsUpdated', this.remoteParticipantsUpdated);
@ -218,6 +230,18 @@ export class CallSubscriber {
this._breakoutRoomsSubscriber.unsubscribe();
};
// This is a helper function to safely call subscriber functions. This is needed in order to prevent events
// with the same event type from failing to fire due to a subscriber throwing an error upon subscription.
// Wrap your listeners with this helper function if your listener can fail due to initialization or fail
// during a function call. This will prevent other events using the same event type from failing to fire.
private _safeSubscribe(subscriber: () => void): void {
try {
subscriber();
} catch (e) {
this._context.teeErrorToState(e as Error, 'Call.on');
}
}
private addParticipantListener(participant: RemoteParticipant): void {
const participantKey = toFlatCommunicationIdentifier(participant.identifier);
this._participantSubscribers.get(participantKey)?.unsubscribe();
@ -248,7 +272,7 @@ export class CallSubscriber {
this._context,
this._call.feature(Features.Captions)
);
this._call.off('stateChanged', this.initCaptionSubscriber);
this._call.off('stateChanged', this._safeSubscribeInitCaptionSubscriber);
}
};
@ -260,7 +284,7 @@ export class CallSubscriber {
.then((teamsMeetingConferenceDetails) => {
this._context.setTeamsMeetingConference(this._callIdRef.callId, teamsMeetingConferenceDetails);
});
this._call.off('stateChanged', this.initTeamsMeetingConference);
this._call.off('stateChanged', this._safeSubscribeInitTeamsMeetingConference);
}
};
@ -274,7 +298,7 @@ export class CallSubscriber {
this._context,
this._call.feature(Features.LocalRecording)
);
this._call.off('stateChanged', this.initLocalRecordingNotificationSubscriber);
this._call.off('stateChanged', this._safeSubscribeInitLocalRecordingNotificationSubscriber);
}
};