polfan-server-js-client 0.1.994 → 0.1.996
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.
|
@@ -2,9 +2,24 @@ import { Message, MessageReference } from "../types/src";
|
|
|
2
2
|
import { ChatStateTracker } from "./ChatStateTracker";
|
|
3
3
|
import { ObservableIndexedObjectCollection } from "../IndexedObjectCollection";
|
|
4
4
|
export declare enum WindowState {
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The latest messages (those received live) are available in the history window, history has not been fetched.
|
|
7
|
+
*/
|
|
8
|
+
LIVE = 0,
|
|
9
|
+
/**
|
|
10
|
+
* The latest messages has been fetched and are available in the history window.
|
|
11
|
+
*/
|
|
6
12
|
LATEST = 1,
|
|
7
|
-
|
|
13
|
+
/**
|
|
14
|
+
* The historical messages have been fetched and are available in the history window.
|
|
15
|
+
* Latest messages are not available and will not be available.
|
|
16
|
+
*/
|
|
17
|
+
PAST = 2,
|
|
18
|
+
/**
|
|
19
|
+
* The oldest messages have been fetched and are available in the history window.
|
|
20
|
+
* Next attempts to fetch previous messages will result with no-op.
|
|
21
|
+
*/
|
|
22
|
+
OLDEST = 3
|
|
8
23
|
}
|
|
9
24
|
export declare abstract class TraversableRemoteCollection<T> extends ObservableIndexedObjectCollection<T> {
|
|
10
25
|
/**
|
|
@@ -25,9 +40,9 @@ export declare abstract class TraversableRemoteCollection<T> extends ObservableI
|
|
|
25
40
|
protected abstract fetchItemsBefore(): Promise<T[] | null>;
|
|
26
41
|
protected abstract fetchItemsAfter(): Promise<T[] | null>;
|
|
27
42
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
28
|
-
protected
|
|
43
|
+
protected refreshFetchedState(): Promise<void>;
|
|
44
|
+
protected addItems(newItems: T[], to: 'head' | 'tail'): void;
|
|
29
45
|
private throwIfFetchingInProgress;
|
|
30
|
-
private addItems;
|
|
31
46
|
/**
|
|
32
47
|
* Return array with messages of count that matching limit.
|
|
33
48
|
*/
|
package/package.json
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
|
-
import {Message, MessageReference, NewMessage,
|
|
1
|
+
import {Message, MessageReference, NewMessage, Session, Topic} from "../types/src";
|
|
2
2
|
import {ChatStateTracker} from "./ChatStateTracker";
|
|
3
3
|
import {ObservableIndexedObjectCollection} from "../IndexedObjectCollection";
|
|
4
4
|
|
|
5
5
|
export enum WindowState {
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* The latest messages (those received live) are available in the history window, history has not been fetched.
|
|
8
|
+
*/
|
|
9
|
+
LIVE,
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The latest messages has been fetched and are available in the history window.
|
|
13
|
+
*/
|
|
7
14
|
LATEST,
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The historical messages have been fetched and are available in the history window.
|
|
18
|
+
* Latest messages are not available and will not be available.
|
|
19
|
+
*/
|
|
8
20
|
PAST,
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The oldest messages have been fetched and are available in the history window.
|
|
24
|
+
* Next attempts to fetch previous messages will result with no-op.
|
|
25
|
+
*/
|
|
26
|
+
OLDEST,
|
|
9
27
|
}
|
|
10
28
|
|
|
11
29
|
export abstract class TraversableRemoteCollection<T> extends ObservableIndexedObjectCollection<T> {
|
|
@@ -22,7 +40,7 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
22
40
|
*/
|
|
23
41
|
public limit: number | null = 50;
|
|
24
42
|
|
|
25
|
-
private currentState: WindowState = WindowState.
|
|
43
|
+
private currentState: WindowState = WindowState.LIVE;
|
|
26
44
|
private fetchingState: WindowState = undefined;
|
|
27
45
|
|
|
28
46
|
public async resetToLatest(): Promise<void> {
|
|
@@ -48,6 +66,10 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
public async fetchPrevious(): Promise<void> {
|
|
69
|
+
if (this.state === WindowState.OLDEST) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
51
73
|
this.throwIfFetchingInProgress();
|
|
52
74
|
|
|
53
75
|
this.fetchingState = WindowState.PAST;
|
|
@@ -61,18 +83,23 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
61
83
|
}
|
|
62
84
|
|
|
63
85
|
if (! result) {
|
|
64
|
-
return
|
|
86
|
+
return this.resetToLatest();
|
|
65
87
|
}
|
|
66
88
|
|
|
67
|
-
if (result.length) {
|
|
68
|
-
this.
|
|
69
|
-
|
|
89
|
+
if (! result.length) {
|
|
90
|
+
this.currentState = WindowState.OLDEST;
|
|
91
|
+
return;
|
|
70
92
|
}
|
|
93
|
+
|
|
94
|
+
this.addItems(result, 'head');
|
|
95
|
+
await this.refreshFetchedState();
|
|
71
96
|
}
|
|
72
97
|
|
|
73
98
|
public async fetchNext(): Promise<void> {
|
|
74
99
|
this.throwIfFetchingInProgress();
|
|
75
100
|
|
|
101
|
+
this.fetchingState = WindowState.PAST;
|
|
102
|
+
|
|
76
103
|
let result;
|
|
77
104
|
|
|
78
105
|
try {
|
|
@@ -88,7 +115,7 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
88
115
|
|
|
89
116
|
if (result.length) {
|
|
90
117
|
this.addItems(result, 'tail');
|
|
91
|
-
await this.
|
|
118
|
+
await this.refreshFetchedState();
|
|
92
119
|
}
|
|
93
120
|
}
|
|
94
121
|
|
|
@@ -100,17 +127,11 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
100
127
|
|
|
101
128
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
102
129
|
|
|
103
|
-
protected async
|
|
130
|
+
protected async refreshFetchedState(): Promise<void> {
|
|
104
131
|
this.currentState = (await this.isLatestItemLoaded()) ? WindowState.LATEST : WindowState.PAST;
|
|
105
132
|
}
|
|
106
133
|
|
|
107
|
-
|
|
108
|
-
if (this.fetchingState) {
|
|
109
|
-
throw new Error(`Items fetching in progress: ${WindowState[this.fetchingState]}`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private addItems(newItems: T[], to: 'head' | 'tail'): void {
|
|
134
|
+
protected addItems(newItems: T[], to: 'head' | 'tail'): void {
|
|
114
135
|
let result;
|
|
115
136
|
|
|
116
137
|
if (to === 'head') {
|
|
@@ -125,6 +146,12 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
125
146
|
this.set(...result);
|
|
126
147
|
}
|
|
127
148
|
|
|
149
|
+
private throwIfFetchingInProgress(): void {
|
|
150
|
+
if (this.fetchingState) {
|
|
151
|
+
throw new Error(`Items fetching in progress: ${WindowState[this.fetchingState]}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
128
155
|
/**
|
|
129
156
|
* Return array with messages of count that matching limit.
|
|
130
157
|
*/
|
|
@@ -174,15 +201,11 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<Message> {
|
|
|
174
201
|
|
|
175
202
|
private async handleNewMessage(ev: NewMessage): Promise<void> {
|
|
176
203
|
if (
|
|
177
|
-
[WindowState.LATEST, WindowState.
|
|
204
|
+
[WindowState.LATEST, WindowState.LIVE].includes(this.state)
|
|
178
205
|
&& ev.location.roomId === this.roomId
|
|
179
206
|
&& ev.location.topicId === this.topicId
|
|
180
207
|
) {
|
|
181
|
-
this.
|
|
182
|
-
|
|
183
|
-
if (this.state === WindowState.UNINITIALIZED) {
|
|
184
|
-
await this.refreshMode();
|
|
185
|
-
}
|
|
208
|
+
this.addItems([ev.message], 'tail');
|
|
186
209
|
}
|
|
187
210
|
}
|
|
188
211
|
|
|
@@ -252,6 +275,6 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<Message> {
|
|
|
252
275
|
|
|
253
276
|
protected async isLatestItemLoaded(): Promise<boolean> {
|
|
254
277
|
const lastMessageId = await this.getLatestMessageId();
|
|
255
|
-
return lastMessageId ? this.has(lastMessageId) :
|
|
278
|
+
return lastMessageId ? this.has(lastMessageId) : true;
|
|
256
279
|
}
|
|
257
280
|
}
|
|
@@ -22,6 +22,20 @@ class TestableHistoryWindow extends TraversableRemoteCollection<SimpleMessage> {
|
|
|
22
22
|
super('id');
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
public simulateNewMessageReceived(): void {
|
|
26
|
+
if ([WindowState.LATEST, WindowState.LIVE].includes(this.state)) {
|
|
27
|
+
const lastId = this.getAt(this.length - 1)?.id;
|
|
28
|
+
|
|
29
|
+
const messageToAdd = lastId
|
|
30
|
+
? this.getAt(lastId + 1)
|
|
31
|
+
: messages[messages.length - 1];
|
|
32
|
+
|
|
33
|
+
if (messageToAdd) {
|
|
34
|
+
this.addItems([messageToAdd], 'tail');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
25
39
|
protected async fetchItemsAfter(): Promise<SimpleMessage[]> {
|
|
26
40
|
const after = this.getAt(this.length - 1)?.id;
|
|
27
41
|
if (after === undefined) {
|
|
@@ -52,7 +66,31 @@ test('history window - fresh instance', async () => {
|
|
|
52
66
|
const window = new TestableHistoryWindow();
|
|
53
67
|
expect(window.items).toHaveLength(0);
|
|
54
68
|
expect(window.limit).toEqual(50);
|
|
55
|
-
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('history window - states change', async () => {
|
|
72
|
+
const window = new TestableHistoryWindow();
|
|
73
|
+
window.limit = 5;
|
|
74
|
+
|
|
75
|
+
expect(window.state).toEqual(WindowState.LIVE);
|
|
76
|
+
|
|
77
|
+
window.simulateNewMessageReceived(); // [9]
|
|
78
|
+
|
|
79
|
+
expect(window.state).toEqual(WindowState.LIVE);
|
|
80
|
+
|
|
81
|
+
await window.fetchPrevious(); // [6,7,8,9]
|
|
82
|
+
await window.fetchPrevious(); // [3,4,5,6,7]
|
|
83
|
+
|
|
84
|
+
expect(window.state).toEqual(WindowState.PAST);
|
|
85
|
+
|
|
86
|
+
await window.fetchPrevious(); // [0,1,2,3,4]
|
|
87
|
+
await window.fetchPrevious(); // [0,1,2,3,4]
|
|
88
|
+
|
|
89
|
+
expect(window.state).toEqual(WindowState.OLDEST);
|
|
90
|
+
|
|
91
|
+
await window.resetToLatest(); // [7,8,9]
|
|
92
|
+
|
|
93
|
+
expect(window.state).toEqual(WindowState.LATEST);
|
|
56
94
|
});
|
|
57
95
|
|
|
58
96
|
test('history window - traverse back', async () => {
|
|
@@ -75,7 +113,7 @@ test('history window - traverse back', async () => {
|
|
|
75
113
|
await window.fetchPrevious(); // 0,1,2,3,4
|
|
76
114
|
await window.fetchPrevious(); // 0,1,2,3,4
|
|
77
115
|
|
|
78
|
-
expect(window.state).toEqual(WindowState.
|
|
116
|
+
expect(window.state).toEqual(WindowState.OLDEST);
|
|
79
117
|
expect(window.items).toHaveLength(5);
|
|
80
118
|
[0,1,2,3,4].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
81
119
|
});
|
|
@@ -84,7 +122,7 @@ test('history window - traverse forward', async () => {
|
|
|
84
122
|
const window = new TestableHistoryWindow();
|
|
85
123
|
window.limit = 5;
|
|
86
124
|
|
|
87
|
-
await window.fetchNext();
|
|
125
|
+
await window.fetchNext(); // [7,8,9]
|
|
88
126
|
|
|
89
127
|
expect(window.state).toEqual(WindowState.LATEST);
|
|
90
128
|
expect(window.items).toHaveLength(3);
|
|
@@ -111,13 +149,9 @@ test('history window - reset to latest', async () => {
|
|
|
111
149
|
const window = new TestableHistoryWindow();
|
|
112
150
|
window.limit = 5;
|
|
113
151
|
|
|
114
|
-
await window.fetchPrevious();
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
await window.fetchPrevious();
|
|
119
|
-
await window.fetchPrevious();
|
|
120
|
-
await window.fetchPrevious(); // Move to start
|
|
152
|
+
await window.fetchPrevious(); // [7,8,9]
|
|
153
|
+
await window.fetchPrevious(); // [4,5,6,7,8]
|
|
154
|
+
await window.fetchPrevious(); // [1,2,3,4,5]
|
|
121
155
|
|
|
122
156
|
expect(window.state).toEqual(WindowState.PAST);
|
|
123
157
|
|
|
@@ -127,3 +161,31 @@ test('history window - reset to latest', async () => {
|
|
|
127
161
|
expect(window.items).toHaveLength(3);
|
|
128
162
|
[7,8,9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
129
163
|
});
|
|
164
|
+
|
|
165
|
+
test('history window - trim messages window to limit', async () => {
|
|
166
|
+
const window = new TestableHistoryWindow();
|
|
167
|
+
window.limit = 5;
|
|
168
|
+
|
|
169
|
+
expect(window.items).toHaveLength(0);
|
|
170
|
+
|
|
171
|
+
await window.fetchPrevious(); // [7,8,9]
|
|
172
|
+
|
|
173
|
+
expect(window.items).toHaveLength(3);
|
|
174
|
+
|
|
175
|
+
await window.fetchPrevious(); // [4,5,6,7,8]
|
|
176
|
+
|
|
177
|
+
expect(window.items).toHaveLength(5);
|
|
178
|
+
|
|
179
|
+
await window.fetchNext(); // [5,6,7,8,9]
|
|
180
|
+
|
|
181
|
+
expect(window.items).toHaveLength(5);
|
|
182
|
+
|
|
183
|
+
await window.fetchPrevious(); // [2,3,4,5,6]
|
|
184
|
+
|
|
185
|
+
expect(window.items).toHaveLength(5);
|
|
186
|
+
|
|
187
|
+
window.simulateNewMessageReceived();
|
|
188
|
+
window.simulateNewMessageReceived();
|
|
189
|
+
|
|
190
|
+
expect(window.items).toHaveLength(5);
|
|
191
|
+
});
|