Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions client/js/irc/catchup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,8 @@ function sendTargets(client: IrcClient, state: TargetsState): void {
// From the start: the server's index moves on messages only (not joins,
// parts, topics, redactions), so the newest line we hold can be well past
// a quiet channel's newest message, and a window starting there would
// leave it out. Newest first, so a long history costs nothing extra.
// leave it out. The limit counts from the first bound, so the newer one
// goes first: the newest `limit` targets, as in the spec's example.
const since = new Date(0);
const until = new Date(Date.now() + TARGETS_AHEAD_MS);
const tags: Record<string, string> = {};
Expand All @@ -559,8 +560,8 @@ function sendTargets(client: IrcClient, state: TargetsState): void {
command: "CHATHISTORY",
params: [
"TARGETS",
`timestamp=${since.toISOString()}`,
`timestamp=${until.toISOString()}`,
`timestamp=${since.toISOString()}`,
String(historyLimit(client, TARGETS_LIMIT)),
],
});
Expand Down
8 changes: 5 additions & 3 deletions docs/projects/connect-burst.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ The background catch-up used to go in JOIN order, so the channel that had
been written to waited behind every quiet one, and a reconnect fetched every
channel whether anything had happened in it or not. Now the first channel
to need the background queue on a connection asks one
`CHATHISTORY TARGETS timestamp=<from> timestamp=<a day past now> <limit>`
`CHATHISTORY TARGETS timestamp=<a day past now> timestamp=<from> <limit>`
(at the front of the queue) and the catch-up of every other channel is
parked until it answers (`catchup.ts`):

Expand All @@ -210,8 +210,10 @@ parked until it answers (`catchup.ts`):
now because nefarious2 drops a target whose newest message is later than
it (`filter_targets_window`), and a server clock ahead of ours would lose
exactly the channel just written to. The limit is 100 (capped by ISUPPORT
`CHATHISTORY`). nefarious2 lists the channels we may read history of:
those we are a member of, and `+H` (public history) channels without
`CHATHISTORY`). The newer bound goes first: TARGETS takes BETWEEN's
semantics, the limit counting from the first argument, so oldest first
would get the oldest `limit` from a server that follows the spec (#216).
nefarious2 lists the channels we may read history of: those we are a member of, and `+H` (public history) channels without
membership (`check_history_access`). So it is asked once the JOINs are
in, newest first; a listed `+H` channel we are not in is simply not
among the parked ones.
Expand Down
15 changes: 10 additions & 5 deletions test/irc/catchup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,12 @@ describe("Connect burst: batched JOIN, catch-up paced by fake lag, lazy MODE (ir
"#four",
]);

// One TARGETS, first in the queue, from the start of time (nothing is
// held yet) to a day past now.
// One TARGETS, first in the queue, from a day past now back to the
// start of time (nothing is held yet): newer bound first, so a server
// following the spec counts the limit from the newest (issue #216).
const [targets] = collect(h, 1).map((s) => s.line);
expect(targets).to.match(
/^@label=tg\d+ CHATHISTORY TARGETS timestamp=1970-01-01T00:00:00\.000Z timestamp=2026-08-28T12:00:\d\d\.\d{3}Z 100$/
/^@label=tg\d+ CHATHISTORY TARGETS timestamp=2026-08-28T12:00:\d\d\.\d{3}Z timestamp=1970-01-01T00:00:00\.000Z 100$/
);
answerTargets(h, targets, [
["#three", "2026-08-27T11:59:00.000Z"],
Expand Down Expand Up @@ -604,7 +605,9 @@ describe("Connect burst: batched JOIN, catch-up paced by fake lag, lazy MODE (ir
const h = heldThenDropped(HELD);
const [targets] = collect(h, 1, isTargets).map((s) => s.line);
// From the start: events move what we hold, not the server's index.
expect(targets).to.include("TARGETS timestamp=1970-01-01T00:00:00.000Z ");
expect(targets).to.match(
/ TARGETS timestamp=\S+ timestamp=1970-01-01T00:00:00\.000Z \d+$/
);
answerTargets(h, targets, [
["#three", "2026-08-27T12:05:00.000Z"], // written to since
["#seance", "2026-08-27T12:04:00.000Z"], // the active one: served already
Expand Down Expand Up @@ -664,7 +667,9 @@ describe("Connect burst: batched JOIN, catch-up paced by fake lag, lazy MODE (ir
h.sent();
joinAll(h);
const [targets] = collect(h, 1, isTargets).map((s) => s.line);
expect(targets).to.include("TARGETS timestamp=1970-01-01T00:00:00.000Z ");
expect(targets).to.match(
/ TARGETS timestamp=\S+ timestamp=1970-01-01T00:00:00\.000Z \d+$/
);
answerTargets(h, targets, []);
expect(fetched(collect(h, 20).map((s) => s.line))).to.deep.equal([
"#two",
Expand Down
Loading