blob: 773b298f2e14e7aa237059c4ab2fe62ac6a568a1 [file] [log] [blame]
Issam E. Maghnif796a092022-10-09 20:25:26 +00001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
Misha Krieger-Raynauldb933fbb2022-11-15 15:11:09 -050018import { createRequire } from 'node:module';
19
Issam E. Maghni0432cb72022-11-12 06:09:26 +000020import {
21 AccountDetails,
22 AccountTextMessage,
23 ConversationMessage,
24 Message,
25 VolatileDetails,
26 WebSocketMessage,
27 WebSocketMessageType,
28} from 'jami-web-common';
Issam E. Maghnif796a092022-10-09 20:25:26 +000029import log from 'loglevel';
Misha Krieger-Raynauld6f9c7ae2022-10-28 11:41:45 -040030import { filter, firstValueFrom, map, Subject } from 'rxjs';
Issam E. Maghnif796a092022-10-09 20:25:26 +000031import { Service } from 'typedi';
32
Misha Krieger-Raynauldb933fbb2022-11-15 15:11:09 -050033import { WebSocketServer } from '../websocket/websocket-server.js';
Misha Krieger-Raynauldaddd6fe2022-10-22 12:46:04 -040034import { JamiSignal } from './jami-signal.js';
35import {
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -040036 AccountDetailsChanged,
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -050037 AccountMessageStatusChanged,
38 ContactAdded,
39 ContactRemoved,
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -040040 ConversationLoaded,
41 ConversationReady,
42 ConversationRemoved,
Charlieb62c6782022-10-30 15:14:56 -040043 IncomingAccountMessage,
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -040044 KnownDevicesChanged,
45 MessageReceived,
Misha Krieger-Raynauldaddd6fe2022-10-22 12:46:04 -040046 NameRegistrationEnded,
47 RegisteredNameFound,
48 RegistrationStateChanged,
49 VolatileDetailsChanged,
50} from './jami-signal-interfaces.js';
Misha Krieger-Raynauldbfed1732022-11-01 20:49:35 -040051import { JamiSwig, StringMap, stringMapToRecord, stringVectToArray, vectMapToRecordArray } from './jami-swig.js';
Issam E. Maghnif796a092022-10-09 20:25:26 +000052
Misha Krieger-Raynauldb933fbb2022-11-15 15:11:09 -050053const require = createRequire(import.meta.url);
54
Misha Krieger-Raynauldbfed1732022-11-01 20:49:35 -040055// TODO: Convert Records to interfaces and replace them in common/ (e.g. Contact)
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -040056
Issam E. Maghnif796a092022-10-09 20:25:26 +000057@Service()
58export class Jamid {
Misha Krieger-Raynauldb933fbb2022-11-15 15:11:09 -050059 private jamiSwig: JamiSwig;
60 private usernamesToAccountIds = new Map<string, string>();
Issam E. Maghnif796a092022-10-09 20:25:26 +000061 private readonly events;
62
Misha Krieger-Raynauldb933fbb2022-11-15 15:11:09 -050063 constructor(private webSocketServer: WebSocketServer) {
64 this.jamiSwig = require('../../jamid.node') as JamiSwig;
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -040065
66 // Setup signal handlers
Issam E. Maghnif796a092022-10-09 20:25:26 +000067 const handlers: Record<string, unknown> = {};
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -040068
69 // Add default handler for all signals
70 const createDefaultHandler = (signal: string) => {
71 return (...args: unknown[]) => log.warn('Unhandled', signal, args);
Issam E. Maghnif796a092022-10-09 20:25:26 +000072 };
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -040073 for (const signal in JamiSignal) {
74 handlers[signal] = createDefaultHandler(signal);
75 }
76
77 // Overwrite handlers for handled signals using RxJS Subjects, converting multiple arguments to objects
78 const onAccountsChanged = new Subject<void>();
79 handlers.AccountsChanged = () => onAccountsChanged.next();
80
81 const onAccountDetailsChanged = new Subject<AccountDetailsChanged>();
82 handlers.AccountDetailsChanged = (accountId: string, details: AccountDetails) =>
83 onAccountDetailsChanged.next({ accountId, details });
Issam E. Maghnif796a092022-10-09 20:25:26 +000084
85 const onVolatileDetailsChanged = new Subject<VolatileDetailsChanged>();
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -040086 handlers.VolatileDetailsChanged = (accountId: string, details: VolatileDetails) =>
87 onVolatileDetailsChanged.next({ accountId, details });
Issam E. Maghnif796a092022-10-09 20:25:26 +000088
89 const onRegistrationStateChanged = new Subject<RegistrationStateChanged>();
90 handlers.RegistrationStateChanged = (accountId: string, state: string, code: number, details: string) =>
91 onRegistrationStateChanged.next({ accountId, state, code, details });
92
93 const onNameRegistrationEnded = new Subject<NameRegistrationEnded>();
94 handlers.NameRegistrationEnded = (accountId: string, state: number, username: string) =>
95 onNameRegistrationEnded.next({ accountId, state, username });
96
97 const onRegisteredNameFound = new Subject<RegisteredNameFound>();
98 handlers.RegisteredNameFound = (accountId: string, state: number, address: string, username: string) =>
99 onRegisteredNameFound.next({ accountId, state, address, username });
100
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400101 const onKnownDevicesChanged = new Subject<KnownDevicesChanged>();
102 handlers.KnownDevicesChanged = (accountId: string, devices: Record<string, string>) =>
103 onKnownDevicesChanged.next({ accountId, devices });
104
Charlieb62c6782022-10-30 15:14:56 -0400105 const onIncomingAccountMessage = new Subject<IncomingAccountMessage>();
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -0500106 handlers.IncomingAccountMessage = (accountId: string, from: string, payload: Record<string, string>) =>
107 onIncomingAccountMessage.next({ accountId, from, payload });
108
109 const onAccountMessageStatusChanged = new Subject<AccountMessageStatusChanged>();
110 handlers.AccountMessageStatusChanged = (accountId: string, messageId: string, peer: string, state: number) =>
111 onAccountMessageStatusChanged.next({ accountId, messageId, peer, state });
112
113 const onContactAdded = new Subject<ContactAdded>();
114 handlers.ContactAdded = (accountId: string, contactId: string, confirmed: boolean) =>
115 onContactAdded.next({ accountId, contactId, confirmed });
116
117 const onContactRemoved = new Subject<ContactRemoved>();
118 handlers.ContactRemoved = (accountId: string, contactId: string, banned: boolean) =>
119 onContactRemoved.next({ accountId, contactId, banned });
Charlieb62c6782022-10-30 15:14:56 -0400120
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400121 const onConversationReady = new Subject<ConversationReady>();
122 handlers.ConversationReady = (accountId: string, conversationId: string) =>
123 onConversationReady.next({ accountId, conversationId });
124
125 const onConversationRemoved = new Subject<ConversationRemoved>();
126 handlers.ConversationRemoved = (accountId: string, conversationId: string) =>
127 onConversationRemoved.next({ accountId, conversationId });
128
129 const onConversationLoaded = new Subject<ConversationLoaded>();
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400130 handlers.ConversationLoaded = (id: number, accountId: string, conversationId: string, messages: Message[]) =>
131 onConversationLoaded.next({ id, accountId, conversationId, messages });
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400132
133 const onMessageReceived = new Subject<MessageReceived>();
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400134 handlers.MessageReceived = (accountId: string, conversationId: string, message: Message) =>
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400135 onMessageReceived.next({ accountId, conversationId, message });
136
137 // Expose all signals in an events object to allow other handlers to subscribe after jamiSwig.init()
Issam E. Maghnif796a092022-10-09 20:25:26 +0000138 this.events = {
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400139 onAccountsChanged: onAccountsChanged.asObservable(),
140 onAccountDetailsChanged: onAccountDetailsChanged.asObservable(),
Issam E. Maghnif796a092022-10-09 20:25:26 +0000141 onVolatileDetailsChanged: onVolatileDetailsChanged.asObservable(),
142 onRegistrationStateChanged: onRegistrationStateChanged.asObservable(),
143 onNameRegistrationEnded: onNameRegistrationEnded.asObservable(),
144 onRegisteredNameFound: onRegisteredNameFound.asObservable(),
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400145 onKnownDevicesChanged: onKnownDevicesChanged.asObservable(),
Charlieb62c6782022-10-30 15:14:56 -0400146 onIncomingAccountMessage: onIncomingAccountMessage.asObservable(),
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -0500147 onAccountMessageStatusChanged: onAccountMessageStatusChanged.asObservable(),
148 onContactAdded: onContactAdded.asObservable(),
149 onContactRemoved: onContactRemoved.asObservable(),
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400150 onConversationReady: onConversationReady.asObservable(),
151 onConversationRemoved: onConversationRemoved.asObservable(),
152 onConversationLoaded: onConversationLoaded.asObservable(),
153 onMessageReceived: onMessageReceived.asObservable(),
Issam E. Maghnif796a092022-10-09 20:25:26 +0000154 };
155
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400156 this.setupSignalHandlers();
Issam E. Maghnif796a092022-10-09 20:25:26 +0000157
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400158 // RxJS Subjects are used as signal handlers for the following reasons:
159 // 1. You cannot change event handlers after calling jamiSwig.init()
Issam E. Maghnif796a092022-10-09 20:25:26 +0000160 // 2. You cannot specify multiple handlers for the same event
161 // 3. You cannot specify a default handler
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400162 this.jamiSwig.init(handlers);
Issam E. Maghnif796a092022-10-09 20:25:26 +0000163 }
164
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400165 stop(): void {
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400166 this.jamiSwig.fini();
Misha Krieger-Raynauld62a0da92022-10-22 13:46:59 -0400167 }
168
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400169 getVolatileAccountDetails(accountId: string): VolatileDetails {
170 return stringMapToRecord(this.jamiSwig.getVolatileAccountDetails(accountId)) as unknown as VolatileDetails;
Issam E. Maghnif796a092022-10-09 20:25:26 +0000171 }
172
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400173 getAccountDetails(accountId: string): AccountDetails {
174 return stringMapToRecord(this.jamiSwig.getAccountDetails(accountId)) as unknown as AccountDetails;
175 }
Issam E. Maghnif796a092022-10-09 20:25:26 +0000176
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400177 setAccountDetails(accountId: string, accountDetails: AccountDetails): void {
simon43da57b2022-10-26 18:22:22 -0400178 const accountDetailsStringMap: StringMap = new this.jamiSwig.StringMap();
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400179 for (const [key, value] of Object.entries(accountDetails)) {
180 accountDetailsStringMap.set(key, value);
181 }
182 this.jamiSwig.setAccountDetails(accountId, accountDetailsStringMap);
183 }
Issam E. Maghnif796a092022-10-09 20:25:26 +0000184
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400185 async addAccount(details: Map<string, string | number | boolean>): Promise<string> {
simon43da57b2022-10-26 18:22:22 -0400186 const detailsStringMap: StringMap = new this.jamiSwig.StringMap();
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400187
188 detailsStringMap.set('Account.type', 'RING');
189 for (const [key, value] of details.entries()) {
190 detailsStringMap.set('Account.' + key, value.toString());
191 }
192
193 const accountId = this.jamiSwig.addAccount(detailsStringMap);
Issam E. Maghnif796a092022-10-09 20:25:26 +0000194 return firstValueFrom(
195 this.events.onRegistrationStateChanged.pipe(
Misha Krieger-Raynauld6f9c7ae2022-10-28 11:41:45 -0400196 filter((value) => value.accountId === accountId),
Issam E. Maghnif796a092022-10-09 20:25:26 +0000197 // TODO: is it the only state?
Misha Krieger-Raynauld6f9c7ae2022-10-28 11:41:45 -0400198 // TODO: Replace with string enum in common/
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400199 filter((value) => value.state === 'REGISTERED'),
200 map((value) => value.accountId)
Issam E. Maghnif796a092022-10-09 20:25:26 +0000201 )
202 );
203 }
204
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400205 removeAccount(accountId: string): void {
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400206 this.jamiSwig.removeAccount(accountId);
Issam E. Maghnif796a092022-10-09 20:25:26 +0000207 }
208
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400209 getAccountIds(): string[] {
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400210 return stringVectToArray(this.jamiSwig.getAccountList());
Issam E. Maghnif796a092022-10-09 20:25:26 +0000211 }
212
Charlie2bc0d672022-11-04 11:53:44 -0400213 sendAccountTextMessage(from: string, to: string, message: string): void {
Charlieb62c6782022-10-30 15:14:56 -0400214 const messageStringMap: StringMap = new this.jamiSwig.StringMap();
Charlie2bc0d672022-11-04 11:53:44 -0400215 messageStringMap.set('application/json', message);
216 this.jamiSwig.sendAccountTextMessage(from, to, messageStringMap);
Charlieb62c6782022-10-30 15:14:56 -0400217 }
218
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400219 // TODO: Add interface for returned type
Misha Krieger-Raynauld6f9c7ae2022-10-28 11:41:45 -0400220 async lookupUsername(username: string, accountId?: string) {
221 const hasRingNs = this.jamiSwig.lookupName(accountId || '', '', username);
Issam E. Maghnif796a092022-10-09 20:25:26 +0000222 if (!hasRingNs) {
Issam E. Maghnif796a092022-10-09 20:25:26 +0000223 throw new Error('Jami does not have NS');
224 }
Misha Krieger-Raynauld6f9c7ae2022-10-28 11:41:45 -0400225 return firstValueFrom(
226 this.events.onRegisteredNameFound.pipe(
227 filter((value) => value.username === username),
228 map(({ accountId: _, ...response }) => response) // Remove accountId from response
229 )
230 );
231 }
232
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400233 // TODO: Add interface for returned type
Misha Krieger-Raynauld6f9c7ae2022-10-28 11:41:45 -0400234 async lookupAddress(address: string, accountId?: string) {
235 const hasRingNs = this.jamiSwig.lookupAddress(accountId || '', '', address);
236 if (!hasRingNs) {
237 throw new Error('Jami does not have NS');
238 }
239 return firstValueFrom(
240 this.events.onRegisteredNameFound.pipe(
241 filter((value) => value.address === address),
242 map(({ accountId: _, ...response }) => response) // Remove accountId from response
243 )
244 );
Issam E. Maghnif796a092022-10-09 20:25:26 +0000245 }
246
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400247 // TODO: Create enum for state and return that rather than a number
248 async registerUsername(accountId: string, username: string, password: string): Promise<number> {
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400249 const hasRingNs = this.jamiSwig.registerName(accountId, password, username);
250 if (!hasRingNs) {
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400251 throw new Error('Jami does not have NS');
252 }
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400253 return firstValueFrom(
254 this.events.onNameRegistrationEnded.pipe(
255 filter((value) => value.accountId === accountId),
256 map((value) => value.state)
257 )
258 );
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400259 }
260
261 getDevices(accountId: string): Record<string, string> {
262 return stringMapToRecord(this.jamiSwig.getKnownRingDevices(accountId));
263 }
264
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400265 addContact(accountId: string, contactId: string): void {
Misha Krieger-Raynauldbfed1732022-11-01 20:49:35 -0400266 this.jamiSwig.addContact(accountId, contactId);
267 }
268
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400269 removeContact(accountId: string, contactId: string): void {
Misha Krieger-Raynauldbfed1732022-11-01 20:49:35 -0400270 this.jamiSwig.removeContact(accountId, contactId, false);
271 }
272
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400273 blockContact(accountId: string, contactId: string): void {
Misha Krieger-Raynauldbfed1732022-11-01 20:49:35 -0400274 this.jamiSwig.removeContact(accountId, contactId, true);
275 }
276
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400277 // TODO: Replace Record with interface
Misha Krieger-Raynauldbfed1732022-11-01 20:49:35 -0400278 getContacts(accountId: string): Record<string, string>[] {
279 return vectMapToRecordArray(this.jamiSwig.getContacts(accountId));
280 }
281
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400282 // TODO: Replace Record with interface
Misha Krieger-Raynauldbfed1732022-11-01 20:49:35 -0400283 getContactDetails(accountId: string, contactId: string): Record<string, string> {
284 return stringMapToRecord(this.jamiSwig.getContactDetails(accountId, contactId));
285 }
286
Misha Krieger-Raynauld153a1482022-11-05 12:00:41 -0400287 getDefaultModeratorUris(accountId: string): string[] {
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400288 return stringVectToArray(this.jamiSwig.getDefaultModerators(accountId));
289 }
290
Misha Krieger-Raynauld153a1482022-11-05 12:00:41 -0400291 addDefaultModerator(accountId: string, contactId: string): void {
292 this.jamiSwig.setDefaultModerator(accountId, contactId, true);
293 }
294
295 removeDefaultModerator(accountId: string, contactId: string): void {
296 this.jamiSwig.setDefaultModerator(accountId, contactId, false);
297 }
298
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400299 getConversationIds(accountId: string): string[] {
300 return stringVectToArray(this.jamiSwig.getConversations(accountId));
301 }
302
303 // TODO: Replace Record with interface
304 getConversationInfos(accountId: string, conversationId: string): Record<string, string> {
305 return stringMapToRecord(this.jamiSwig.conversationInfos(accountId, conversationId));
306 }
307
308 // TODO: Replace Record with interface
309 getConversationMembers(accountId: string, conversationId: string): Record<string, string>[] {
310 return vectMapToRecordArray(this.jamiSwig.getConversationMembers(accountId, conversationId));
311 }
312
313 async getConversationMessages(accountId: string, conversationId: string, fromMessage?: string): Promise<Message[]> {
314 const requestId = this.jamiSwig.loadConversationMessages(accountId, conversationId, fromMessage || '', 32);
315 return firstValueFrom(
316 this.events.onConversationLoaded.pipe(
317 filter((value) => value.id === requestId),
318 map((value) => value.messages)
319 )
320 );
321 }
322
323 sendConversationMessage(accountId: string, conversationId: string, message: string, replyTo?: string): void {
324 this.jamiSwig.sendMessage(accountId, conversationId, message, replyTo || '');
325 }
326
Misha Krieger-Raynauld7f959332022-11-04 15:12:53 -0400327 getCallIds(accountId: string): string[] {
328 return stringVectToArray(this.jamiSwig.getCallList(accountId));
329 }
330
331 // TODO: Replace Record with interface
332 getCallDetails(accountId: string, callId: string): Record<string, string> {
333 return stringMapToRecord(this.jamiSwig.getCallDetails(accountId, callId));
334 }
335
Misha Krieger-Raynauldb6f1c322022-10-23 20:42:57 -0400336 getAccountIdFromUsername(username: string): string | undefined {
337 return this.usernamesToAccountIds.get(username);
Issam E. Maghnif796a092022-10-09 20:25:26 +0000338 }
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400339
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400340 private setupSignalHandlers(): void {
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400341 this.events.onAccountsChanged.subscribe(() => {
342 log.debug('Received AccountsChanged');
343 });
344
345 this.events.onAccountDetailsChanged.subscribe((signal) => {
346 log.debug('Received AccountsDetailsChanged', JSON.stringify(signal));
347 });
348
349 this.events.onVolatileDetailsChanged.subscribe(({ accountId, details }) => {
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400350 const username = details['Account.registeredName'];
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400351 log.debug(
352 `Received VolatileDetailsChanged: {"accountId":"${accountId}",` +
353 `"details":{"Account.registeredName":"${username}", ...}}`
354 );
355 // Keep map of usernames to account IDs
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400356 if (username) {
357 this.usernamesToAccountIds.set(username, accountId);
358 }
359 });
360
361 this.events.onRegistrationStateChanged.subscribe((signal) => {
362 log.debug('Received RegistrationStateChanged:', JSON.stringify(signal));
363 });
364
365 this.events.onNameRegistrationEnded.subscribe((signal) => {
366 log.debug('Received NameRegistrationEnded:', JSON.stringify(signal));
367 });
368
369 this.events.onRegisteredNameFound.subscribe((signal) => {
370 log.debug('Received RegisteredNameFound:', JSON.stringify(signal));
371 });
372
373 this.events.onKnownDevicesChanged.subscribe(({ accountId }) => {
374 log.debug(`Received KnownDevicesChanged: {"accountId":"${accountId}", ...}`);
375 });
376
377 this.events.onIncomingAccountMessage.subscribe((signal) => {
378 log.debug('Received IncomingAccountMessage:', JSON.stringify(signal));
Issam E. Maghni0432cb72022-11-12 06:09:26 +0000379 const message: WebSocketMessage<any> = JSON.parse(signal.payload['application/json']);
Charlie2bc0d672022-11-04 11:53:44 -0400380
381 if (message === undefined) {
Misha Krieger-Raynauldb933fbb2022-11-15 15:11:09 -0500382 log.warn('Undefined account message');
383 return;
384 }
385
386 if (message.type === undefined || message.data === undefined) {
387 log.warn('Account message is not a valid WebSocketMessage (missing type or data fields)');
Charlie2bc0d672022-11-04 11:53:44 -0400388 return;
389 }
390
391 if (!Object.values(WebSocketMessageType).includes(message.type)) {
Misha Krieger-Raynauldb933fbb2022-11-15 15:11:09 -0500392 log.warn(`Invalid WebSocket message type: ${message.type}`);
Charlie2bc0d672022-11-04 11:53:44 -0400393 return;
394 }
395
Issam E. Maghni0432cb72022-11-12 06:09:26 +0000396 const data: AccountTextMessage<unknown> = {
397 from: signal.from,
398 to: signal.accountId,
399 message: message.data.message,
400 };
Issam E. Maghni0432cb72022-11-12 06:09:26 +0000401
Misha Krieger-Raynauldb933fbb2022-11-15 15:11:09 -0500402 this.webSocketServer.send(signal.accountId, message.type, data);
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400403 });
404
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -0500405 this.events.onAccountMessageStatusChanged.subscribe((signal) => {
406 log.debug('Received AccountMessageStatusChanged:', JSON.stringify(signal));
407 });
408
409 this.events.onContactAdded.subscribe((signal) => {
410 log.debug('Received ContactAdded:', JSON.stringify(signal));
411 });
412
413 this.events.onContactRemoved.subscribe((signal) => {
414 log.debug('Received ContactRemoved:', JSON.stringify(signal));
415 });
416
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400417 this.events.onConversationReady.subscribe((signal) => {
418 log.debug('Received ConversationReady:', JSON.stringify(signal));
419 });
420
421 this.events.onConversationRemoved.subscribe((signal) => {
422 log.debug('Received ConversationRemoved:', JSON.stringify(signal));
423 });
424
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400425 this.events.onConversationLoaded.subscribe(({ id, accountId, conversationId }) => {
426 log.debug(
427 `Received ConversationLoaded: {"id":"${id}","accountId":"${accountId}",` +
428 `"conversationId":"${conversationId}","messages":[...]}`
429 );
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400430 });
431
432 this.events.onMessageReceived.subscribe((signal) => {
433 log.debug('Received MessageReceived:', JSON.stringify(signal));
Issam E. Maghni0432cb72022-11-12 06:09:26 +0000434 const data: ConversationMessage = {
435 conversationId: signal.conversationId,
436 message: signal.message,
437 };
Misha Krieger-Raynauldb933fbb2022-11-15 15:11:09 -0500438 this.webSocketServer.send(signal.accountId, WebSocketMessageType.ConversationMessage, data);
Misha Krieger-Raynauld68a9b562022-10-28 19:47:46 -0400439 });
440 }
Issam E. Maghnif796a092022-10-09 20:25:26 +0000441}