polfan-server-js-client 0.1.23 → 0.1.25

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.
@@ -1,346 +0,0 @@
1
- import {WebSocketChatClient} from "./WebSocketChatClient";
2
- import {IndexedCollection, ObservableIndexedObjectCollection} from "./IndexedObjectCollection";
3
- import {
4
- Message,
5
- NewMessage,
6
- NewRole,
7
- NewRoom,
8
- NewTopic, Role,
9
- RoleDeleted,
10
- Room,
11
- RoomDeleted,
12
- RoomJoined,
13
- RoomLeft, RoomMember,
14
- RoomMemberJoined,
15
- RoomMemberLeft,
16
- RoomMembers, RoomSummary,
17
- Session,
18
- Space,
19
- SpaceDeleted,
20
- SpaceJoined,
21
- SpaceLeft, SpaceMember,
22
- SpaceMemberJoined,
23
- SpaceMemberLeft,
24
- SpaceMembers,
25
- SpaceMemberUpdate,
26
- SpaceRooms, Topic,
27
- TopicDeleted, User
28
- } from "pserv-ts-types";
29
-
30
- type Deferred = {resolver: () => void, promise: Promise<void>};
31
-
32
- export class ChatStateTracker {
33
- private readonly joinedSpaces = new ObservableIndexedObjectCollection<Space>('id');
34
- private readonly joinedRooms = new ObservableIndexedObjectCollection<Room>('id');
35
- private readonly spacesRoles = new IndexedCollection<string, ObservableIndexedObjectCollection<Role>>();
36
- private readonly roomsTopics = new IndexedCollection<string, ObservableIndexedObjectCollection<Topic>>();
37
- // Temporary not lazy loaded; server must implement GetTopicMessages command.
38
- private readonly topicsMessages = new IndexedCollection<string, ObservableIndexedObjectCollection<Message>>();
39
-
40
- // lazy loaded collections
41
- private readonly spacesRooms = new IndexedCollection<string, ObservableIndexedObjectCollection<RoomSummary>>();
42
- private readonly spacesMembers = new IndexedCollection<string, ObservableIndexedObjectCollection<SpaceMember>>();
43
- private readonly roomsMembers = new IndexedCollection<string, ObservableIndexedObjectCollection<RoomMember>>();
44
- private readonly deferredGetters = new IndexedCollection<string, Deferred>();
45
-
46
- private reconnecting: boolean = false;
47
- private me: User = null;
48
-
49
- public constructor(private readonly client: WebSocketChatClient) {
50
- this.createDeferredGetter('session');
51
- this.bind();
52
- }
53
-
54
- public async getMe(): Promise<User> {
55
- await this.deferredGetterReadiness('session');
56
- return this.me;
57
- }
58
-
59
- public async getJoinedSpaces(): Promise<ObservableIndexedObjectCollection<Space>> {
60
- await this.deferredGetterReadiness('session');
61
- return this.joinedSpaces;
62
- }
63
-
64
- public async getJoinedRooms(): Promise<ObservableIndexedObjectCollection<Room>> {
65
- await this.deferredGetterReadiness('session');
66
- return this.joinedRooms;
67
- }
68
-
69
- public async getSpaceRoles(spaceId: string): Promise<ObservableIndexedObjectCollection<Role> | null> {
70
- await this.deferredGetterReadiness('session');
71
- return this.spacesRoles.get(spaceId);
72
- }
73
-
74
- public async getRoomTopics(roomId: string): Promise<ObservableIndexedObjectCollection<Topic> | null> {
75
- await this.deferredGetterReadiness('session');
76
- return this.roomsTopics.get(roomId);
77
- }
78
-
79
- public async getTopicMessages(topicId: string): Promise<ObservableIndexedObjectCollection<Message> | null> {
80
- return this.topicsMessages.get(topicId);
81
- }
82
-
83
- public async getSpaceRooms(spaceId: string): Promise<ObservableIndexedObjectCollection<RoomSummary> | null> {
84
- const deferredGetterName = `spaces-rooms-${spaceId}`;
85
- if (!this.spacesRooms.has(spaceId) && !this.deferredGetters.has(deferredGetterName)) {
86
- this.createDeferredGetter(deferredGetterName);
87
- this.client.send('GetSpaceRooms', {id: spaceId});
88
- }
89
- await this.deferredGetterReadiness(deferredGetterName);
90
- return this.spacesRooms.get(spaceId);
91
- }
92
-
93
- public async getSpaceMembers(spaceId: string): Promise<ObservableIndexedObjectCollection<SpaceMember> | null> {
94
- const deferredGetterName = `spaces-members-${spaceId}`;
95
- if (!this.spacesMembers.has(spaceId) && !this.deferredGetters.has(deferredGetterName)) {
96
- this.createDeferredGetter(deferredGetterName);
97
- this.client.send('GetSpaceMembers', {id: spaceId});
98
- }
99
- await this.deferredGetterReadiness(deferredGetterName);
100
- return this.spacesMembers.get(spaceId);
101
- }
102
-
103
- public async getRoomMembers(roomId: string): Promise<ObservableIndexedObjectCollection<RoomMember> | null> {
104
- const deferredGetterName = `rooms-members-${roomId}`;
105
- if (!this.roomsMembers.has(roomId) && !this.deferredGetters.has(deferredGetterName)) {
106
- this.createDeferredGetter(deferredGetterName);
107
- this.client.send('GetRoomMembers', {id: roomId});
108
- }
109
- await this.deferredGetterReadiness(deferredGetterName);
110
- return this.roomsMembers.get(roomId);
111
- }
112
-
113
- private async deferredGetterReadiness(name: string): Promise<void> {
114
- if (this.deferredGetters.has(name)) {
115
- await this.deferredGetters.get(name)?.promise;
116
- }
117
- }
118
-
119
- private bind(): void {
120
- this.client.on(this.client.Event.disconnect, ev => this.handleDisconnect(ev as any as boolean));
121
- this.client.on('NewMessage', ev => this.handleNewMessage(ev));
122
- this.client.on('NewRole', ev => this.handleNewRole(ev));
123
- this.client.on('NewRoom', ev => this.handleNewRoom(ev));
124
- this.client.on('NewTopic', ev => this.handleNewTopic(ev));
125
- this.client.on('RoleDeleted', ev => this.handleRoleDeleted(ev));
126
- this.client.on('RoomDeleted', ev => this.handleRoomDeleted(ev));
127
- this.client.on('RoomJoined', ev => this.handleRoomJoined(ev));
128
- this.client.on('RoomLeft', ev => this.handleRoomLeft(ev));
129
- this.client.on('RoomMemberJoined', ev => this.handleRoomMemberJoined(ev));
130
- this.client.on('RoomMemberLeft', ev => this.handleRoomMemberLeft(ev));
131
- this.client.on('RoomMembers', ev => this.handleRoomMembers(ev));
132
- this.client.on('Session', ev => this.handleSession(ev));
133
- this.client.on('SpaceDeleted', ev => this.handleSpaceDeleted(ev));
134
- this.client.on('SpaceJoined', ev => this.handleSpaceJoined(ev));
135
- this.client.on('SpaceLeft', ev => this.handleSpaceLeft(ev));
136
- this.client.on('SpaceMemberJoined', ev => this.handleSpaceMemberJoined(ev));
137
- this.client.on('SpaceMemberLeft', ev => this.handleSpaceMemberLeft(ev));
138
- this.client.on('SpaceMembers', ev => this.handleSpaceMembers(ev));
139
- this.client.on('SpaceRooms', ev => this.handleSpaceRooms(ev));
140
- this.client.on('SpaceMemberUpdate', ev => this.handleSpaceMemberUpdate(ev));
141
- this.client.on('TopicDeleted', ev => this.handleTopicDeleted(ev));
142
- }
143
-
144
- private createDeferredGetter(name: string): void {
145
- if (this.deferredGetters.has(name)) {
146
- return;
147
- }
148
- const deferred: Deferred = {promise: undefined, resolver: undefined};
149
- deferred.promise = new Promise(resolve => deferred.resolver = resolve);
150
- this.deferredGetters.set([name, deferred]);
151
- }
152
-
153
- private handleDisconnect(reconnect: boolean): void {
154
- if (reconnect) {
155
- this.reconnecting = true;
156
- return;
157
- }
158
- }
159
-
160
- private handleNewMessage(ev: NewMessage): void {
161
- this.topicsMessages.get(ev.topicId).set(ev.message);
162
- }
163
-
164
- private handleNewRole(ev: NewRole): void {
165
- const collection = this.spacesRoles.get(ev.spaceId);
166
- collection.set(ev.role);
167
- this.joinedSpaces.get(ev.spaceId).roles = collection.items;
168
- }
169
-
170
- private handleNewRoom(ev: NewRoom): void {
171
- this.spacesRooms.get(ev.spaceId)?.set(ev.summary);
172
- }
173
-
174
- private handleNewTopic(ev: NewTopic): void {
175
- this.addJoinedRoomTopics(ev.roomId, ev.topic);
176
- this.joinedRooms.get(ev.roomId).topics.push(ev.topic);
177
- }
178
-
179
- private addJoinedRoomTopics(roomId: string, ...topics: Topic[]): void {
180
- if (this.roomsTopics.has(roomId)) {
181
- this.roomsTopics.get(roomId).set(...topics);
182
- } else {
183
- this.roomsTopics.set([roomId, new ObservableIndexedObjectCollection<Topic>('id', topics)]);
184
- }
185
-
186
- this.topicsMessages.set(...topics.map<[string, ObservableIndexedObjectCollection<Message>]>(topic => [
187
- topic.id,
188
- new ObservableIndexedObjectCollection<Message>('id')
189
- ]));
190
- }
191
-
192
- private handleRoleDeleted(ev: RoleDeleted): void {
193
- const collection = this.spacesRoles.get(ev.spaceId);
194
- collection.delete(ev.id);
195
- this.joinedSpaces.get(ev.spaceId).roles = collection.items;
196
- }
197
-
198
- private handleRoomDeleted(ev: RoomDeleted): void {
199
- if (ev.spaceId) {
200
- this.spacesRooms.get(ev.spaceId).delete(ev.id);
201
- }
202
- this.deleteJoinedRooms(ev.id);
203
- }
204
-
205
- private handleRoomJoined(ev: RoomJoined): void {
206
- this.addJoinedRooms(ev.room);
207
- }
208
-
209
- private addJoinedRooms(...rooms: Room[]): void {
210
- for (const room of rooms) {
211
- this.addJoinedRoomTopics(room.id, ...room.topics);
212
- }
213
- this.joinedRooms.set(...rooms);
214
- }
215
-
216
- private handleRoomLeft(ev: RoomLeft): void {
217
- this.deleteJoinedRooms(ev.id);
218
- }
219
-
220
- private deleteJoinedRooms(...roomIds: string[]): void {
221
- this.joinedRooms.delete(...roomIds);
222
- this.roomsMembers.delete(...roomIds);
223
-
224
- const topicIds: string[] = [];
225
- for (const roomId of roomIds) {
226
- topicIds.push(...(this.roomsTopics.get(roomId)?.map(topic => topic.id) ?? []));
227
- }
228
- this.topicsMessages.delete(...topicIds);
229
-
230
- this.roomsTopics.delete(...roomIds);
231
- }
232
-
233
- private handleRoomMemberJoined(ev: RoomMemberJoined): void {
234
- if (this.roomsMembers.has(ev.roomId)) {
235
- this.roomsMembers.get(ev.roomId).set(ev.member);
236
- }
237
- }
238
-
239
- private handleRoomMemberLeft(ev: RoomMemberLeft): void {
240
- if (this.roomsMembers.has(ev.roomId)) {
241
- this.roomsMembers.get(ev.roomId).delete(ev.userId);
242
- }
243
- }
244
-
245
- private handleRoomMembers(ev: RoomMembers): void {
246
- if (!this.roomsMembers.has(ev.id)) {
247
- this.roomsMembers.set([
248
- ev.id,
249
- new ObservableIndexedObjectCollection(
250
- member => member.user?.id ?? member.spaceMember.user.id,
251
- ev.members,
252
- )
253
- ]);
254
- this.deferredGetters.get(`rooms-members-${ev.id}`)?.resolver();
255
- }
256
- }
257
-
258
- private handleSession(ev: Session): void {
259
- if (this.me && !this.reconnecting) {
260
- return;
261
- }
262
-
263
- this.me = ev.user;
264
- this.reconnecting = false;
265
-
266
- this.joinedRooms.deleteAll();
267
- this.roomsTopics.deleteAll();
268
- this.roomsMembers.deleteAll();
269
- this.joinedSpaces.deleteAll();
270
- this.spacesRoles.deleteAll();
271
- this.spacesRooms.deleteAll();
272
- this.spacesMembers.deleteAll();
273
-
274
- this.addJoinedRooms(...ev.state.rooms);
275
- this.addJoinedSpaces(...ev.state.spaces);
276
-
277
- this.deferredGetters.get('session')?.resolver();
278
- }
279
-
280
- private handleSpaceDeleted(ev: SpaceDeleted): void {
281
- this.deleteJoinedRooms(
282
- ...this.joinedRooms.findBy('spaceId', ev.id).map(room => room.id)
283
- );
284
- this.spacesRoles.delete(ev.id);
285
- this.spacesMembers.delete(ev.id);
286
- this.spacesRooms.delete(ev.id);
287
- this.joinedSpaces.delete(ev.id);
288
- }
289
-
290
- private handleSpaceJoined(ev: SpaceJoined): void {
291
- this.addJoinedSpaces(ev.space);
292
- }
293
-
294
- private addJoinedSpaces(...spaces: Space[]): void {
295
- this.spacesRoles.set(...(spaces.map(space => [
296
- space.id,
297
- new ObservableIndexedObjectCollection<Role>('id', space.roles)
298
- ]) as [string, ObservableIndexedObjectCollection<Role>][]));
299
- this.joinedSpaces.set(...spaces);
300
- }
301
-
302
- private handleSpaceLeft(ev: SpaceLeft): void {
303
- this.handleSpaceDeleted(ev);
304
- }
305
-
306
- private handleSpaceMemberJoined(ev: SpaceMemberJoined): void {
307
- if (this.spacesMembers.has(ev.spaceId)) {
308
- this.spacesMembers.get(ev.spaceId).set(ev.member);
309
- }
310
- }
311
-
312
- private handleSpaceMemberLeft(ev: SpaceMemberLeft): void {
313
- if (this.spacesMembers.has(ev.spaceId)) {
314
- this.spacesMembers.get(ev.spaceId).delete(ev.userId);
315
- }
316
- }
317
-
318
- private handleSpaceMembers(ev: SpaceMembers): void {
319
- if (!this.spacesMembers.has(ev.id)) {
320
- this.spacesMembers.set([
321
- ev.id,
322
- new ObservableIndexedObjectCollection(member => member?.user.id, ev.members)
323
- ]);
324
- this.deferredGetters.get(`spaces-members-${ev.id}`)?.resolver();
325
- }
326
- }
327
-
328
- private handleSpaceRooms(ev: SpaceRooms): void {
329
- if (!this.spacesRooms.has(ev.id)) {
330
- this.spacesRooms.set([ev.id, new ObservableIndexedObjectCollection('id', ev.summaries)]);
331
- this.deferredGetters.get(`spaces-rooms-${ev.id}`)?.resolver();
332
- }
333
- }
334
-
335
- private handleSpaceMemberUpdate(ev: SpaceMemberUpdate): void {
336
- if (this.spacesMembers.has(ev.spaceId)) {
337
- this.spacesMembers.get(ev.spaceId).set(ev.member);
338
- }
339
- }
340
-
341
- private handleTopicDeleted(ev: TopicDeleted): void {
342
- const collection = this.roomsTopics.get(ev.roomId);
343
- collection.delete(ev.id);
344
- this.joinedRooms.get(ev.roomId).topics = collection.items;
345
- }
346
- }