Initial Commit
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* DMP-11 — Response presence piggyback.
|
||||
*
|
||||
* `ChunkResponsePayload` includes `presence` (the responder's full
|
||||
* inventory bitset) and `generation`; receivers update their peer
|
||||
* index from this payload without requiring a separate `cd:advertise`.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
chunkIdsToRawBitset,
|
||||
decodeFramedBitset,
|
||||
decodeResponsePayload,
|
||||
encodeFramedBitset,
|
||||
encodeResponsePayload,
|
||||
GenerationTracker,
|
||||
rawBitsetToChunkIds,
|
||||
} from "../src/index.js";
|
||||
import type { ChunkResponsePayload } from "../src/types/protocol.types.js";
|
||||
|
||||
const FILE_ID = "c".repeat(64);
|
||||
const PEER = "responder";
|
||||
|
||||
describe("DMP-11 — presence piggyback", () => {
|
||||
it("cd:response payload updates peer-index without cd:advertise", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const inventory = [0, 5, 17, 99];
|
||||
const presence = encodeFramedBitset(
|
||||
chunkIdsToRawBitset(inventory, 100),
|
||||
100
|
||||
);
|
||||
const payload: ChunkResponsePayload = {
|
||||
fileId: FILE_ID,
|
||||
chunks: [
|
||||
{ chunkId: 0, bytes: new Uint8Array([0xa1]) },
|
||||
{ chunkId: 5, bytes: new Uint8Array([0xa2]) },
|
||||
],
|
||||
presence,
|
||||
generation: 11,
|
||||
};
|
||||
const wire = encodeResponsePayload(payload);
|
||||
const decoded = decodeResponsePayload(wire);
|
||||
expect(decoded.generation).toBe(11);
|
||||
// Receiver decodes the piggybacked bitset and updates its
|
||||
// peer-index for (responder, FILE_ID) — no cd:advertise needed.
|
||||
const decodedPresence = decodeFramedBitset(decoded.presence);
|
||||
const recoveredInventory = rawBitsetToChunkIds(
|
||||
decodedPresence.raw,
|
||||
decodedPresence.bitLength
|
||||
);
|
||||
expect(recoveredInventory).toEqual(inventory);
|
||||
|
||||
const tracker = new GenerationTracker();
|
||||
const observation = tracker.observe(PEER, FILE_ID, decoded.generation);
|
||||
expect(observation.accept).toBe(true);
|
||||
expect(tracker.peek(PEER, FILE_ID)).toBe(11);
|
||||
});
|
||||
|
||||
it("piggyback applies even on partial responses (chunks.length < requested)", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const presence = encodeFramedBitset(
|
||||
chunkIdsToRawBitset([3, 7], 16),
|
||||
16
|
||||
);
|
||||
const partial: ChunkResponsePayload = {
|
||||
fileId: FILE_ID,
|
||||
chunks: [{ chunkId: 3, bytes: new Uint8Array([0xc0]) }],
|
||||
presence,
|
||||
generation: 4,
|
||||
};
|
||||
const wire = encodeResponsePayload(partial);
|
||||
const round = decodeResponsePayload(wire);
|
||||
expect(round.chunks.length).toBe(1);
|
||||
expect(round.presence).toEqual(presence);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user