Skip to content

Commit 913ed92

Browse files
authored
refactor: Improve visibility of sub conversation actions execution by adding logs [WPB-21170] (#7489)
1 parent 28ddfb8 commit 913ed92

File tree

1 file changed

+155
-15
lines changed

1 file changed

+155
-15
lines changed

packages/core/src/conversation/SubconversationService/SubconversationService.ts

Lines changed: 155 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export class SubconversationService extends TypedEventEmitter<Events> {
7373
shouldRetry = true,
7474
): Promise<{groupId: string; epoch: number}> {
7575
try {
76+
this.logger.info('Joining conference subconversation', {conversationId, groupId});
7677
const {
7778
group_id: subconversationGroupId,
7879
epoch: subconversationEpoch,
@@ -113,6 +114,7 @@ export class SubconversationService extends TypedEventEmitter<Events> {
113114

114115
return {groupId: subconversationGroupId, epoch};
115116
} catch (error) {
117+
this.logger.error('Failed to join conference subconversation', {conversationId, groupId, error, shouldRetry});
116118
if (shouldRetry) {
117119
return this.joinConferenceSubconversation(conversationId, groupId, false);
118120
}
@@ -126,34 +128,55 @@ export class SubconversationService extends TypedEventEmitter<Events> {
126128
* @param conversationId Id of the parent conversation which subconversation we want to leave
127129
*/
128130
public async leaveConferenceSubconversation(conversationId: QualifiedId): Promise<void> {
131+
this.logger.info('Leaving conference subconversation', {conversationId});
129132
const subconversationGroupId = await this.getSubconversationGroupId(conversationId, SUBCONVERSATION_ID.CONFERENCE);
130133

131134
if (!subconversationGroupId) {
135+
this.logger.warn('No subconversation groupId found when leaving conference subconversation', {conversationId});
132136
return;
133137
}
134138

135139
const doesGroupExistLocally = await this.mlsService.conversationExists(subconversationGroupId);
136140
if (!doesGroupExistLocally) {
137141
// If the subconversation was known by a client but is does not exist locally, we can remove it from the store.
142+
this.logger.info('Subconversation not found locally; clearing stored mapping', {
143+
conversationId,
144+
subconversationId: SUBCONVERSATION_ID.CONFERENCE,
145+
subconversationGroupId,
146+
});
138147
return this.clearSubconversationGroupId(conversationId, SUBCONVERSATION_ID.CONFERENCE);
139148
}
140149

141150
try {
142151
await this.apiClient.api.conversation.deleteSubconversationSelf(conversationId, SUBCONVERSATION_ID.CONFERENCE);
143152
} catch (error) {
144-
this.logger.error(`Failed to leave conference subconversation:`, error);
153+
this.logger.error('Failed to leave conference subconversation', {
154+
conversationId,
155+
subconversationId: SUBCONVERSATION_ID.CONFERENCE,
156+
subconversationGroupId,
157+
error,
158+
});
145159
}
146160

147161
await this.mlsService.wipeConversation(subconversationGroupId);
148162

149163
// once we've left the subconversation, we can remove it from the store
164+
this.logger.info('Clearing stored mapping after leaving conference subconversation', {
165+
conversationId,
166+
subconversationId: SUBCONVERSATION_ID.CONFERENCE,
167+
subconversationGroupId,
168+
});
150169
await this.clearSubconversationGroupId(conversationId, SUBCONVERSATION_ID.CONFERENCE);
151170
}
152171

153172
public async leaveStaleConferenceSubconversations(): Promise<void> {
173+
this.logger.info('Leaving all stale conference subconversations');
154174
const conversationIds = await this.getAllGroupIdsBySubconversationId(SUBCONVERSATION_ID.CONFERENCE);
155175

156176
for (const {parentConversationId} of conversationIds) {
177+
this.logger.debug('Leaving stale conference subconversation for parent conversation', {
178+
parentConversationId,
179+
});
157180
await this.leaveConferenceSubconversation(parentConversationId);
158181
}
159182
}
@@ -168,38 +191,55 @@ export class SubconversationService extends TypedEventEmitter<Events> {
168191
secretKey: string;
169192
keyLength: number;
170193
} | null> {
194+
this.logger.info('Getting subconversation epoch info', {
195+
parentConversationId,
196+
parentConversationGroupId,
197+
shouldAdvanceEpoch,
198+
});
171199
const subconversationGroupId = await this.getSubconversationGroupId(
172200
parentConversationId,
173201
SUBCONVERSATION_ID.CONFERENCE,
174202
);
175203

176204
// this method should not be called if the subconversation (and its parent conversation) is not established
177205
if (!subconversationGroupId) {
178-
this.logger.error(
179-
`Could not obtain epoch info for conference subconversation of conversation ${JSON.stringify(
180-
parentConversationId,
181-
)}: parent or subconversation group ID is missing`,
182-
);
206+
this.logger.error('Could not obtain epoch info for conference subconversation: missing groupId', {
207+
parentConversationId,
208+
});
183209

184210
return null;
185211
}
186212

187213
//we don't want to react to avs callbacks when conversation was not yet established
188214
const doesMLSGroupExist = await this.mlsService.conversationExists(subconversationGroupId);
189215
if (!doesMLSGroupExist) {
216+
this.logger.debug('Subconversation MLS group does not exist locally; skipping epoch info', {
217+
parentConversationId,
218+
parentConversationGroupId,
219+
subconversationGroupId,
220+
});
190221
return null;
191222
}
192223

193224
const members = await this.generateSubconversationMembers(subconversationGroupId, parentConversationGroupId);
194225

195226
if (shouldAdvanceEpoch) {
227+
this.logger.info('Advancing epoch and renewing key material for subconversation', {subconversationGroupId});
196228
await this.mlsService.renewKeyMaterial(subconversationGroupId);
197229
}
198230

199231
const epoch = Number(await this.mlsService.getEpoch(subconversationGroupId));
200232

201233
const secretKey = await this.mlsService.exportSecretKey(subconversationGroupId, MLS_CONVERSATION_KEY_LENGTH);
202234

235+
this.logger.debug('Obtained subconversation epoch info', {
236+
parentConversationId,
237+
parentConversationGroupId,
238+
subconversationGroupId,
239+
epoch,
240+
membersCount: members.length,
241+
keyLength: MLS_CONVERSATION_KEY_LENGTH,
242+
});
203243
return {members, epoch, keyLength: MLS_CONVERSATION_KEY_LENGTH, secretKey};
204244
}
205245

@@ -214,16 +254,22 @@ export class SubconversationService extends TypedEventEmitter<Events> {
214254
keyLength: number;
215255
}) => void,
216256
): Promise<() => void> {
257+
this.logger.info('Subscribing to subconversation epoch updates', {
258+
parentConversationId,
259+
parentConversationGroupId,
260+
});
217261
const {epoch: initialEpoch, groupId: subconversationGroupId} = await this.joinConferenceSubconversation(
218262
parentConversationId,
219263
parentConversationGroupId,
220264
);
221265

222266
const forwardNewEpoch = async ({groupId}: {groupId: string; epoch: number}) => {
267+
this.logger.debug('Received MLS NEW_EPOCH event', {eventGroupId: groupId, subconversationGroupId});
223268
if (groupId !== subconversationGroupId) {
224269
// if the epoch update did not happen in the subconversation directly, check if it happened in the parent conversation
225270
const parentConversationId = findConversationByGroupId(groupId);
226271
if (!parentConversationId) {
272+
this.logger.debug('Ignoring NEW_EPOCH event: could not map to parent conversation');
227273
return;
228274
}
229275

@@ -234,6 +280,11 @@ export class SubconversationService extends TypedEventEmitter<Events> {
234280

235281
// if the conference subconversation of parent conversation is not known, ignore the epoch update
236282
if (foundSubconversationGroupId !== subconversationGroupId) {
283+
this.logger.debug('Ignoring NEW_EPOCH event: not related to subscribed subconversation', {
284+
eventGroupId: groupId,
285+
foundSubconversationGroupId,
286+
expectedSubconversationGroupId: subconversationGroupId,
287+
});
237288
return;
238289
}
239290
}
@@ -244,11 +295,19 @@ export class SubconversationService extends TypedEventEmitter<Events> {
244295
);
245296

246297
if (!subconversationEpochInfo) {
298+
this.logger.debug('No subconversation epoch info available; skipping callback', {
299+
parentConversationId,
300+
parentConversationGroupId,
301+
});
247302
return;
248303
}
249304

250305
const newSubconversationEpoch = Number(await this.mlsService.getEpoch(subconversationGroupId));
251306

307+
this.logger.info('Forwarding epoch update to subscriber', {
308+
subconversationGroupId,
309+
epoch: newSubconversationEpoch,
310+
});
252311
return onEpochUpdate({
253312
...subconversationEpochInfo,
254313
epoch: newSubconversationEpoch,
@@ -259,21 +318,32 @@ export class SubconversationService extends TypedEventEmitter<Events> {
259318

260319
await forwardNewEpoch({groupId: subconversationGroupId, epoch: initialEpoch});
261320

321+
this.logger.info('Subscribed to MLS NEW_EPOCH events for subconversation', {subconversationGroupId});
262322
return () => this.mlsService.off(MLSServiceEvents.NEW_EPOCH, forwardNewEpoch);
263323
}
264324

265325
public async removeClientFromConferenceSubconversation(
266326
conversationId: QualifiedId,
267327
clientToRemove: {user: QualifiedId; clientId: string},
268328
): Promise<void> {
329+
this.logger.info('Removing client from conference subconversation', {
330+
conversationId,
331+
user: clientToRemove.user,
332+
clientId: clientToRemove.clientId,
333+
});
269334
const subconversationGroupId = await this.getSubconversationGroupId(conversationId, SUBCONVERSATION_ID.CONFERENCE);
270335

271336
if (!subconversationGroupId) {
337+
this.logger.warn('Cannot remove client: subconversation groupId missing', {conversationId});
272338
return;
273339
}
274340

275341
const doesMLSGroupExist = await this.mlsService.conversationExists(subconversationGroupId);
276342
if (!doesMLSGroupExist) {
343+
this.logger.debug('Cannot remove client: subconversation MLS group does not exist locally', {
344+
conversationId,
345+
subconversationGroupId,
346+
});
277347
return;
278348
}
279349

@@ -291,37 +361,84 @@ export class SubconversationService extends TypedEventEmitter<Events> {
291361
);
292362

293363
if (!isSubconversationMember) {
364+
this.logger.info('Client is not a member of the subconversation; nothing to remove', {
365+
conversationId,
366+
subconversationGroupId,
367+
clientToRemoveQualifiedId,
368+
});
294369
return;
295370
}
296371

297-
return void this.mlsService.removeClientsFromConversation(subconversationGroupId, [clientToRemoveQualifiedId]);
372+
this.logger.info('Removing client from subconversation', {
373+
subconversationGroupId,
374+
clientToRemoveQualifiedId,
375+
});
376+
try {
377+
await this.mlsService.removeClientsFromConversation(subconversationGroupId, [clientToRemoveQualifiedId]);
378+
} catch (error) {
379+
this.logger.error('Failed to remove client from subconversation', {
380+
subconversationGroupId,
381+
clientToRemoveQualifiedId,
382+
error,
383+
});
384+
}
298385
}
299386

300387
private async joinSubconversationByExternalCommit(conversationId: QualifiedId, subconversation: SUBCONVERSATION_ID) {
301-
await this.mlsService.joinByExternalCommit(() =>
302-
this.apiClient.api.conversation.getSubconversationGroupInfo(conversationId, subconversation),
303-
);
388+
try {
389+
this.logger.info('Joining subconversation by external commit', {conversationId, subconversation});
390+
await this.mlsService.joinByExternalCommit(() =>
391+
this.apiClient.api.conversation.getSubconversationGroupInfo(conversationId, subconversation),
392+
);
393+
} catch (error) {
394+
this.logger.error('Failed to join subconversation by external commit', {
395+
conversationId,
396+
subconversation,
397+
error,
398+
});
399+
throw error;
400+
}
304401
}
305402

306403
private async getConferenceSubconversation(conversationId: QualifiedId): Promise<Subconversation> {
307-
return this.apiClient.api.conversation.getSubconversation(conversationId, SUBCONVERSATION_ID.CONFERENCE);
404+
this.logger.debug('Fetching conference subconversation metadata', {conversationId});
405+
try {
406+
return await this.apiClient.api.conversation.getSubconversation(conversationId, SUBCONVERSATION_ID.CONFERENCE);
407+
} catch (error) {
408+
this.logger.error('Failed to fetch conference subconversation metadata', {conversationId, error});
409+
throw error;
410+
}
308411
}
309412

310413
private async deleteConferenceSubconversation(
311414
conversationId: QualifiedId,
312415
data: {groupId: string; epoch: number},
313416
): Promise<void> {
314-
return this.apiClient.api.conversation.deleteSubconversation(conversationId, SUBCONVERSATION_ID.CONFERENCE, data);
417+
this.logger.info('Deleting conference subconversation', {conversationId, data});
418+
try {
419+
return await this.apiClient.api.conversation.deleteSubconversation(
420+
conversationId,
421+
SUBCONVERSATION_ID.CONFERENCE,
422+
data,
423+
);
424+
} catch (error) {
425+
this.logger.error('Failed to delete conference subconversation', {conversationId, data, error});
426+
throw error;
427+
}
315428
}
316429

317430
private async generateSubconversationMembers(
318431
subconversationGroupId: string,
319432
parentGroupId: string,
320433
): Promise<SubconversationEpochInfoMember[]> {
434+
this.logger.debug('Generating subconversation members info', {
435+
subconversationGroupId,
436+
parentGroupId,
437+
});
321438
const subconversationMemberIds = await this.mlsService.getClientIds(subconversationGroupId);
322439
const parentMemberIds = await this.mlsService.getClientIds(parentGroupId);
323440

324-
return parentMemberIds.map(parentMember => {
441+
const members = parentMemberIds.map(parentMember => {
325442
const isSubconversationMember = subconversationMemberIds.some(
326443
({userId, clientId, domain}) =>
327444
constructFullyQualifiedClientId(userId, clientId, domain) ===
@@ -336,6 +453,12 @@ export class SubconversationService extends TypedEventEmitter<Events> {
336453
in_subconv: isSubconversationMember,
337454
};
338455
});
456+
this.logger.debug('Generated subconversation members info', {
457+
subconversationGroupId,
458+
parentGroupId,
459+
membersCount: members.length,
460+
});
461+
return members;
339462
}
340463

341464
public getSubconversationGroupId = async (
@@ -346,7 +469,11 @@ export class SubconversationService extends TypedEventEmitter<Events> {
346469
'subconversations',
347470
generateSubconversationStoreKey(parentConversationId, subconversationId),
348471
);
349-
472+
this.logger.debug('Loaded subconversation groupId from store', {
473+
parentConversationId,
474+
subconversationId,
475+
found: Boolean(foundSubconversation?.groupId),
476+
});
350477
return foundSubconversation?.groupId;
351478
};
352479

@@ -359,11 +486,15 @@ export class SubconversationService extends TypedEventEmitter<Events> {
359486
groupId: string;
360487
}[]
361488
> => {
489+
this.logger.debug('Retrieving all subconversations by subconversationId', {subconversationId});
362490
const allSubconversations = await this.coreDatabase.getAll('subconversations');
363491
const foundSubconversations = allSubconversations.filter(
364492
subconversation => subconversation.subconversationId === subconversationId,
365493
);
366-
494+
this.logger.debug('Found subconversations by id', {
495+
subconversationId,
496+
count: foundSubconversations.length,
497+
});
367498
return foundSubconversations;
368499
};
369500

@@ -372,6 +503,11 @@ export class SubconversationService extends TypedEventEmitter<Events> {
372503
subconversationId: SUBCONVERSATION_ID,
373504
groupId: string,
374505
) => {
506+
this.logger.debug('Saving subconversation groupId mapping', {
507+
parentConversationId,
508+
subconversationId,
509+
groupId,
510+
});
375511
return this.coreDatabase.put(
376512
'subconversations',
377513
{parentConversationId, subconversationId, groupId},
@@ -383,6 +519,10 @@ export class SubconversationService extends TypedEventEmitter<Events> {
383519
parentConversationId: QualifiedId,
384520
subconversationId: SUBCONVERSATION_ID,
385521
) => {
522+
this.logger.debug('Clearing subconversation groupId mapping', {
523+
parentConversationId,
524+
subconversationId,
525+
});
386526
return this.coreDatabase.delete(
387527
'subconversations',
388528
generateSubconversationStoreKey(parentConversationId, subconversationId),

0 commit comments

Comments
 (0)