diff --git a/src/services/notifications.service.ts b/src/services/notifications.service.ts index be33b067f7..8e6fcddd16 100644 --- a/src/services/notifications.service.ts +++ b/src/services/notifications.service.ts @@ -19,25 +19,54 @@ import { export class NotificationsService implements NotificationsServiceAbstraction { private signalrConnection: signalR.HubConnection; private url: string; + private connected = false; + private inited = false; + private reconnectTimer: any = null; constructor(private userService: UserService, private tokenService: TokenService, private syncService: SyncService, private appIdService: AppIdService, private apiService: ApiService) { } async init(environmentService: EnvironmentService): Promise { + this.inited = false; this.url = 'https://notifications.bitwarden.com'; if (environmentService.notificationsUrl != null) { this.url = environmentService.notificationsUrl; } else if (environmentService.baseUrl != null) { this.url = environmentService.baseUrl + '/notifications'; } - this.reconnect(); + + if (this.signalrConnection != null) { + this.signalrConnection.off('ReceiveMessage'); + await this.signalrConnection.stop(); + this.connected = false; + this.signalrConnection = null; + } + + this.signalrConnection = new signalR.HubConnectionBuilder() + .withUrl(this.url + '/hub', { + accessTokenFactory: () => this.tokenService.getToken(), + }) + // .configureLogging(signalR.LogLevel.Information) + .build(); + + this.signalrConnection.on('ReceiveMessage', async (data: any) => { + await this.processNotification(new NotificationResponse(data)); + }); + this.signalrConnection.onclose(() => { + this.connected = false; + this.reconnect(); + }); + this.inited = true; + if (await this.userService.isAuthenticated()) { + await this.connect(); + } } async updateConnection(): Promise { try { if (await this.userService.isAuthenticated()) { - await this.signalrConnection.start(); + await this.connect(); } else { await this.signalrConnection.stop(); } @@ -79,30 +108,37 @@ export class NotificationsService implements NotificationsServiceAbstraction { case NotificationType.SyncOrgKeys: await this.apiService.refreshIdentityToken(); await this.syncService.fullSync(true); - // Now reconnect to join the new org groups - await this.reconnect(); + // Stop so a reconnect can be made + await this.signalrConnection.stop(); break; default: break; } } + private async connect() { + await this.signalrConnection.start(); + this.connected = true; + } + private async reconnect() { - if (this.signalrConnection != null) { - await this.signalrConnection.stop(); - this.signalrConnection = null; + if (this.reconnectTimer != null) { + clearTimeout(this.reconnectTimer); + this.reconnectTimer = null; + } + const authed = await this.userService.isAuthenticated(); + if (this.connected || !this.inited || !authed) { + return; } - this.signalrConnection = new signalR.HubConnectionBuilder() - .withUrl(this.url + '/hub', { - accessTokenFactory: () => this.tokenService.getToken(), - }) - // .configureLogging(signalR.LogLevel.Information) - .build(); + try { + await this.connect(); + } catch { } - this.signalrConnection.on('ReceiveMessage', async (data: any) => { - await this.processNotification(new NotificationResponse(data)); - }); - await this.updateConnection(); + if (!this.connected) { + this.reconnectTimer = setTimeout(() => { + this.reconnect(); + }, 120000); + } } }