Skip to content

Commit 35d862e

Browse files
Handle M_MAX_DELAY_EXCEEDED errors (#4511)
* Handle M_MAX_DELAY_EXCEEDED errors Use a lower delay time if the server rejects a delay as too long. * Add test * Lint test * Update src/matrixrtc/MatrixRTCSession.ts Co-authored-by: Robin <robin@robin.town> * Test computed expiry timeout value --------- Co-authored-by: Robin <robin@robin.town>
1 parent 581b320 commit 35d862e

File tree

2 files changed

+46
-2
lines changed

2 files changed

+46
-2
lines changed

spec/unit/matrixrtc/MatrixRTCSession.spec.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,19 @@ describe("MatrixRTCSession", () => {
508508

509509
jest.useFakeTimers();
510510

511+
// preparing the delayed disconnect should handle the delay being too long
512+
const sendDelayedStateExceedAttempt = new Promise<void>((resolve) => {
513+
const error = new MatrixError({
514+
"errcode": "M_UNKNOWN",
515+
"org.matrix.msc4140.errcode": "M_MAX_DELAY_EXCEEDED",
516+
"org.matrix.msc4140.max_delay": 7500,
517+
});
518+
sendDelayedStateMock.mockImplementationOnce(() => {
519+
resolve();
520+
return Promise.reject(error);
521+
});
522+
});
523+
511524
// preparing the delayed disconnect should handle ratelimiting
512525
const sendDelayedStateAttempt = new Promise<void>((resolve) => {
513526
const error = new MatrixError({ errcode: "M_LIMIT_EXCEEDED" });
@@ -541,7 +554,14 @@ describe("MatrixRTCSession", () => {
541554
});
542555
});
543556

544-
sess!.joinRoomSession([activeFocusConfig], activeFocus, { useLegacyMemberEvents: false });
557+
sess!.joinRoomSession([activeFocusConfig], activeFocus, {
558+
useLegacyMemberEvents: false,
559+
membershipServerSideExpiryTimeout: 9000,
560+
});
561+
562+
expect(sess).toHaveProperty("membershipServerSideExpiryTimeout", 9000);
563+
await sendDelayedStateExceedAttempt.then(); // needed to resolve after the send attempt catches
564+
expect(sess).toHaveProperty("membershipServerSideExpiryTimeout", 7500);
545565

546566
await sendDelayedStateAttempt;
547567
jest.advanceTimersByTime(5000);

src/matrixrtc/MatrixRTCSession.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,18 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
184184
return this.joinConfig?.useKeyDelay ?? 5_000;
185185
}
186186

187+
/**
188+
* If the server disallows the configured {@link membershipServerSideExpiryTimeout},
189+
* this stores a delay that the server does allow.
190+
*/
191+
private membershipServerSideExpiryTimeoutOverride?: number;
192+
187193
private get membershipServerSideExpiryTimeout(): number {
188-
return this.joinConfig?.membershipServerSideExpiryTimeout ?? 8_000;
194+
return (
195+
this.membershipServerSideExpiryTimeoutOverride ??
196+
this.joinConfig?.membershipServerSideExpiryTimeout ??
197+
8_000
198+
);
189199
}
190200

191201
private get membershipKeepAlivePeriod(): number {
@@ -1141,6 +1151,20 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
11411151
);
11421152
this.disconnectDelayId = res.delay_id;
11431153
} catch (e) {
1154+
if (
1155+
e instanceof MatrixError &&
1156+
e.errcode === "M_UNKNOWN" &&
1157+
e.data["org.matrix.msc4140.errcode"] === "M_MAX_DELAY_EXCEEDED"
1158+
) {
1159+
const maxDelayAllowed = e.data["org.matrix.msc4140.max_delay"];
1160+
if (
1161+
typeof maxDelayAllowed === "number" &&
1162+
this.membershipServerSideExpiryTimeout > maxDelayAllowed
1163+
) {
1164+
this.membershipServerSideExpiryTimeoutOverride = maxDelayAllowed;
1165+
return prepareDelayedDisconnection();
1166+
}
1167+
}
11441168
logger.error("Failed to prepare delayed disconnection event:", e);
11451169
}
11461170
};

0 commit comments

Comments
 (0)