@@ -34,6 +34,7 @@ import {
3434 type IMembershipManager ,
3535 type MembershipManagerEventHandlerMap ,
3636} from "./IMembershipManager.ts" ;
37+ import { type EmptyObject } from "src/matrix.ts" ;
3738
3839/* MembershipActionTypes:
3940
@@ -77,6 +78,8 @@ On Leave: ───────── STOP ALL ABOVE
7778(s) Successful restart/resend
7879*/
7980
81+ const STICK_DURATION_MS = 60 * 60 * 1000 ; // 60 minutes
82+
8083/**
8184 * The different types of actions the MembershipManager can take.
8285 * @internal
@@ -295,9 +298,9 @@ export class MembershipManager
295298 MatrixClient ,
296299 | "getUserId"
297300 | "getDeviceId"
298- | "sendStateEvent"
299- | "_unstable_sendDelayedStateEvent"
300301 | "_unstable_updateDelayedEvent"
302+ | "_unstable_sendStickyEvent"
303+ | "_unstable_sendStickyDelayedEvent"
301304 > ,
302305 private getOldestMembership : ( ) => CallMembership | undefined ,
303306 public readonly sessionDescription : SessionDescription ,
@@ -371,7 +374,11 @@ export class MembershipManager
371374 return this . joinConfig ?. membershipEventExpiryHeadroomMs ?? 5_000 ;
372375 }
373376 private computeNextExpiryActionTs ( iteration : number ) : number {
374- return this . state . startTime + this . membershipEventExpiryMs * iteration - this . membershipEventExpiryHeadroomMs ;
377+ return (
378+ this . state . startTime +
379+ Math . min ( this . membershipEventExpiryMs , STICK_DURATION_MS ) * iteration -
380+ this . membershipEventExpiryHeadroomMs
381+ ) ;
375382 }
376383 private get delayedLeaveEventDelayMs ( ) : number {
377384 return this . delayedLeaveEventDelayMsOverride ?? this . joinConfig ?. delayedLeaveEventDelayMs ?? 8_000 ;
@@ -450,14 +457,15 @@ export class MembershipManager
450457 // (Another client could have canceled it, the homeserver might have removed/lost it due to a restart, ...)
451458 // In the `then` and `catch` block we treat both cases differently. "if (this.state.hasMemberStateEvent) {} else {}"
452459 return await this . client
453- . _unstable_sendDelayedStateEvent (
460+ . _unstable_sendStickyDelayedEvent (
454461 this . room . roomId ,
462+ STICK_DURATION_MS ,
455463 {
456464 delay : this . delayedLeaveEventDelayMs ,
457465 } ,
466+ null ,
458467 EventType . GroupCallMemberPrefix ,
459- { } , // leave event
460- this . stateKey ,
468+ { sticky_key : this . stateKey } as EmptyObject & { sticky_key : string } , // leave event
461469 )
462470 . then ( ( response ) => {
463471 this . state . expectedServerDelayLeaveTs = Date . now ( ) + this . delayedLeaveEventDelayMs ;
@@ -482,7 +490,7 @@ export class MembershipManager
482490 if ( this . manageMaxDelayExceededSituation ( e ) ) {
483491 return createInsertActionUpdate ( repeatActionType ) ;
484492 }
485- const update = this . actionUpdateFromErrors ( e , repeatActionType , "sendDelayedStateEvent " ) ;
493+ const update = this . actionUpdateFromErrors ( e , repeatActionType , "_unstable_sendStickyDelayedEvent " ) ;
486494 if ( update ) return update ;
487495
488496 if ( this . state . hasMemberStateEvent ) {
@@ -640,12 +648,10 @@ export class MembershipManager
640648
641649 private async sendJoinEvent ( ) : Promise < ActionUpdate > {
642650 return await this . client
643- . sendStateEvent (
644- this . room . roomId ,
645- EventType . GroupCallMemberPrefix ,
646- this . makeMyMembership ( this . membershipEventExpiryMs ) ,
647- this . stateKey ,
648- )
651+ . _unstable_sendStickyEvent ( this . room . roomId , STICK_DURATION_MS , null , EventType . GroupCallMemberPrefix , {
652+ ...this . makeMyMembership ( this . membershipEventExpiryMs ) ,
653+ sticky_key : this . stateKey ,
654+ } )
649655 . then ( ( ) => {
650656 this . setAndEmitProbablyLeft ( false ) ;
651657 this . state . startTime = Date . now ( ) ;
@@ -677,7 +683,11 @@ export class MembershipManager
677683 } ;
678684 } )
679685 . catch ( ( e ) => {
680- const update = this . actionUpdateFromErrors ( e , MembershipActionType . SendJoinEvent , "sendStateEvent" ) ;
686+ const update = this . actionUpdateFromErrors (
687+ e ,
688+ MembershipActionType . SendJoinEvent ,
689+ "_unstable_sendStickyEvent" ,
690+ ) ;
681691 if ( update ) return update ;
682692 throw e ;
683693 } ) ;
@@ -686,12 +696,10 @@ export class MembershipManager
686696 private async updateExpiryOnJoinedEvent ( ) : Promise < ActionUpdate > {
687697 const nextExpireUpdateIteration = this . state . expireUpdateIterations + 1 ;
688698 return await this . client
689- . sendStateEvent (
690- this . room . roomId ,
691- EventType . GroupCallMemberPrefix ,
692- this . makeMyMembership ( this . membershipEventExpiryMs * nextExpireUpdateIteration ) ,
693- this . stateKey ,
694- )
699+ . _unstable_sendStickyEvent ( this . room . roomId , STICK_DURATION_MS , null , EventType . GroupCallMemberPrefix , {
700+ ...this . makeMyMembership ( this . membershipEventExpiryMs ) ,
701+ sticky_key : this . stateKey ,
702+ } )
695703 . then ( ( ) => {
696704 // Success, we reset retries and schedule update.
697705 this . resetRateLimitCounter ( MembershipActionType . UpdateExpiry ) ;
@@ -706,22 +714,36 @@ export class MembershipManager
706714 } ;
707715 } )
708716 . catch ( ( e ) => {
709- const update = this . actionUpdateFromErrors ( e , MembershipActionType . UpdateExpiry , "sendStateEvent" ) ;
717+ const update = this . actionUpdateFromErrors (
718+ e ,
719+ MembershipActionType . UpdateExpiry ,
720+ "_unstable_sendStickyEvent" ,
721+ ) ;
710722 if ( update ) return update ;
711723
712724 throw e ;
713725 } ) ;
714726 }
715727 private async sendFallbackLeaveEvent ( ) : Promise < ActionUpdate > {
716728 return await this . client
717- . sendStateEvent ( this . room . roomId , EventType . GroupCallMemberPrefix , { } , this . stateKey )
729+ . _unstable_sendStickyEvent (
730+ this . room . roomId ,
731+ STICK_DURATION_MS ,
732+ null ,
733+ EventType . GroupCallMemberPrefix ,
734+ { sticky_key : this . stateKey } as EmptyObject & { sticky_key : string } , // leave event
735+ )
718736 . then ( ( ) => {
719737 this . resetRateLimitCounter ( MembershipActionType . SendLeaveEvent ) ;
720738 this . state . hasMemberStateEvent = false ;
721739 return { replace : [ ] } ;
722740 } )
723741 . catch ( ( e ) => {
724- const update = this . actionUpdateFromErrors ( e , MembershipActionType . SendLeaveEvent , "sendStateEvent" ) ;
742+ const update = this . actionUpdateFromErrors (
743+ e ,
744+ MembershipActionType . SendLeaveEvent ,
745+ "_unstable_sendStickyEvent" ,
746+ ) ;
725747 if ( update ) return update ;
726748 throw e ;
727749 } ) ;
0 commit comments