Skip to content

Commit 2ecb0d9

Browse files
committed
feat: Enhance reconnect #350
1 parent b587742 commit 2ecb0d9

File tree

3 files changed

+81
-40
lines changed

3 files changed

+81
-40
lines changed

projects/stream-chat-angular/src/lib/channel.service.spec.ts

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,35 +1702,35 @@ describe('ChannelService', () => {
17021702

17031703
it('should reset state after connection recovered', async () => {
17041704
await init();
1705-
spyOn(service, 'init');
1706-
spyOn(service, 'reset');
1705+
mockChatClient.queryChannels.calls.reset();
17071706
events$.next({ eventType: 'connection.recovered' } as ClientEvent);
17081707

1709-
expect(service.init).toHaveBeenCalledWith(
1710-
service['filters']!,
1711-
service['sort'],
1712-
service['options'],
1713-
service['shouldSetActiveChannel']
1708+
expect(mockChatClient.queryChannels).toHaveBeenCalledWith(
1709+
jasmine.any(Object),
1710+
jasmine.any(Object),
1711+
jasmine.any(Object)
17141712
);
1715-
1716-
expect(service.reset).toHaveBeenCalledWith();
17171713
});
17181714

17191715
it(`shouldn't do duplicate state reset after connection recovered`, async () => {
17201716
await init();
1721-
spyOn(service, 'init');
1722-
spyOn(service, 'reset');
1717+
mockChatClient.queryChannels.calls.reset();
17231718
events$.next({ eventType: 'connection.recovered' } as ClientEvent);
17241719
events$.next({ eventType: 'connection.recovered' } as ClientEvent);
17251720

1726-
expect(service.init).toHaveBeenCalledOnceWith(
1727-
service['filters']!,
1728-
service['sort'],
1729-
service['options'],
1730-
service['shouldSetActiveChannel']
1731-
);
1721+
expect(mockChatClient.queryChannels).toHaveBeenCalledTimes(1);
1722+
});
17321723

1733-
expect(service.reset).toHaveBeenCalledOnceWith();
1724+
it('should reset pagination options after reconnect', async () => {
1725+
await init(undefined, undefined, { offset: 20 });
1726+
mockChatClient.queryChannels.calls.reset();
1727+
events$.next({ eventType: 'connection.recovered' } as ClientEvent);
1728+
1729+
expect(mockChatClient.queryChannels).toHaveBeenCalledWith(
1730+
jasmine.any(Object),
1731+
jasmine.any(Object),
1732+
jasmine.objectContaining({ offset: 0 })
1733+
);
17341734
});
17351735

17361736
it('should load message into state', async () => {
@@ -1823,4 +1823,39 @@ describe('ChannelService', () => {
18231823
'Error removing message pin'
18241824
);
18251825
});
1826+
1827+
it('should deselect active channel if active channel is not present after state reconnect', fakeAsync(async () => {
1828+
await init();
1829+
let activeChannel!: Channel<DefaultStreamChatGenerics>;
1830+
service.activeChannel$.subscribe((c) => (activeChannel = c!));
1831+
let channels!: Channel<DefaultStreamChatGenerics>[];
1832+
service.channels$.subscribe((c) => (channels = c!));
1833+
channels = channels.filter((c) => c.id !== activeChannel.id);
1834+
const spy = jasmine.createSpy();
1835+
service.activeChannel$.subscribe(spy);
1836+
spy.calls.reset();
1837+
mockChatClient.queryChannels.and.resolveTo(channels);
1838+
spyOn(service, 'deselectActiveChannel').and.callThrough();
1839+
events$.next({ eventType: 'connection.recovered' } as ClientEvent);
1840+
tick();
1841+
1842+
expect(spy).toHaveBeenCalledWith(undefined);
1843+
expect(service.deselectActiveChannel).toHaveBeenCalledWith();
1844+
}));
1845+
1846+
it(`shouldn't deselect active channel if active channel is present after state reconnect`, fakeAsync(async () => {
1847+
await init();
1848+
let channels!: Channel<DefaultStreamChatGenerics>[];
1849+
service.channels$.subscribe((c) => (channels = c!));
1850+
const spy = jasmine.createSpy();
1851+
service.activeChannel$.subscribe(spy);
1852+
spy.calls.reset();
1853+
mockChatClient.queryChannels.and.resolveTo(channels);
1854+
spyOn(service, 'deselectActiveChannel').and.callThrough();
1855+
events$.next({ eventType: 'connection.recovered' } as ClientEvent);
1856+
tick();
1857+
1858+
expect(spy).not.toHaveBeenCalled();
1859+
expect(service.deselectActiveChannel).not.toHaveBeenCalled();
1860+
}));
18261861
});

projects/stream-chat-angular/src/lib/channel.service.thread.spec.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TestBed } from '@angular/core/testing';
1+
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
22
import { Subject } from 'rxjs';
33
import { first } from 'rxjs/operators';
44
import {
@@ -225,18 +225,19 @@ describe('ChannelService - threads', () => {
225225
expect(activeParentMessageSpy).toHaveBeenCalledWith(undefined);
226226
});
227227

228-
it('should deselect thread after reconnect', async () => {
228+
it('should deselect thread after reconnect', fakeAsync(async () => {
229229
await init();
230230
let parentMessage!: StreamMessage;
231231
service.activeChannelMessages$.subscribe((m) => (parentMessage = m[0]));
232232
await service.setAsActiveParentMessage(parentMessage);
233233
const spy = jasmine.createSpy();
234234
service.activeParentMessage$.subscribe(spy);
235235
spy.calls.reset();
236-
connectionState$.next('online');
236+
events$.next({ eventType: 'connection.recovered' } as ClientEvent);
237+
tick();
237238

238239
expect(spy).toHaveBeenCalledWith(undefined);
239-
});
240+
}));
240241

241242
it('should not add readBy field to messages', async () => {
242243
await init();

projects/stream-chat-angular/src/lib/channel.service.ts

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ReplaySubject,
77
Subscription,
88
} from 'rxjs';
9-
import { filter, first, map, shareReplay } from 'rxjs/operators';
9+
import { first, map, shareReplay } from 'rxjs/operators';
1010
import {
1111
Attachment,
1212
Channel,
@@ -359,12 +359,6 @@ export class ChannelService<
359359
this.messageToQuote$ = this.messageToQuoteSubject.asObservable();
360360
this.jumpToMessage$ = this.jumpToMessageSubject.asObservable();
361361

362-
this.chatClientService.connectionState$
363-
.pipe(filter((s) => s === 'online'))
364-
.subscribe(() => {
365-
void this.setAsActiveParentMessage(undefined);
366-
});
367-
368362
this.usersTypingInChannel$ =
369363
this.usersTypingInChannelSubject.asObservable();
370364
this.usersTypingInThread$ = this.usersTypingInThreadSubject.asObservable();
@@ -956,14 +950,13 @@ export class ChannelService<
956950
return;
957951
}
958952
this.isStateRecoveryInProgress = true;
959-
this.reset();
960953
try {
961-
await this.init(
962-
this.filters!,
963-
this.sort,
964-
this.options,
965-
this.shouldSetActiveChannel
966-
);
954+
if (this.options) {
955+
this.options.offset = 0;
956+
}
957+
await this.queryChannels(false, true);
958+
// Thread messages are not refetched so active thread gets deselected to avoid displaying stale messages
959+
void this.setAsActiveParentMessage(undefined);
967960
this.isStateRecoveryInProgress = false;
968961
} catch {
969962
this.isStateRecoveryInProgress = false;
@@ -1247,23 +1240,35 @@ export class ChannelService<
12471240
this.activeChannelSubscriptions = [];
12481241
}
12491242

1250-
private async queryChannels(shouldSetActiveChannel: boolean) {
1243+
private async queryChannels(
1244+
shouldSetActiveChannel: boolean,
1245+
recoverState = false
1246+
) {
12511247
try {
12521248
const channels = await this.chatClientService.chatClient.queryChannels(
12531249
this.filters!,
1254-
this.sort,
1250+
this.sort || {},
12551251
this.options
12561252
);
12571253
channels.forEach((c) => this.watchForChannelEvents(c));
1258-
const prevChannels = this.channelsSubject.getValue() || [];
1254+
const prevChannels = recoverState
1255+
? []
1256+
: this.channelsSubject.getValue() || [];
12591257
this.channelsSubject.next([...prevChannels, ...channels]);
1258+
const currentActiveChannel = this.activeChannelSubject.getValue();
12601259
if (
12611260
channels.length > 0 &&
1262-
!this.activeChannelSubject.getValue() &&
1261+
!currentActiveChannel &&
12631262
shouldSetActiveChannel
12641263
) {
12651264
this.setAsActiveChannel(channels[0]);
12661265
}
1266+
if (
1267+
recoverState &&
1268+
!channels.find((c) => c.cid === currentActiveChannel?.cid)
1269+
) {
1270+
this.deselectActiveChannel();
1271+
}
12671272
this.hasMoreChannelsSubject.next(channels.length >= this.options!.limit!);
12681273
return channels;
12691274
} catch (error) {

0 commit comments

Comments
 (0)