@@ -330,12 +330,6 @@ interface RoomState {
330
330
created? : number ;
331
331
}
332
332
333
- // in addition to acting as a cache, this also ensures we have
334
- // triple equal equivalence for the interior cards of RoomField
335
- const eventCache = initSharedState (
336
- ' eventCache' ,
337
- () => new WeakMap <RoomField , Map <string , MatrixEvent >>(),
338
- );
339
333
const messageCache = initSharedState (
340
334
' messageCache' ,
341
335
() => new WeakMap <RoomField , Map <string , MessageField >>(),
@@ -353,39 +347,34 @@ const fragmentCache = initSharedState(
353
347
() => new WeakMap <RoomField , Map <string , CardFragmentContent >>(),
354
348
);
355
349
350
+ function newEvents(events : () => MatrixEvent []): () => MatrixEvent [] {
351
+ let seen = new Set <string >();
352
+ return function () {
353
+ return events ().filter ((e ) => {
354
+ if (seen .has (e .event_id )) {
355
+ return false ;
356
+ }
357
+ seen .add (e .event_id );
358
+ return true ;
359
+ });
360
+ };
361
+ }
362
+
356
363
export class RoomField extends FieldDef {
357
364
static displayName = ' Room' ;
358
365
359
366
// the only writeable field for this card should be the "events" field.
360
367
// All other fields should derive from the "events" field.
361
368
@field events = containsMany (MatrixEventField );
362
369
363
- // This works well for synchronous computeds only
364
- @field newEvents = containsMany (MatrixEventField , {
365
- computeVia : function (this : RoomField ) {
366
- let cache = eventCache .get (this );
367
- if (! cache ) {
368
- cache = new Map ();
369
- eventCache .set (this , cache );
370
- }
371
- let newEvents = new Map <string , MatrixEvent >();
372
- for (let event of this .events ) {
373
- if (cache .has (event .event_id )) {
374
- continue ;
375
- }
376
- cache .set (event .event_id , event );
377
- newEvents .set (event .event_id , event );
378
- }
379
- return [... newEvents .values ()];
380
- },
381
- });
382
-
383
370
@field roomId = contains (StringField , {
384
371
computeVia : function (this : RoomField ) {
385
372
return this .events .length > 0 ? this .events [0 ].room_id : undefined ;
386
373
},
387
374
});
388
375
376
+ private nameEvents = newEvents (() => this .events );
377
+
389
378
@field name = contains (StringField , {
390
379
computeVia : function (this : RoomField ) {
391
380
let roomState = roomStateCache .get (this );
@@ -394,9 +383,7 @@ export class RoomField extends FieldDef {
394
383
roomStateCache .set (this , roomState );
395
384
}
396
385
397
- // Read from this.events instead of this.newEvents to avoid a race condition bug where
398
- // newEvents never returns the m.room.name while the event is present in events
399
- let events = this .events
386
+ let events = this .nameEvents ()
400
387
.filter ((e ) => e .type === ' m.room.name' )
401
388
.sort (
402
389
(a , b ) => a .origin_server_ts - b .origin_server_ts ,
@@ -409,6 +396,8 @@ export class RoomField extends FieldDef {
409
396
},
410
397
});
411
398
399
+ private creatorEvents = newEvents (() => this .events );
400
+
412
401
@field creator = contains (RoomMemberField , {
413
402
computeVia : function (this : RoomField ) {
414
403
let roomState = roomStateCache .get (this );
@@ -420,9 +409,9 @@ export class RoomField extends FieldDef {
420
409
if (creator ) {
421
410
return creator ;
422
411
}
423
- let event = this .newEvents . find (( e ) => e . type === ' m.room.create ' ) as
424
- | RoomCreateEvent
425
- | undefined ;
412
+ let event = this .creatorEvents (). find (
413
+ ( e ) => e . type === ' m.room.create ' ,
414
+ ) as RoomCreateEvent | undefined ;
426
415
if (event ) {
427
416
roomState .creator = upsertRoomMember ({
428
417
room: this ,
@@ -433,6 +422,8 @@ export class RoomField extends FieldDef {
433
422
},
434
423
});
435
424
425
+ private createdEvents = newEvents (() => this .events );
426
+
436
427
@field created = contains (DateTimeField , {
437
428
computeVia : function (this : RoomField ) {
438
429
let roomState = roomStateCache .get (this );
@@ -444,9 +435,9 @@ export class RoomField extends FieldDef {
444
435
if (created != null ) {
445
436
return new Date (created );
446
437
}
447
- let event = this .newEvents . find (( e ) => e . type === ' m.room.create ' ) as
448
- | RoomCreateEvent
449
- | undefined ;
438
+ let event = this .createdEvents (). find (
439
+ ( e ) => e . type === ' m.room.create ' ,
440
+ ) as RoomCreateEvent | undefined ;
450
441
if (event ) {
451
442
roomState .created = event .origin_server_ts ;
452
443
}
@@ -456,19 +447,23 @@ export class RoomField extends FieldDef {
456
447
},
457
448
});
458
449
450
+ private roomMemberEvents = newEvents (() => this .events );
451
+
459
452
@field roomMembers = containsMany (RoomMemberField , {
460
453
computeVia : function (this : RoomField ) {
454
+ console .log (' computing roomMembers' );
461
455
let roomMembers = roomMemberCache .get (this );
462
456
if (! roomMembers ) {
463
457
roomMembers = new Map ();
464
458
roomMemberCache .set (this , roomMembers );
465
459
}
466
460
467
- for (let event of this .newEvents ) {
461
+ for (let event of this .roomMemberEvents () ) {
468
462
if (event .type !== ' m.room.member' ) {
469
463
continue ;
470
464
}
471
465
let userId = event .state_key ;
466
+ console .log (' upsertRoomMember' );
472
467
upsertRoomMember ({
473
468
room: this ,
474
469
userId ,
@@ -482,6 +477,8 @@ export class RoomField extends FieldDef {
482
477
},
483
478
});
484
479
480
+ private messageEvents = newEvents (() => this .events );
481
+
485
482
@field messages = containsMany (MessageField , {
486
483
// since we are rendering this card without the isolated renderer, we cannot use
487
484
// the rendering mechanism to test if a field is used or not, so we explicitely
@@ -502,8 +499,7 @@ export class RoomField extends FieldDef {
502
499
messageCache .set (this , cache );
503
500
}
504
501
let index = cache .size ;
505
- let newMessages = new Map <string , MessageField >();
506
- for (let event of this .events ) {
502
+ for (let event of this .messageEvents ()) {
507
503
if (event .type !== ' m.room.message' ) {
508
504
continue ;
509
505
}
@@ -611,26 +607,17 @@ export class RoomField extends FieldDef {
611
607
if (messageField ) {
612
608
// if the message is a replacement for other messages,
613
609
// use `created` from the oldest one.
614
- if (newMessages .has (event_id )) {
615
- messageField .created = newMessages .get (event_id )! .created ;
610
+ if (cache .has (event_id )) {
611
+ messageField .created = cache .get (event_id )! .created ;
616
612
}
617
- newMessages .set (
613
+ cache .set (
618
614
(event .content as CardMessageContent ).clientGeneratedId ?? event_id ,
619
615
messageField ,
620
616
);
621
617
index ++ ;
622
618
}
623
619
}
624
620
625
- // update the cache with the new messages
626
- for (let [id, message] of newMessages ) {
627
- // The `id` can either be an `eventId` or `clientGeneratedId`.
628
- // For messages sent by the user, we prefer to use `clientGeneratedId`
629
- // because `eventId` can change in certain scenarios,
630
- // such as when resending a failed message or updating its status from sending to sent.
631
- cache .set (id , message );
632
- }
633
-
634
621
// this sort should hopefully be very optimized since events will
635
622
// be close to chronological order
636
623
return [... cache .values ()].sort (
@@ -641,12 +628,16 @@ export class RoomField extends FieldDef {
641
628
642
629
@field joinedMembers = containsMany (RoomMemberField , {
643
630
computeVia : function (this : RoomField ) {
631
+ console .log (' computing joinedMembers' );
632
+ console .log (' this.roomMembers' , this .roomMembers );
644
633
return this .roomMembers .filter ((m ) => m .membership === ' join' );
645
634
},
646
635
});
647
636
648
637
@field invitedMembers = containsMany (RoomMemberField , {
649
638
computeVia : function (this : RoomField ) {
639
+ console .log (' computing invitedMembers' );
640
+ console .log (' this.roomMembers' , this .roomMembers );
650
641
return this .roomMembers .filter ((m ) => m .membership === ' invite' );
651
642
},
652
643
});
0 commit comments