polfan-server-js-client 0.1.995 → 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,23 +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
|
-
/**
|
|
6
|
-
* No messages exist in the history window.
|
|
7
|
-
*/
|
|
8
|
-
EMPTY = 0,
|
|
9
5
|
/**
|
|
10
6
|
* The latest messages (those received live) are available in the history window, history has not been fetched.
|
|
11
7
|
*/
|
|
12
|
-
|
|
8
|
+
LIVE = 0,
|
|
13
9
|
/**
|
|
14
10
|
* The latest messages has been fetched and are available in the history window.
|
|
15
11
|
*/
|
|
16
|
-
|
|
12
|
+
LATEST = 1,
|
|
17
13
|
/**
|
|
18
14
|
* The historical messages have been fetched and are available in the history window.
|
|
19
15
|
* Latest messages are not available and will not be available.
|
|
20
16
|
*/
|
|
21
|
-
|
|
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
|
|
22
23
|
}
|
|
23
24
|
export declare abstract class TraversableRemoteCollection<T> extends ObservableIndexedObjectCollection<T> {
|
|
24
25
|
/**
|
|
@@ -40,9 +41,8 @@ export declare abstract class TraversableRemoteCollection<T> extends ObservableI
|
|
|
40
41
|
protected abstract fetchItemsAfter(): Promise<T[] | null>;
|
|
41
42
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
42
43
|
protected refreshFetchedState(): Promise<void>;
|
|
43
|
-
protected
|
|
44
|
+
protected addItems(newItems: T[], to: 'head' | 'tail'): void;
|
|
44
45
|
private throwIfFetchingInProgress;
|
|
45
|
-
private addItems;
|
|
46
46
|
/**
|
|
47
47
|
* Return array with messages of count that matching limit.
|
|
48
48
|
*/
|
package/package.json
CHANGED
|
@@ -3,26 +3,27 @@ import {ChatStateTracker} from "./ChatStateTracker";
|
|
|
3
3
|
import {ObservableIndexedObjectCollection} from "../IndexedObjectCollection";
|
|
4
4
|
|
|
5
5
|
export enum WindowState {
|
|
6
|
-
/**
|
|
7
|
-
* No messages exist in the history window.
|
|
8
|
-
*/
|
|
9
|
-
EMPTY,
|
|
10
|
-
|
|
11
6
|
/**
|
|
12
7
|
* The latest messages (those received live) are available in the history window, history has not been fetched.
|
|
13
8
|
*/
|
|
14
|
-
|
|
9
|
+
LIVE,
|
|
15
10
|
|
|
16
11
|
/**
|
|
17
12
|
* The latest messages has been fetched and are available in the history window.
|
|
18
13
|
*/
|
|
19
|
-
|
|
14
|
+
LATEST,
|
|
20
15
|
|
|
21
16
|
/**
|
|
22
17
|
* The historical messages have been fetched and are available in the history window.
|
|
23
18
|
* Latest messages are not available and will not be available.
|
|
24
19
|
*/
|
|
25
|
-
|
|
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,
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export abstract class TraversableRemoteCollection<T> extends ObservableIndexedObjectCollection<T> {
|
|
@@ -39,17 +40,17 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
39
40
|
*/
|
|
40
41
|
public limit: number | null = 50;
|
|
41
42
|
|
|
42
|
-
private currentState: WindowState = WindowState.
|
|
43
|
+
private currentState: WindowState = WindowState.LIVE;
|
|
43
44
|
private fetchingState: WindowState = undefined;
|
|
44
45
|
|
|
45
46
|
public async resetToLatest(): Promise<void> {
|
|
46
47
|
this.throwIfFetchingInProgress();
|
|
47
48
|
|
|
48
|
-
if (this.currentState === WindowState.
|
|
49
|
+
if (this.currentState === WindowState.LATEST) {
|
|
49
50
|
return;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
this.fetchingState = WindowState.
|
|
53
|
+
this.fetchingState = WindowState.LATEST;
|
|
53
54
|
|
|
54
55
|
let result;
|
|
55
56
|
|
|
@@ -61,13 +62,17 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
61
62
|
|
|
62
63
|
this.deleteAll();
|
|
63
64
|
this.addItems(result, 'tail');
|
|
64
|
-
this.currentState = WindowState.
|
|
65
|
+
this.currentState = WindowState.LATEST;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
public async fetchPrevious(): Promise<void> {
|
|
69
|
+
if (this.state === WindowState.OLDEST) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
68
73
|
this.throwIfFetchingInProgress();
|
|
69
74
|
|
|
70
|
-
this.fetchingState = WindowState.
|
|
75
|
+
this.fetchingState = WindowState.PAST;
|
|
71
76
|
|
|
72
77
|
let result;
|
|
73
78
|
|
|
@@ -78,18 +83,23 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
if (! result) {
|
|
81
|
-
return
|
|
86
|
+
return this.resetToLatest();
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
if (result.length) {
|
|
85
|
-
this.
|
|
86
|
-
|
|
89
|
+
if (! result.length) {
|
|
90
|
+
this.currentState = WindowState.OLDEST;
|
|
91
|
+
return;
|
|
87
92
|
}
|
|
93
|
+
|
|
94
|
+
this.addItems(result, 'head');
|
|
95
|
+
await this.refreshFetchedState();
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
public async fetchNext(): Promise<void> {
|
|
91
99
|
this.throwIfFetchingInProgress();
|
|
92
100
|
|
|
101
|
+
this.fetchingState = WindowState.PAST;
|
|
102
|
+
|
|
93
103
|
let result;
|
|
94
104
|
|
|
95
105
|
try {
|
|
@@ -118,22 +128,10 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
118
128
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
119
129
|
|
|
120
130
|
protected async refreshFetchedState(): Promise<void> {
|
|
121
|
-
this.currentState = (await this.isLatestItemLoaded()) ? WindowState.
|
|
131
|
+
this.currentState = (await this.isLatestItemLoaded()) ? WindowState.LATEST : WindowState.PAST;
|
|
122
132
|
}
|
|
123
133
|
|
|
124
|
-
protected
|
|
125
|
-
if (this.currentState === WindowState.EMPTY && this.length) {
|
|
126
|
-
this.currentState = WindowState.LATEST_LIVE;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private throwIfFetchingInProgress(): void {
|
|
131
|
-
if (this.fetchingState) {
|
|
132
|
-
throw new Error(`Items fetching in progress: ${WindowState[this.fetchingState]}`);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private addItems(newItems: T[], to: 'head' | 'tail'): void {
|
|
134
|
+
protected addItems(newItems: T[], to: 'head' | 'tail'): void {
|
|
137
135
|
let result;
|
|
138
136
|
|
|
139
137
|
if (to === 'head') {
|
|
@@ -148,6 +146,12 @@ export abstract class TraversableRemoteCollection<T> extends ObservableIndexedOb
|
|
|
148
146
|
this.set(...result);
|
|
149
147
|
}
|
|
150
148
|
|
|
149
|
+
private throwIfFetchingInProgress(): void {
|
|
150
|
+
if (this.fetchingState) {
|
|
151
|
+
throw new Error(`Items fetching in progress: ${WindowState[this.fetchingState]}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
151
155
|
/**
|
|
152
156
|
* Return array with messages of count that matching limit.
|
|
153
157
|
*/
|
|
@@ -197,12 +201,11 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<Message> {
|
|
|
197
201
|
|
|
198
202
|
private async handleNewMessage(ev: NewMessage): Promise<void> {
|
|
199
203
|
if (
|
|
200
|
-
[WindowState.
|
|
204
|
+
[WindowState.LATEST, WindowState.LIVE].includes(this.state)
|
|
201
205
|
&& ev.location.roomId === this.roomId
|
|
202
206
|
&& ev.location.topicId === this.topicId
|
|
203
207
|
) {
|
|
204
|
-
this.
|
|
205
|
-
this.refreshLiveState();
|
|
208
|
+
this.addItems([ev.message], 'tail');
|
|
206
209
|
}
|
|
207
210
|
}
|
|
208
211
|
|
|
@@ -23,8 +23,17 @@ class TestableHistoryWindow extends TraversableRemoteCollection<SimpleMessage> {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
public simulateNewMessageReceived(): void {
|
|
26
|
-
|
|
27
|
-
|
|
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
|
+
}
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
protected async fetchItemsAfter(): Promise<SimpleMessage[]> {
|
|
@@ -63,20 +72,25 @@ test('history window - states change', async () => {
|
|
|
63
72
|
const window = new TestableHistoryWindow();
|
|
64
73
|
window.limit = 5;
|
|
65
74
|
|
|
66
|
-
expect(window.state).toEqual(WindowState.
|
|
75
|
+
expect(window.state).toEqual(WindowState.LIVE);
|
|
67
76
|
|
|
68
77
|
window.simulateNewMessageReceived(); // [9]
|
|
69
78
|
|
|
70
|
-
expect(window.state).toEqual(WindowState.
|
|
79
|
+
expect(window.state).toEqual(WindowState.LIVE);
|
|
71
80
|
|
|
72
81
|
await window.fetchPrevious(); // [6,7,8,9]
|
|
73
82
|
await window.fetchPrevious(); // [3,4,5,6,7]
|
|
74
83
|
|
|
75
|
-
expect(window.state).toEqual(WindowState.
|
|
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]
|
|
76
88
|
|
|
77
|
-
|
|
89
|
+
expect(window.state).toEqual(WindowState.OLDEST);
|
|
78
90
|
|
|
79
|
-
|
|
91
|
+
await window.resetToLatest(); // [7,8,9]
|
|
92
|
+
|
|
93
|
+
expect(window.state).toEqual(WindowState.LATEST);
|
|
80
94
|
});
|
|
81
95
|
|
|
82
96
|
test('history window - traverse back', async () => {
|
|
@@ -85,13 +99,13 @@ test('history window - traverse back', async () => {
|
|
|
85
99
|
|
|
86
100
|
await window.fetchPrevious(); // 7,8,9
|
|
87
101
|
|
|
88
|
-
expect(window.state).toEqual(WindowState.
|
|
102
|
+
expect(window.state).toEqual(WindowState.LATEST);
|
|
89
103
|
expect(window.items).toHaveLength(3);
|
|
90
104
|
[7,8,9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
91
105
|
|
|
92
106
|
await window.fetchPrevious(); // 4,5,6,7,8
|
|
93
107
|
|
|
94
|
-
expect(window.state).toEqual(WindowState.
|
|
108
|
+
expect(window.state).toEqual(WindowState.PAST);
|
|
95
109
|
expect(window.items).toHaveLength(5);
|
|
96
110
|
[4,5,6,7,8].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
97
111
|
|
|
@@ -99,7 +113,7 @@ test('history window - traverse back', async () => {
|
|
|
99
113
|
await window.fetchPrevious(); // 0,1,2,3,4
|
|
100
114
|
await window.fetchPrevious(); // 0,1,2,3,4
|
|
101
115
|
|
|
102
|
-
expect(window.state).toEqual(WindowState.
|
|
116
|
+
expect(window.state).toEqual(WindowState.OLDEST);
|
|
103
117
|
expect(window.items).toHaveLength(5);
|
|
104
118
|
[0,1,2,3,4].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
105
119
|
});
|
|
@@ -108,9 +122,9 @@ test('history window - traverse forward', async () => {
|
|
|
108
122
|
const window = new TestableHistoryWindow();
|
|
109
123
|
window.limit = 5;
|
|
110
124
|
|
|
111
|
-
await window.fetchNext();
|
|
125
|
+
await window.fetchNext(); // [7,8,9]
|
|
112
126
|
|
|
113
|
-
expect(window.state).toEqual(WindowState.
|
|
127
|
+
expect(window.state).toEqual(WindowState.LATEST);
|
|
114
128
|
expect(window.items).toHaveLength(3);
|
|
115
129
|
[7,8,9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
116
130
|
|
|
@@ -118,7 +132,7 @@ test('history window - traverse forward', async () => {
|
|
|
118
132
|
await window.fetchPrevious(); // [1,2,3,4,5]
|
|
119
133
|
await window.fetchNext(); // [4,5,6,7,8]
|
|
120
134
|
|
|
121
|
-
expect(window.state).toEqual(WindowState.
|
|
135
|
+
expect(window.state).toEqual(WindowState.PAST);
|
|
122
136
|
expect(window.items).toHaveLength(5);
|
|
123
137
|
[4,5,6,7,8].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
124
138
|
|
|
@@ -126,7 +140,7 @@ test('history window - traverse forward', async () => {
|
|
|
126
140
|
await window.fetchNext();
|
|
127
141
|
await window.fetchNext(); // move to latest
|
|
128
142
|
|
|
129
|
-
expect(window.state).toEqual(WindowState.
|
|
143
|
+
expect(window.state).toEqual(WindowState.LATEST);
|
|
130
144
|
expect(window.items).toHaveLength(5);
|
|
131
145
|
[5,6,7,8,9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
132
146
|
});
|
|
@@ -135,19 +149,43 @@ test('history window - reset to latest', async () => {
|
|
|
135
149
|
const window = new TestableHistoryWindow();
|
|
136
150
|
window.limit = 5;
|
|
137
151
|
|
|
138
|
-
await window.fetchPrevious();
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
await window.fetchPrevious();
|
|
143
|
-
await window.fetchPrevious();
|
|
144
|
-
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]
|
|
145
155
|
|
|
146
|
-
expect(window.state).toEqual(WindowState.
|
|
156
|
+
expect(window.state).toEqual(WindowState.PAST);
|
|
147
157
|
|
|
148
158
|
await window.resetToLatest();
|
|
149
159
|
|
|
150
|
-
expect(window.state).toEqual(WindowState.
|
|
160
|
+
expect(window.state).toEqual(WindowState.LATEST);
|
|
151
161
|
expect(window.items).toHaveLength(3);
|
|
152
162
|
[7,8,9].forEach(id => expect(window.items.map(item => item.id)).toContain(id));
|
|
153
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
|
+
});
|