polfan-server-js-client 0.2.92 → 0.2.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/workspace.xml +31 -14
- package/build/index.cjs.js +209 -106
- package/build/index.cjs.js.map +1 -1
- package/build/index.umd.js +1 -1
- package/build/index.umd.js.map +1 -1
- package/build/types/state-tracker/TopicHistoryWindow.d.ts +4 -0
- package/build/types/types/src/schemes/commands/GetMessages.d.ts +1 -0
- package/package.json +1 -1
- package/src/state-tracker/TopicHistoryWindow.ts +50 -1
- package/src/types/src/schemes/commands/GetMessages.ts +1 -0
- package/tests/history-window.test.ts +84 -1
|
@@ -67,9 +67,11 @@ export declare abstract class TraversableRemoteCollection<ItemT, EventMapT exten
|
|
|
67
67
|
resetToLatest(): Promise<void>;
|
|
68
68
|
fetchPrevious(): Promise<void>;
|
|
69
69
|
fetchNext(): Promise<void>;
|
|
70
|
+
jumpTo(id: string): Promise<void>;
|
|
70
71
|
protected abstract fetchLatestItems(): Promise<ItemT[]>;
|
|
71
72
|
protected abstract fetchItemsBefore(): Promise<ItemT[] | null>;
|
|
72
73
|
protected abstract fetchItemsAfter(): Promise<ItemT[] | null>;
|
|
74
|
+
protected abstract fetchItemsAround(id: string): Promise<ItemT[] | null>;
|
|
73
75
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
74
76
|
protected refreshFetchedState(): Promise<void>;
|
|
75
77
|
protected addItems(newItems: ItemT[], to: 'head' | 'tail'): void;
|
|
@@ -100,12 +102,14 @@ export declare class TopicHistoryWindow extends TraversableRemoteCollection<Mess
|
|
|
100
102
|
resetToLatest(): Promise<void>;
|
|
101
103
|
fetchNext(): Promise<void>;
|
|
102
104
|
fetchPrevious(): Promise<void>;
|
|
105
|
+
jumpTo(id: string): Promise<void>;
|
|
103
106
|
/**
|
|
104
107
|
* For internal use.
|
|
105
108
|
* @internal
|
|
106
109
|
*/
|
|
107
110
|
_updateMessageReference(refTopic: Topic): void;
|
|
108
111
|
protected fetchItemsAfter(): Promise<Message[] | null>;
|
|
112
|
+
protected fetchItemsAround(id: string): Promise<Message[] | null>;
|
|
109
113
|
protected fetchItemsBefore(): Promise<Message[] | null>;
|
|
110
114
|
protected fetchLatestItems(): Promise<Message[]>;
|
|
111
115
|
private getTopic;
|
package/package.json
CHANGED
|
@@ -202,12 +202,40 @@ export abstract class TraversableRemoteCollection<
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
public async jumpTo(id: string): Promise<void> {
|
|
206
|
+
if (this.internalState.ongoing || this._items.has(id)) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let result: ItemT[] | null;
|
|
211
|
+
const originalState = this.state;
|
|
212
|
+
this.internalState.ongoing = WindowState.PAST;
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
result = await this.fetchItemsAround(id);
|
|
216
|
+
this.internalState.lastFetchCount = result ? result.length : 0;
|
|
217
|
+
} finally {
|
|
218
|
+
this.internalState.ongoing = undefined;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (!result) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
this._items.deleteAll(); // Directly call deleteAll to prevent event emit.
|
|
226
|
+
this.addItems(result, 'tail');
|
|
227
|
+
this.internalState.current = WindowState.PAST;
|
|
228
|
+
this.emitChangeWithDiff(true, originalState);
|
|
229
|
+
}
|
|
230
|
+
|
|
205
231
|
protected abstract fetchLatestItems(): Promise<ItemT[]>;
|
|
206
232
|
|
|
207
233
|
protected abstract fetchItemsBefore(): Promise<ItemT[] | null>;
|
|
208
234
|
|
|
209
235
|
protected abstract fetchItemsAfter(): Promise<ItemT[] | null>;
|
|
210
236
|
|
|
237
|
+
protected abstract fetchItemsAround(id: string): Promise<ItemT[] | null>;
|
|
238
|
+
|
|
211
239
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
212
240
|
|
|
213
241
|
protected async refreshFetchedState(): Promise<void> {
|
|
@@ -334,6 +362,13 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<
|
|
|
334
362
|
return super.fetchPrevious();
|
|
335
363
|
}
|
|
336
364
|
|
|
365
|
+
public async jumpTo(id: string): Promise<void> {
|
|
366
|
+
if (this.internalState.traverseLock) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
return super.jumpTo(id);
|
|
370
|
+
}
|
|
371
|
+
|
|
337
372
|
/**
|
|
338
373
|
* For internal use.
|
|
339
374
|
* @internal
|
|
@@ -368,6 +403,20 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<
|
|
|
368
403
|
return result.data.messages;
|
|
369
404
|
}
|
|
370
405
|
|
|
406
|
+
protected async fetchItemsAround(id: string): Promise<Message[] | null> {
|
|
407
|
+
const result = await this.tracker.client.send('GetMessages', {
|
|
408
|
+
location: {roomId: this.roomId, topicId: this.topicId},
|
|
409
|
+
around: id,
|
|
410
|
+
limit: this.internalState.fetchLimit,
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
if (result.error) {
|
|
414
|
+
throw new Error(`Cannot fetch messages: ${result.error.message}`);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return result.data.messages;
|
|
418
|
+
}
|
|
419
|
+
|
|
371
420
|
protected async fetchItemsBefore(): Promise<Message[] | null> {
|
|
372
421
|
const beforeId = this.getAt(0)?.id;
|
|
373
422
|
|
|
@@ -446,4 +495,4 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<
|
|
|
446
495
|
this.eventTarget.emit('reftopicsdeleted', refTopicIds);
|
|
447
496
|
}
|
|
448
497
|
}
|
|
449
|
-
}
|
|
498
|
+
}
|
|
@@ -18,12 +18,32 @@ const messages: SimpleMessage[] = [
|
|
|
18
18
|
];
|
|
19
19
|
|
|
20
20
|
class TestableHistoryWindow extends TraversableRemoteCollection<SimpleMessage> {
|
|
21
|
+
declare protected internalState: TraversableRemoteCollection<SimpleMessage>['internalState'] & {
|
|
22
|
+
traverseLock: boolean,
|
|
23
|
+
};
|
|
24
|
+
|
|
21
25
|
public createMirror(): TraversableRemoteCollection<SimpleMessage> {
|
|
22
26
|
throw new Error('Method not implemented.');
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
public constructor() {
|
|
26
30
|
super('id');
|
|
31
|
+
this.internalState.traverseLock = false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public async setTraverseLock(lock: boolean): Promise<void> {
|
|
35
|
+
this.internalState.traverseLock = lock;
|
|
36
|
+
|
|
37
|
+
if (lock && (this.state !== WindowState.LIVE && this.state !== WindowState.LATEST)) {
|
|
38
|
+
await super.resetToLatest();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public async jumpTo(id: string): Promise<void> {
|
|
43
|
+
if (this.internalState.traverseLock) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
return super.jumpTo(id);
|
|
27
47
|
}
|
|
28
48
|
|
|
29
49
|
public simulateNewMessageReceived(): void {
|
|
@@ -49,6 +69,18 @@ class TestableHistoryWindow extends TraversableRemoteCollection<SimpleMessage> {
|
|
|
49
69
|
return messages.slice(after + 1, after + 4);
|
|
50
70
|
}
|
|
51
71
|
|
|
72
|
+
protected async fetchItemsAround(id: string): Promise<SimpleMessage[] | null> {
|
|
73
|
+
const numericId = parseInt(id, 10);
|
|
74
|
+
const item = messages.find(m => m.id === numericId);
|
|
75
|
+
if (!item) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const index = messages.indexOf(item);
|
|
79
|
+
const start = Math.max(0, index - Math.floor(this.fetchLimit / 2));
|
|
80
|
+
const end = Math.min(messages.length, index + Math.ceil(this.fetchLimit / 2));
|
|
81
|
+
return messages.slice(start, end);
|
|
82
|
+
}
|
|
83
|
+
|
|
52
84
|
protected async fetchItemsBefore(): Promise<SimpleMessage[]> {
|
|
53
85
|
const before = this.getAt(0)?.id;
|
|
54
86
|
if (before === undefined) {
|
|
@@ -177,6 +209,57 @@ test('history window - reset to latest', async () => {
|
|
|
177
209
|
[7,8,9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
178
210
|
});
|
|
179
211
|
|
|
212
|
+
test('history window - jump to message', async () => {
|
|
213
|
+
const window = new TestableHistoryWindow();
|
|
214
|
+
window.limit = 5;
|
|
215
|
+
window.fetchLimit = 3;
|
|
216
|
+
|
|
217
|
+
await window.resetToLatest(); // [7,8,9]
|
|
218
|
+
await window.jumpTo('2'); // [1,2,3]
|
|
219
|
+
|
|
220
|
+
expect(window.state).toEqual(WindowState.PAST);
|
|
221
|
+
expect(window.items).toHaveLength(3);
|
|
222
|
+
[1,2,3].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test('history window - jump to message already in window', async () => {
|
|
226
|
+
const window = new TestableHistoryWindow();
|
|
227
|
+
window.limit = 5;
|
|
228
|
+
window.fetchLimit = 3;
|
|
229
|
+
|
|
230
|
+
await window.resetToLatest(); // [7,8,9]
|
|
231
|
+
const itemsBeforeJump = window.items;
|
|
232
|
+
await window.jumpTo('8');
|
|
233
|
+
|
|
234
|
+
expect(window.items).toEqual(itemsBeforeJump);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
test('history window - jump to non-existent message', async () => {
|
|
238
|
+
const window = new TestableHistoryWindow();
|
|
239
|
+
window.limit = 5;
|
|
240
|
+
window.fetchLimit = 3;
|
|
241
|
+
|
|
242
|
+
await window.resetToLatest(); // [7,8,9]
|
|
243
|
+
const itemsBeforeJump = window.items;
|
|
244
|
+
await window.jumpTo('99'); // non-existent
|
|
245
|
+
|
|
246
|
+
expect(window.items).toEqual(itemsBeforeJump);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('history window - jump to message with traverseLock', async () => {
|
|
250
|
+
const window = new TestableHistoryWindow();
|
|
251
|
+
window.limit = 5;
|
|
252
|
+
window.fetchLimit = 3;
|
|
253
|
+
|
|
254
|
+
await window.resetToLatest(); // [7,8,9]
|
|
255
|
+
await window.setTraverseLock(true);
|
|
256
|
+
await window.jumpTo('2');
|
|
257
|
+
|
|
258
|
+
expect(window.state).toEqual(WindowState.LATEST);
|
|
259
|
+
expect(window.items).toHaveLength(3);
|
|
260
|
+
[7,8,9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
261
|
+
});
|
|
262
|
+
|
|
180
263
|
test('history window - trim messages window to limit', async () => {
|
|
181
264
|
const window = new TestableHistoryWindow();
|
|
182
265
|
window.limit = 5;
|
|
@@ -284,4 +367,4 @@ test('history window - high/low watermark limit (retainRatio)', async () => {
|
|
|
284
367
|
expect(window.items).toHaveLength(3);
|
|
285
368
|
[7, 8, 9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
286
369
|
expect(window.state).toEqual(WindowState.LATEST);
|
|
287
|
-
});
|
|
370
|
+
});
|