polfan-server-js-client 0.2.89 → 0.2.91
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 +22 -22
- package/build/index.cjs.js +255 -151
- 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/MessagesManager.d.ts +6 -1
- package/build/types/state-tracker/RoomMessagesHistory.d.ts +3 -1
- package/build/types/state-tracker/TopicHistoryWindow.d.ts +3 -2
- package/package.json +1 -1
- package/src/state-tracker/MessagesManager.ts +31 -2
- package/src/state-tracker/RoomMessagesHistory.ts +4 -2
- package/src/state-tracker/RoomsManager.ts +5 -6
- package/src/state-tracker/TopicHistoryWindow.ts +51 -38
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ChatStateTracker } from "./ChatStateTracker";
|
|
2
|
-
import { FollowedTopic } from "../types/src";
|
|
2
|
+
import { FollowedTopic, Message, ChatLocation } from "../types/src";
|
|
3
3
|
import { ObservableIndexedObjectCollection } from "../IndexedObjectCollection";
|
|
4
4
|
import { RoomMessagesHistory } from "./RoomMessagesHistory";
|
|
5
5
|
export declare class MessagesManager {
|
|
@@ -38,6 +38,11 @@ export declare class MessagesManager {
|
|
|
38
38
|
* @internal
|
|
39
39
|
*/
|
|
40
40
|
_deleteByTopicIds(roomId: string, ...topicIds: string[]): void;
|
|
41
|
+
/**
|
|
42
|
+
* For internal use.
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
_resolveLastMessage(location: ChatLocation): Promise<Message | null>;
|
|
41
46
|
private createHistoryForNewRoom;
|
|
42
47
|
private handleNewMessage;
|
|
43
48
|
private handleFollowedTopicUpdated;
|
|
@@ -9,8 +9,10 @@ export declare class RoomMessagesHistory {
|
|
|
9
9
|
constructor(room: Room, tracker: ChatStateTracker);
|
|
10
10
|
/**
|
|
11
11
|
* Returns a history window object for the given topic ID, allowing you to view message history.
|
|
12
|
+
* @param topicId
|
|
13
|
+
* @param peek If true, do not create a cache for this topic and do not allow it to collect new messages.
|
|
12
14
|
*/
|
|
13
|
-
getMessagesWindow(topicId: string): Promise<TopicHistoryWindow | undefined>;
|
|
15
|
+
getMessagesWindow(topicId: string, peek?: boolean): Promise<TopicHistoryWindow | undefined>;
|
|
14
16
|
private handleRoomUpdated;
|
|
15
17
|
private handleNewTopic;
|
|
16
18
|
private handleTopicDeleted;
|
|
@@ -73,6 +73,7 @@ export declare abstract class TraversableRemoteCollection<ItemT, EventMapT exten
|
|
|
73
73
|
protected abstract isLatestItemLoaded(): Promise<boolean>;
|
|
74
74
|
protected refreshFetchedState(): Promise<void>;
|
|
75
75
|
protected addItems(newItems: ItemT[], to: 'head' | 'tail'): void;
|
|
76
|
+
protected emitChangeWithDiff(itemChanged: boolean, originalState: WindowState): void;
|
|
76
77
|
/**
|
|
77
78
|
* Return array with messages trimmed using High/Low Watermark strategy.
|
|
78
79
|
*/
|
|
@@ -104,12 +105,12 @@ export declare class TopicHistoryWindow extends TraversableRemoteCollection<Mess
|
|
|
104
105
|
* @internal
|
|
105
106
|
*/
|
|
106
107
|
_updateMessageReference(refTopic: Topic): void;
|
|
107
|
-
private handleNewMessage;
|
|
108
|
-
private handleMessagesRedacted;
|
|
109
108
|
protected fetchItemsAfter(): Promise<Message[] | null>;
|
|
110
109
|
protected fetchItemsBefore(): Promise<Message[] | null>;
|
|
111
110
|
protected fetchLatestItems(): Promise<Message[]>;
|
|
112
111
|
private getTopic;
|
|
113
112
|
private getLatestMessageId;
|
|
114
113
|
protected isLatestItemLoaded(): Promise<boolean>;
|
|
114
|
+
private handleNewMessage;
|
|
115
|
+
private handleMessagesRedacted;
|
|
115
116
|
}
|
package/package.json
CHANGED
|
@@ -7,7 +7,12 @@ import {
|
|
|
7
7
|
RoomDeleted,
|
|
8
8
|
RoomLeft,
|
|
9
9
|
TopicDeleted,
|
|
10
|
-
FollowedTopicUpdated,
|
|
10
|
+
FollowedTopicUpdated,
|
|
11
|
+
RoomJoined,
|
|
12
|
+
NewTopic,
|
|
13
|
+
Session,
|
|
14
|
+
Room,
|
|
15
|
+
Message, ChatLocation,
|
|
11
16
|
} from "../types/src";
|
|
12
17
|
import {
|
|
13
18
|
IndexedCollection,
|
|
@@ -129,7 +134,7 @@ export class MessagesManager {
|
|
|
129
134
|
return collection.items.reduce(
|
|
130
135
|
(previousValue: number, currentValue) => previousValue + (currentValue.missed ?? 0),
|
|
131
136
|
0,
|
|
132
|
-
);
|
|
137
|
+
) as number;
|
|
133
138
|
}
|
|
134
139
|
|
|
135
140
|
return undefined;
|
|
@@ -143,6 +148,30 @@ export class MessagesManager {
|
|
|
143
148
|
this.followedTopics.get(roomId)?.delete(...topicIds);
|
|
144
149
|
}
|
|
145
150
|
|
|
151
|
+
/**
|
|
152
|
+
* For internal use.
|
|
153
|
+
* @internal
|
|
154
|
+
*/
|
|
155
|
+
public async _resolveLastMessage(location: ChatLocation): Promise<Message|null> {
|
|
156
|
+
// Try to get last message from history window (if cached)
|
|
157
|
+
let message: Message = await this.getRoomHistory(location.roomId)
|
|
158
|
+
.then(roomHistory => roomHistory?.getMessagesWindow(location.topicId, true))
|
|
159
|
+
.then(
|
|
160
|
+
historyWindow =>
|
|
161
|
+
historyWindow?.hasLatest && historyWindow.getAt(historyWindow.length - 1)
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
if (!message) {
|
|
165
|
+
const result = await this.tracker.client.send('GetMessages', {
|
|
166
|
+
location,
|
|
167
|
+
limit: 1,
|
|
168
|
+
});
|
|
169
|
+
message = result.data?.messages[0];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return message || null;
|
|
173
|
+
}
|
|
174
|
+
|
|
146
175
|
private createHistoryForNewRoom(room: Room): void {
|
|
147
176
|
this.roomHistories.set([room.id, new RoomMessagesHistory(room, this.tracker)]);
|
|
148
177
|
}
|
|
@@ -24,9 +24,11 @@ export class RoomMessagesHistory {
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Returns a history window object for the given topic ID, allowing you to view message history.
|
|
27
|
+
* @param topicId
|
|
28
|
+
* @param peek If true, do not create a cache for this topic and do not allow it to collect new messages.
|
|
27
29
|
*/
|
|
28
|
-
public async getMessagesWindow(topicId: string): Promise<TopicHistoryWindow | undefined> {
|
|
29
|
-
if (!this.historyWindows.has(topicId)) {
|
|
30
|
+
public async getMessagesWindow(topicId: string, peek: boolean = false): Promise<TopicHistoryWindow | undefined> {
|
|
31
|
+
if (!this.historyWindows.has(topicId) && !peek) {
|
|
30
32
|
const topic = (await this.tracker.rooms.getTopics(this.room.id, [topicId])).get(topicId);
|
|
31
33
|
|
|
32
34
|
if (topic) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {IndexedCollection, ObservableIndexedObjectCollection} from "../IndexedObjectCollection";
|
|
2
2
|
import {
|
|
3
|
+
Message,
|
|
3
4
|
MessagesRedacted,
|
|
4
5
|
NewMessage,
|
|
5
6
|
NewTopic,
|
|
@@ -368,16 +369,14 @@ export class RoomsManager {
|
|
|
368
369
|
}
|
|
369
370
|
}
|
|
370
371
|
|
|
371
|
-
private handleMessagesRedacted(ev: MessagesRedacted): void {
|
|
372
|
+
private async handleMessagesRedacted(ev: MessagesRedacted): Promise<void> {
|
|
372
373
|
// Remove redacted messages from topic and update metadata
|
|
373
374
|
const topics = this.topics.get(ev.location.roomId);
|
|
374
375
|
const topic = topics?.get(ev.location.topicId);
|
|
375
376
|
if (topic) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
lastMessage: ev.ids.includes(topic.lastMessage?.id) ? null : topic.lastMessage,
|
|
380
|
-
} as Topic);
|
|
377
|
+
const messageCount = Math.max(topic.messageCount - ev.ids.length, 0);
|
|
378
|
+
const lastMessage: Message = messageCount > 0 ? await this.messages._resolveLastMessage(ev.location) : null;
|
|
379
|
+
topics.set({ ...topic, messageCount, lastMessage } as Topic);
|
|
381
380
|
}
|
|
382
381
|
}
|
|
383
382
|
}
|
|
@@ -116,9 +116,9 @@ export abstract class TraversableRemoteCollection<
|
|
|
116
116
|
return;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
this.internalState.ongoing = WindowState.LATEST;
|
|
120
|
-
|
|
121
119
|
let result;
|
|
120
|
+
const originalState = this.state;
|
|
121
|
+
this.internalState.ongoing = WindowState.LATEST;
|
|
122
122
|
|
|
123
123
|
try {
|
|
124
124
|
result = await this.fetchLatestItems();
|
|
@@ -130,6 +130,7 @@ export abstract class TraversableRemoteCollection<
|
|
|
130
130
|
this._items.deleteAll(); // Directly call deleteAll to prevent event emit.
|
|
131
131
|
this.addItems(result, 'tail');
|
|
132
132
|
this.internalState.current = WindowState.LATEST;
|
|
133
|
+
this.emitChangeWithDiff(true, originalState);
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
public async fetchPrevious(): Promise<void> {
|
|
@@ -137,9 +138,9 @@ export abstract class TraversableRemoteCollection<
|
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
this.internalState.ongoing = WindowState.PAST;
|
|
141
|
-
|
|
142
141
|
let result;
|
|
142
|
+
const originalState = this.state;
|
|
143
|
+
this.internalState.ongoing = WindowState.PAST;
|
|
143
144
|
|
|
144
145
|
try {
|
|
145
146
|
result = await this.fetchItemsBefore();
|
|
@@ -163,11 +164,13 @@ export abstract class TraversableRemoteCollection<
|
|
|
163
164
|
this.internalState.current = WindowState.OLDEST;
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
this.emitChangeWithDiff(false, originalState);
|
|
166
168
|
return;
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
this.addItems(result, 'head');
|
|
170
172
|
await this.refreshFetchedState();
|
|
173
|
+
this.emitChangeWithDiff(true, originalState);
|
|
171
174
|
}
|
|
172
175
|
|
|
173
176
|
public async fetchNext(): Promise<void> {
|
|
@@ -175,9 +178,9 @@ export abstract class TraversableRemoteCollection<
|
|
|
175
178
|
return;
|
|
176
179
|
}
|
|
177
180
|
|
|
178
|
-
this.internalState.ongoing = WindowState.PAST;
|
|
179
|
-
|
|
180
181
|
let result;
|
|
182
|
+
const originalState = this.state;
|
|
183
|
+
this.internalState.ongoing = WindowState.PAST;
|
|
181
184
|
|
|
182
185
|
try {
|
|
183
186
|
result = await this.fetchItemsAfter();
|
|
@@ -194,6 +197,7 @@ export abstract class TraversableRemoteCollection<
|
|
|
194
197
|
if (result.length) {
|
|
195
198
|
this.addItems(result, 'tail');
|
|
196
199
|
await this.refreshFetchedState();
|
|
200
|
+
this.emitChangeWithDiff(true, originalState);
|
|
197
201
|
return;
|
|
198
202
|
}
|
|
199
203
|
}
|
|
@@ -221,8 +225,15 @@ export abstract class TraversableRemoteCollection<
|
|
|
221
225
|
result = this.trimItemsArrayToLimit([...this.items, ...newItems], 'head');
|
|
222
226
|
}
|
|
223
227
|
|
|
224
|
-
|
|
225
|
-
this.
|
|
228
|
+
// Directly calls to prevent event emit.
|
|
229
|
+
this._items.deleteAll();
|
|
230
|
+
this._items.set(...(result.map(item => [this.getId(item), item] as [string, ItemT])));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
protected emitChangeWithDiff(itemChanged: boolean, originalState: WindowState): void {
|
|
234
|
+
if (itemChanged || originalState !== this.state) {
|
|
235
|
+
this.eventTarget.emit('change', { setItems: Array.from(this._items.items.keys()) })
|
|
236
|
+
}
|
|
226
237
|
}
|
|
227
238
|
|
|
228
239
|
/**
|
|
@@ -336,36 +347,6 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<
|
|
|
336
347
|
}
|
|
337
348
|
}
|
|
338
349
|
|
|
339
|
-
private async handleNewMessage(ev: NewMessage): Promise<void> {
|
|
340
|
-
if (
|
|
341
|
-
[WindowState.LATEST, WindowState.LIVE].includes(this.state)
|
|
342
|
-
&& ev.message.location.roomId === this.roomId
|
|
343
|
-
&& ev.message.location.topicId === this.topicId
|
|
344
|
-
) {
|
|
345
|
-
this.addItems([ev.message], 'tail');
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
private async handleMessagesRedacted(ev: MessagesRedacted): Promise<void> {
|
|
350
|
-
if (ev.location.topicId !== this.topicId || ev.location.roomId !== this.roomId) {
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const refTopicIds = this.items
|
|
355
|
-
.filter(msg => msg.topicRef && ev.ids.includes(msg.id))
|
|
356
|
-
.map(msg => msg.topicRef as string);
|
|
357
|
-
|
|
358
|
-
this.delete(...ev.ids);
|
|
359
|
-
|
|
360
|
-
if (this.length === 0) {
|
|
361
|
-
await this.resetToLatest();
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
if (refTopicIds.length > 0) {
|
|
365
|
-
this.eventTarget.emit('reftopicsdeleted', refTopicIds);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
350
|
protected async fetchItemsAfter(): Promise<Message[] | null> {
|
|
370
351
|
const afterId = this.getAt(this.length - 1)?.id;
|
|
371
352
|
|
|
@@ -433,4 +414,36 @@ export class TopicHistoryWindow extends TraversableRemoteCollection<
|
|
|
433
414
|
const lastMessageId = await this.getLatestMessageId();
|
|
434
415
|
return lastMessageId ? this.has(lastMessageId) : true;
|
|
435
416
|
}
|
|
417
|
+
|
|
418
|
+
private async handleNewMessage(ev: NewMessage): Promise<void> {
|
|
419
|
+
if (
|
|
420
|
+
[WindowState.LATEST, WindowState.LIVE].includes(this.state)
|
|
421
|
+
&& ev.message.location.roomId === this.roomId
|
|
422
|
+
&& ev.message.location.topicId === this.topicId
|
|
423
|
+
) {
|
|
424
|
+
const originalState = this.state;
|
|
425
|
+
this.addItems([ev.message], 'tail');
|
|
426
|
+
this.emitChangeWithDiff(true, originalState);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private async handleMessagesRedacted(ev: MessagesRedacted): Promise<void> {
|
|
431
|
+
if (ev.location.topicId !== this.topicId || ev.location.roomId !== this.roomId) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const refTopicIds = this.items
|
|
436
|
+
.filter(msg => msg.topicRef && ev.ids.includes(msg.id))
|
|
437
|
+
.map(msg => msg.topicRef as string);
|
|
438
|
+
|
|
439
|
+
this.delete(...ev.ids);
|
|
440
|
+
|
|
441
|
+
if (this.length === 0) {
|
|
442
|
+
await this.resetToLatest();
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (refTopicIds.length > 0) {
|
|
446
|
+
this.eventTarget.emit('reftopicsdeleted', refTopicIds);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
436
449
|
}
|