Matrix mouth: re-read the brake before every join; pin the encoded presence path
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
8938dbd739
commit
94606d04a6
2 changed files with 19 additions and 3 deletions
|
|
@ -1035,6 +1035,7 @@ test("presence follows the brake: online while released, offline and one PUT on
|
|||
await mouth.syncOnce(); await mouth.syncOnce(); await mouth.syncOnce();
|
||||
assert.deepEqual(syncs().slice(2), ["offline", "offline", "offline"]);
|
||||
assert.deepEqual(hs.presencePuts().map(r => [r.path, r.body]), [[`/_matrix/client/v3/presence/${SELF}/status`, { presence: "offline" }]], "exactly one PUT");
|
||||
assert.equal(hs.presencePuts()[0].rawPath, `/_matrix/client/v3/presence/${encodeURIComponent(SELF)}/status`, "the user id is percent-encoded on the wire");
|
||||
open = true;
|
||||
await mouth.syncOnce();
|
||||
assert.equal(syncs().at(-1), "online");
|
||||
|
|
@ -1151,3 +1152,18 @@ test("a full backlog still sets presence from the brake", async () => {
|
|||
assert.equal(hs.seen.filter(r => r.path.endsWith("/sync")).length, syncsBefore);
|
||||
assert.deepEqual(hs.presencePuts().map(r => r.body), [{ presence: "offline" }]);
|
||||
});
|
||||
|
||||
test("a brake placed during the first of two joins stops the second join and its m.direct write", async () => {
|
||||
const DM2 = "!newdm2:gamecult.test";
|
||||
const invites2 = { ...invite(`@meta:${HS_NAME}`), [DM2]: invite(`@meta:${HS_NAME}`)[DMROOM] };
|
||||
const hs = await fakeHomeserver({ sync: since => since === null ? { next_batch: "b0" } : since === "b0" ? { next_batch: "b1", rooms: { invite: invites2 } } : { next_batch: since } });
|
||||
let open = true;
|
||||
const fetch = async (url, init) => { const res = await hs.fetch(url, init); if (init?.method === "POST" && String(url).includes("/join/")) open = false; return res; }; // the brake lands during the first join
|
||||
const mouth = mouthFor(hs, { fetch, brake: async () => open });
|
||||
await mouth.syncOnce(); await mouth.syncOnce();
|
||||
assert.deepEqual(joinsOf(hs), [DMROOM], "only the join already started");
|
||||
assert.equal(hs.seen.filter(r => r.method === "PUT" && r.path.endsWith("/account_data/m.direct")).length, 1, "one m.direct, for the first join");
|
||||
open = true;
|
||||
await mouth.syncOnce();
|
||||
assert.deepEqual(joinsOf(hs), [DMROOM, DM2], "the second waits for the release");
|
||||
});
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ export function createMouth({
|
|||
// A DM invitation from an account on our own homeserver is accepted, and only while the brake is
|
||||
// released; one received while braked waits for the release. An invitation from any other server is
|
||||
// declined. A same-server invitation to a room that is not a DM is not ours to accept and is dropped.
|
||||
async function answerInvites(free) {
|
||||
async function answerInvites() {
|
||||
for (const [roomId, invite] of [...invites]) {
|
||||
try {
|
||||
const room = encodeURIComponent(roomId);
|
||||
|
|
@ -174,7 +174,7 @@ export function createMouth({
|
|||
} else if (!invite.direct) {
|
||||
invites.delete(roomId);
|
||||
} else {
|
||||
if (!free) continue;
|
||||
if (!(await released())) continue; // read fresh before every join: a brake placed mid-pass stops the next one
|
||||
await matrix("POST", `/join/${room}`, {});
|
||||
invites.delete(roomId);
|
||||
directRooms.add(roomId);
|
||||
|
|
@ -299,7 +299,7 @@ export function createMouth({
|
|||
const baseline = cursor === null; // first ever sync: history is context, not mail
|
||||
for (const event of reply.account_data?.events ?? []) if (event.type === "m.direct") noteDirect(event.content);
|
||||
noteInvites(reply.rooms?.invite);
|
||||
await answerInvites(await released()); // a brake placed during the long-poll stops the join, as send re-reads it
|
||||
await answerInvites(); // each join re-reads the brake, as send does
|
||||
const made = [];
|
||||
const round = new Map();
|
||||
let truncated = false; // the pending cap was reached inside this round
|
||||
|
|
|
|||
Loading…
Reference in a new issue