matrix-js-sdk
Version:
Matrix Client-Server SDK for Javascript
210 lines • 11.5 kB
TypeScript
import { type ISendEventResponse, type SendDelayedEventResponse } from "../@types/requests.ts";
import { type EmptyObject } from "../@types/common.ts";
import type { MatrixClient } from "../client.ts";
import { type Logger } from "../logger.ts";
import { type Room } from "../models/room.ts";
import { type CallMembership } from "./CallMembership.ts";
import { type Transport, type RTCCallIntent, Status, type SlotDescription } from "./types.ts";
import { type MembershipConfig, type SessionConfig } from "./MatrixRTCSession.ts";
import { type ActionUpdate } from "./MembershipManagerActionScheduler.ts";
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
import { MembershipManagerEvent, type IMembershipManager, type MembershipManagerEventHandlerMap } from "./IMembershipManager.ts";
import { type RtcMembershipData, type SessionMembershipData } from "./membershipData/index.ts";
/**
* The different types of actions the MembershipManager can take.
* @internal
*/
export declare enum MembershipActionType {
SendDelayedEvent = "SendDelayedEvent",
SendJoinEvent = "SendJoinEvent",
RestartDelayedEvent = "RestartDelayedEvent",
UpdateExpiry = "UpdateExpiry",
SendScheduledDelayedLeaveEvent = "SendScheduledDelayedLeaveEvent",
SendLeaveEvent = "SendLeaveEvent"
}
/**
* @internal
*/
export interface MembershipManagerState {
/** The delayId we got when successfully sending the delayed leave event.
* Gets set to undefined if the server claims it cannot find the delayed event anymore. */
delayId?: string;
/** Stores how often we have update the `expires` field.
* `expireUpdateIterations` * `membershipEventExpiryTimeout` resolves to the value the expires field should contain next */
expireUpdateIterations: number;
/** The time at which we send the first state event. The time the call started from the DAG point of view.
* This is used to compute the local sleep timestamps when to next update the member event with a new expires value. */
startTime: number;
/** The manager is in the state where its actually connected to the session. */
hasMemberStateEvent: boolean;
/** Retry counter for rate limits */
rateLimitRetries: Map<MembershipActionType, number>;
/** Retry counter for other errors */
networkErrorRetries: Map<MembershipActionType, number>;
/** The time at which we expect the server to send the delayed leave event. */
expectedServerDelayLeaveTs?: number;
/** This is used to track if the client expects the scheduled delayed leave event to have
* been sent because restarting failed during the available time.
* Once we resend the delayed event or successfully restarted it will get unset. */
probablyLeft: boolean;
}
type MembershipManagerClient = Pick<MatrixClient, "getUserId" | "getDeviceId" | "sendStateEvent" | "_unstable_sendDelayedStateEvent" | "_unstable_updateDelayedEvent" | "_unstable_cancelScheduledDelayedEvent" | "_unstable_restartScheduledDelayedEvent" | "_unstable_sendScheduledDelayedEvent">;
/**
* This class is responsible for sending all events relating to the own membership of a matrixRTC call.
* It has the following tasks:
* - Send the users leave delayed event before sending the membership
* - Send the users membership if the state machine is started
* - Check if the delayed event was canceled due to sending the membership
* - update the delayed event (`restart`)
* - Update the state event every ~5h = `DEFAULT_EXPIRE_DURATION` (so it does not get treated as expired)
* - When the state machine is stopped:
* - Disconnect the member
* - Stop the timer for the delay refresh
* - Stop the timer for updating the state event
*/
export declare class MembershipManager extends TypedEventEmitter<MembershipManagerEvent, MembershipManagerEventHandlerMap> implements IMembershipManager {
private readonly joinConfig;
protected readonly room: Pick<Room, "roomId" | "getVersion">;
protected readonly client: MembershipManagerClient;
readonly slotDescription: SlotDescription;
private activated;
private readonly logger;
protected callIntent: RTCCallIntent | undefined;
isActivated(): boolean;
isJoined(): boolean;
/**
* Puts the MembershipManager in a state where it tries to be joined.
* It will send delayed events and membership events
* @param fociPreferred the list of preferred foci to use in the joined RTC membership event.
* If multiSfuFocus is set, this is only needed if this client wants to publish to multiple transports simultaneously.
* @param multiSfuFocus the active focus to use in the joined RTC membership event. Setting this implies the
* membership manager will operate in a multi-SFU connection mode. If `undefined`, an `oldest_membership`
* transport selection will be used instead.
* @param onError This will be called once the membership manager encounters an unrecoverable error.
* This should bubble up the the frontend to communicate that the call does not work in the current environment.
*/
join(fociPreferred: Transport[], multiSfuFocus?: Transport, onError?: (error: unknown) => void): void;
/**
* Leave from the call (Send an rtc session event with content: `{}`)
* @param timeout the maximum duration this promise will take to resolve
* @returns true if it managed to leave and false if the timeout condition happened.
*/
leave(timeout?: number): Promise<boolean>;
private leavePromiseResolvers?;
onRTCSessionMemberUpdate(memberships: CallMembership[]): Promise<void>;
updateCallIntent(callIntent: RTCCallIntent): Promise<void>;
/**
* @throws if the client does not return user or device id.
* @param joinConfig
* @param room
* @param client
*/
constructor(joinConfig: (SessionConfig & MembershipConfig) | undefined, room: Pick<Room, "roomId" | "getVersion">, client: MembershipManagerClient, slotDescription: SlotDescription, parentLogger?: Logger);
private _ownMembership?;
get ownMembership(): CallMembership | undefined;
private oldStatus?;
private scheduler;
private state;
private static get defaultState();
protected deviceId: string;
protected userId: string;
protected stateKey: string;
protected rtcTransport?: Transport;
/** @deprecated This will be removed in favor or rtcTransport becoming a list of actively used transports */
private fociPreferred?;
private delayedLeaveEventDelayMsOverride?;
private get networkErrorRetryMs();
private get membershipEventExpiryMs();
private get membershipEventExpiryHeadroomMs();
private computeNextExpiryActionTs;
protected get delayedLeaveEventDelayMs(): number;
private get delayedLeaveEventRestartMs();
private get maximumRateLimitRetryCount();
private get maximumNetworkErrorRetryCount();
private get delayedLeaveEventRestartLocalTimeoutMs();
private membershipLoopHandler;
protected clientSendDelayedDisconnectMembership: () => Promise<SendDelayedEventResponse>;
private sendOrResendDelayedLeaveEvent;
private cancelKnownDelayIdBeforeSendDelayedEvent;
private setAndEmitProbablyLeft;
private setAndEmitDelayId;
private restartDelayedEvent;
private sendScheduledDelayedLeaveEventOrFallbackToSendLeaveEvent;
protected clientSendMembership: (myMembership: RtcMembershipData | SessionMembershipData | EmptyObject) => Promise<ISendEventResponse>;
private sendJoinEvent;
private updateExpiryOnJoinedEvent;
private sendFallbackLeaveEvent;
/**
* this creates `${localUserId}_${localDeviceId}_${this.slotDescription.application}${this.slotDescription.id}`
* which is not compatible with membershipID of session type member events. They have to be `${localUserId}:${localDeviceId}`
*/
private makeMembershipStateKey;
/**
* Constructs our own membership
* @returns Only returns `SessionMembershipData`
*/
protected makeMyMembership(expires: number): SessionMembershipData | RtcMembershipData;
/**
* Check if its a NOT_FOUND error
* @param error the error causing this handler check/execution
* @returns true if its a not found error
*/
private isNotFoundError;
/**
* Check if this is a DelayExceeded timeout and update the TimeoutOverride for the next try
* @param error the error causing this handler check/execution
* @returns true if its a delay exceeded error and we updated the local TimeoutOverride
*/
private manageMaxDelayExceededSituation;
protected actionUpdateFromErrors(error: unknown, type: MembershipActionType, method: string): ActionUpdate | undefined;
/**
* Check if we have a rate limit error and schedule the same action again if we dont exceed the rate limit retry count yet.
* @param error the error causing this handler check/execution
* @param method the method used for the throw message
* @param type which MembershipActionType we reschedule because of a rate limit.
* @throws If it is a rate limit error and the retry count got exceeded
* @returns Returns true if we handled the error by rescheduling the correct next action.
* Returns false if it is not a network error.
*/
private actionUpdateFromRateLimitError;
/**
* FIXME Don't Check the error and retry the same MembershipAction again in the configured time and for the configured retry count.
* @param error the error causing this handler check/execution
* @param type the action type that we need to repeat because of the error
* @throws If it is a network error and the retry count got exceeded
* @returns
* Returns true if we handled the error by rescheduling the correct next action.
* Returns false if it is not a network error.
*/
private actionUpdateFromNetworkErrorRetry;
/**
* Check if its an UnsupportedDelayedEventsEndpointError and which implies that we cannot do any delayed event logic
* @param error The error to check
* @returns true it its an UnsupportedDelayedEventsEndpointError
*/
private isUnsupportedDelayedEndpoint;
private resetRateLimitCounter;
get status(): Status;
get probablyLeft(): boolean;
get delayId(): string | undefined;
}
/**
* Implementation of the Membership manager that uses sticky events
* rather than state events.
*/
export declare class StickyEventMembershipManager extends MembershipManager {
private readonly clientWithSticky;
private readonly memberId;
constructor(joinConfig: (SessionConfig & MembershipConfig) | undefined, room: Pick<Room, "getLiveTimeline" | "roomId" | "getVersion">, clientWithSticky: MembershipManagerClient & Pick<MatrixClient, "_unstable_sendStickyEvent" | "_unstable_sendStickyDelayedEvent">, sessionDescription: SlotDescription, memberId: string, parentLogger?: Logger);
protected clientSendDelayedDisconnectMembership: () => Promise<SendDelayedEventResponse>;
protected clientSendMembership: (myMembership: RtcMembershipData | SessionMembershipData | EmptyObject) => Promise<ISendEventResponse>;
private static nameMap;
protected actionUpdateFromErrors(e: unknown, t: MembershipActionType, m: string): ActionUpdate | undefined;
/**
*
* @returns Only returns `RtcMembershipData`
*/
protected makeMyMembership(): RtcMembershipData;
}
export {};
//# sourceMappingURL=MembershipManager.d.ts.map