@trystero-p2p/torrent 0.23.0-beta.1 → 0.23.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1071 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +102 -76
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;KA+CY,iBAAA,GAAoB,cAAA,GAAiB,WAAA;AAAA,cA6VpC,QAAA,EAAU,QAAA,CAAS,iBAAA;AAAA,cAcnB,eAAA;AAAA,cAIA,gBAAA"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { createStrategy, entries, fromJson, genId, getRelays, libName, makeSocket, pauseRelayReconnection, resumeRelayReconnection, selfId, sha1,
|
|
1
|
+
import { createRelayManager, createStrategy, entries, fromJson, genId, getRelays, keys, libName, makeSocket, pauseRelayReconnection, resumeRelayReconnection, selfId, sha1, toJson } from "@trystero-p2p/core";
|
|
2
2
|
//#region src/index.ts
|
|
3
|
-
const
|
|
3
|
+
const relayManager = createRelayManager((client) => client.socket);
|
|
4
4
|
const topicToInfoHash = {};
|
|
5
5
|
const infoHashToTopic = {};
|
|
6
|
-
const announceIntervals =
|
|
7
|
-
const announceFns =
|
|
8
|
-
const subscriptionTokens =
|
|
6
|
+
const announceIntervals = relayManager.scoped();
|
|
7
|
+
const announceFns = relayManager.scoped();
|
|
8
|
+
const subscriptionTokens = relayManager.scoped();
|
|
9
9
|
const trackerAnnounceMs = {};
|
|
10
10
|
const handledSignals = {};
|
|
11
|
-
const msgHandlers =
|
|
11
|
+
const msgHandlers = relayManager.scoped();
|
|
12
|
+
const roomOutstandingOffers = {};
|
|
13
|
+
const roomOfferGenerationPromises = {};
|
|
14
|
+
const roomSubscriberCounts = {};
|
|
12
15
|
const trackerAction = "announce";
|
|
13
16
|
const hashLimit = 20;
|
|
14
|
-
const offerPoolSize =
|
|
17
|
+
const offerPoolSize = 3;
|
|
15
18
|
const defaultAnnounceMs = 1e4;
|
|
16
19
|
const maxAnnounceMs = 2e4;
|
|
17
20
|
const offerRetentionMs = 12e4;
|
|
@@ -24,18 +27,68 @@ const getInfoHash = async (topic) => {
|
|
|
24
27
|
infoHashToTopic[hash] = topic;
|
|
25
28
|
return hash;
|
|
26
29
|
};
|
|
27
|
-
const send = async (client, topic, payload) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}));
|
|
34
|
-
};
|
|
30
|
+
const send = async (client, topic, payload) => client.send(toJson({
|
|
31
|
+
action: trackerAction,
|
|
32
|
+
info_hash: await getInfoHash(topic),
|
|
33
|
+
peer_id: selfId,
|
|
34
|
+
...payload
|
|
35
|
+
}));
|
|
35
36
|
const warn = (url, msg, didFail = false) => console.warn(`${libName}: torrent tracker ${didFail ? "failure" : "warning"} from ${url} - ${msg}`);
|
|
37
|
+
const getRoomOutstandingOffers = (rootTopic) => roomOutstandingOffers[rootTopic] ??= {};
|
|
38
|
+
const deleteRoomOfferBookkeeping = (rootTopic) => {
|
|
39
|
+
delete roomOutstandingOffers[rootTopic];
|
|
40
|
+
delete roomOfferGenerationPromises[rootTopic];
|
|
41
|
+
};
|
|
42
|
+
const claimOutstandingOffer = (rootTopic, offerId) => {
|
|
43
|
+
const outstandingOffers = roomOutstandingOffers[rootTopic];
|
|
44
|
+
const offer = outstandingOffers?.[offerId];
|
|
45
|
+
if (!offer) return;
|
|
46
|
+
delete outstandingOffers[offerId];
|
|
47
|
+
offer.claim?.();
|
|
48
|
+
if (!keys(outstandingOffers).length && !roomSubscriberCounts[rootTopic]) deleteRoomOfferBookkeeping(rootTopic);
|
|
49
|
+
return offer;
|
|
50
|
+
};
|
|
51
|
+
const reclaimOutstandingOffer = (rootTopic, offerId) => {
|
|
52
|
+
const outstandingOffers = roomOutstandingOffers[rootTopic];
|
|
53
|
+
const offer = outstandingOffers?.[offerId];
|
|
54
|
+
if (!offer) return;
|
|
55
|
+
delete outstandingOffers[offerId];
|
|
56
|
+
offer.reclaim?.();
|
|
57
|
+
if (!keys(outstandingOffers).length && !roomSubscriberCounts[rootTopic]) deleteRoomOfferBookkeeping(rootTopic);
|
|
58
|
+
};
|
|
59
|
+
const reclaimAllOutstandingOffers = (rootTopic) => {
|
|
60
|
+
keys(getRoomOutstandingOffers(rootTopic)).forEach((offerId) => reclaimOutstandingOffer(rootTopic, offerId));
|
|
61
|
+
deleteRoomOfferBookkeeping(rootTopic);
|
|
62
|
+
};
|
|
63
|
+
const pruneOutstandingOffers = (rootTopic) => {
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
entries(getRoomOutstandingOffers(rootTopic)).forEach(([offerId, offer]) => {
|
|
66
|
+
if (now - offer.createdAt > offerRetentionMs) reclaimOutstandingOffer(rootTopic, offerId);
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const ensureOutstandingOffers = async (rootTopic, getOffers) => {
|
|
70
|
+
while (roomOfferGenerationPromises[rootTopic]) await roomOfferGenerationPromises[rootTopic];
|
|
71
|
+
const nextPromise = (async () => {
|
|
72
|
+
pruneOutstandingOffers(rootTopic);
|
|
73
|
+
const outstandingOffers = getRoomOutstandingOffers(rootTopic);
|
|
74
|
+
const outstandingCount = keys(outstandingOffers).length;
|
|
75
|
+
const missingOffers = Math.max(0, offerPoolSize - outstandingCount);
|
|
76
|
+
if (missingOffers > 0) (await getOffers(missingOffers)).forEach((peerAndOffer) => {
|
|
77
|
+
outstandingOffers[genId(hashLimit)] = {
|
|
78
|
+
...peerAndOffer,
|
|
79
|
+
createdAt: Date.now()
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
})().finally(() => {
|
|
83
|
+
if (roomOfferGenerationPromises[rootTopic] === nextPromise) delete roomOfferGenerationPromises[rootTopic];
|
|
84
|
+
});
|
|
85
|
+
roomOfferGenerationPromises[rootTopic] = nextPromise;
|
|
86
|
+
await nextPromise;
|
|
87
|
+
return getRoomOutstandingOffers(rootTopic);
|
|
88
|
+
};
|
|
36
89
|
const joinRoomStrategy = createStrategy({
|
|
37
90
|
init: (config) => getRelays(config, defaultRelayUrls, defaultRedundancy).map((rawUrl) => {
|
|
38
|
-
const client = makeSocket(rawUrl, (rawData) => {
|
|
91
|
+
const client = relayManager.register(rawUrl, makeSocket(rawUrl, (rawData) => {
|
|
39
92
|
const data = fromJson(rawData);
|
|
40
93
|
const errMsg = data["failure reason"];
|
|
41
94
|
const warnMsg = data["warning message"];
|
|
@@ -46,14 +99,16 @@ const joinRoomStrategy = createStrategy({
|
|
|
46
99
|
return;
|
|
47
100
|
}
|
|
48
101
|
if (warnMsg) warn(client.url, warnMsg);
|
|
49
|
-
if (interval && interval * 1e3 > (trackerAnnounceMs[client.url] ?? defaultAnnounceMs) && topic && announceFns
|
|
102
|
+
if (interval && interval * 1e3 > (trackerAnnounceMs[client.url] ?? defaultAnnounceMs) && topic && announceFns.forKey(rawUrl)[topic]) {
|
|
50
103
|
const nextInterval = Math.min(interval * 1e3, maxAnnounceMs);
|
|
51
|
-
const relayIntervals = announceIntervals
|
|
52
|
-
const relayFns = announceFns
|
|
104
|
+
const relayIntervals = announceIntervals.forKey(rawUrl);
|
|
105
|
+
const relayFns = announceFns.forKey(rawUrl);
|
|
53
106
|
if (relayIntervals[topic]) clearInterval(relayIntervals[topic]);
|
|
54
107
|
trackerAnnounceMs[client.url] = nextInterval;
|
|
55
108
|
const relayFn = relayFns[topic];
|
|
56
|
-
if (relayFn) relayIntervals[topic] = setInterval(
|
|
109
|
+
if (relayFn) relayIntervals[topic] = setInterval(() => {
|
|
110
|
+
relayFn();
|
|
111
|
+
}, nextInterval);
|
|
57
112
|
}
|
|
58
113
|
if ((data.offer || data.answer) && topic && data.offer_id) {
|
|
59
114
|
if (data.peer_id === selfId) return;
|
|
@@ -65,61 +120,36 @@ const joinRoomStrategy = createStrategy({
|
|
|
65
120
|
entries(handledSignals).forEach(([key, handledAtMs]) => {
|
|
66
121
|
if (nowMs - handledAtMs > signalDedupeWindowMs * 6) delete handledSignals[key];
|
|
67
122
|
});
|
|
68
|
-
msgHandlers
|
|
123
|
+
msgHandlers.forKey(rawUrl)[topic]?.(data);
|
|
69
124
|
}
|
|
70
|
-
});
|
|
71
|
-
const { url } = client;
|
|
72
|
-
clients[url] = client;
|
|
73
|
-
msgHandlers[url] = {};
|
|
125
|
+
}));
|
|
74
126
|
return client.ready;
|
|
75
127
|
}),
|
|
76
128
|
subscribe: (client, rootTopic, _, onMessage, getOffers) => {
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const activeTokens = subscriptionTokens[url] ??= {};
|
|
129
|
+
const handlers = msgHandlers.forRelay(client);
|
|
130
|
+
const relayFns = announceFns.forRelay(client);
|
|
131
|
+
const relayIntervals = announceIntervals.forRelay(client);
|
|
132
|
+
const activeTokens = subscriptionTokens.forRelay(client);
|
|
82
133
|
const subscriptionToken = Symbol(rootTopic);
|
|
83
|
-
const outstandingOffers = {};
|
|
84
134
|
activeTokens[rootTopic] = subscriptionToken;
|
|
85
|
-
|
|
86
|
-
const offer = outstandingOffers[offerId];
|
|
87
|
-
if (!offer) return;
|
|
88
|
-
delete outstandingOffers[offerId];
|
|
89
|
-
offer.claim?.();
|
|
90
|
-
return offer;
|
|
91
|
-
};
|
|
92
|
-
const reclaimOutstandingOffer = (offerId) => {
|
|
93
|
-
const offer = outstandingOffers[offerId];
|
|
94
|
-
if (!offer) return;
|
|
95
|
-
delete outstandingOffers[offerId];
|
|
96
|
-
offer.reclaim?.();
|
|
97
|
-
};
|
|
98
|
-
const reclaimAllOutstandingOffers = () => {
|
|
99
|
-
entries(outstandingOffers).forEach(([offerId]) => {
|
|
100
|
-
reclaimOutstandingOffer(offerId);
|
|
101
|
-
});
|
|
102
|
-
};
|
|
103
|
-
const pruneOutstandingOffers = () => {
|
|
104
|
-
const now = Date.now();
|
|
105
|
-
entries(outstandingOffers).forEach(([offerId, offer]) => {
|
|
106
|
-
if (now - offer.createdAt > offerRetentionMs) reclaimOutstandingOffer(offerId);
|
|
107
|
-
});
|
|
108
|
-
};
|
|
135
|
+
roomSubscriberCounts[rootTopic] = (roomSubscriberCounts[rootTopic] ?? 0) + 1;
|
|
109
136
|
const topicHandler = (data) => {
|
|
110
137
|
if (data.offer && data.peer_id && data.offer_id) onMessage(rootTopic, {
|
|
111
|
-
offer: data.offer,
|
|
138
|
+
offer: data.offer.sdp,
|
|
112
139
|
peerId: data.peer_id,
|
|
113
|
-
hasOutgoingOffer:
|
|
140
|
+
hasOutgoingOffer: keys(getRoomOutstandingOffers(rootTopic)).length > 0
|
|
114
141
|
}, (_, signal) => void send(client, rootTopic, {
|
|
115
|
-
answer:
|
|
142
|
+
answer: {
|
|
143
|
+
type: "answer",
|
|
144
|
+
sdp: fromJson(signal).answer
|
|
145
|
+
},
|
|
116
146
|
offer_id: data.offer_id,
|
|
117
147
|
to_peer_id: data.peer_id
|
|
118
148
|
}));
|
|
119
149
|
else if (data.answer && data.offer_id && data.peer_id) {
|
|
120
|
-
const offer = claimOutstandingOffer(data.offer_id);
|
|
150
|
+
const offer = claimOutstandingOffer(rootTopic, data.offer_id);
|
|
121
151
|
if (offer) onMessage(rootTopic, {
|
|
122
|
-
answer: data.answer,
|
|
152
|
+
answer: data.answer.sdp,
|
|
123
153
|
peerId: data.peer_id,
|
|
124
154
|
peer: offer.peer
|
|
125
155
|
}, () => {});
|
|
@@ -128,30 +158,26 @@ const joinRoomStrategy = createStrategy({
|
|
|
128
158
|
handlers[rootTopic] = topicHandler;
|
|
129
159
|
const announce = async () => {
|
|
130
160
|
if (activeTokens[rootTopic] !== subscriptionToken) return;
|
|
131
|
-
pruneOutstandingOffers();
|
|
132
|
-
const outstandingCount = entries(outstandingOffers).length;
|
|
133
|
-
const missingOffers = Math.max(0, offerPoolSize - outstandingCount);
|
|
134
|
-
if (missingOffers > 0) (await getOffers(missingOffers)).forEach((peerAndOffer) => {
|
|
135
|
-
outstandingOffers[genId(hashLimit)] = {
|
|
136
|
-
...peerAndOffer,
|
|
137
|
-
createdAt: Date.now()
|
|
138
|
-
};
|
|
139
|
-
});
|
|
140
161
|
send(client, rootTopic, {
|
|
141
162
|
numwant: offerPoolSize,
|
|
142
|
-
offers: entries(
|
|
163
|
+
offers: entries(await ensureOutstandingOffers(rootTopic, getOffers)).map(([id, { offer }]) => ({
|
|
143
164
|
offer_id: id,
|
|
144
|
-
offer
|
|
165
|
+
offer: {
|
|
166
|
+
type: "offer",
|
|
167
|
+
sdp: offer
|
|
168
|
+
}
|
|
145
169
|
}))
|
|
146
170
|
});
|
|
147
171
|
};
|
|
148
|
-
trackerAnnounceMs[url] = defaultAnnounceMs;
|
|
172
|
+
trackerAnnounceMs[client.url] = defaultAnnounceMs;
|
|
149
173
|
relayFns[rootTopic] = announce;
|
|
150
|
-
relayIntervals[rootTopic] = setInterval(announce, trackerAnnounceMs[url]);
|
|
174
|
+
relayIntervals[rootTopic] = setInterval(announce, trackerAnnounceMs[client.url]);
|
|
151
175
|
announce();
|
|
152
176
|
return () => {
|
|
177
|
+
roomSubscriberCounts[rootTopic] = Math.max(0, (roomSubscriberCounts[rootTopic] ?? 1) - 1);
|
|
178
|
+
if (!roomSubscriberCounts[rootTopic]) delete roomSubscriberCounts[rootTopic];
|
|
153
179
|
if (activeTokens[rootTopic] !== subscriptionToken) {
|
|
154
|
-
reclaimAllOutstandingOffers();
|
|
180
|
+
if (!roomSubscriberCounts[rootTopic]) reclaimAllOutstandingOffers(rootTopic);
|
|
155
181
|
return;
|
|
156
182
|
}
|
|
157
183
|
const interval = relayIntervals[rootTopic];
|
|
@@ -162,7 +188,7 @@ const joinRoomStrategy = createStrategy({
|
|
|
162
188
|
if (handlers[rootTopic] === topicHandler) delete handlers[rootTopic];
|
|
163
189
|
if (relayFns[rootTopic] === announce) delete relayFns[rootTopic];
|
|
164
190
|
delete activeTokens[rootTopic];
|
|
165
|
-
reclaimAllOutstandingOffers();
|
|
191
|
+
if (!roomSubscriberCounts[rootTopic]) reclaimAllOutstandingOffers(rootTopic);
|
|
166
192
|
};
|
|
167
193
|
},
|
|
168
194
|
announce: (client) => trackerAnnounceMs[client.url]
|
|
@@ -171,7 +197,7 @@ const joinRoom = (config, roomId, callbacks) => joinRoomStrategy({
|
|
|
171
197
|
...config,
|
|
172
198
|
trickleIce: config.trickleIce ?? false
|
|
173
199
|
}, roomId, callbacks);
|
|
174
|
-
const getRelaySockets =
|
|
200
|
+
const getRelaySockets = relayManager.getSockets;
|
|
175
201
|
const defaultRelayUrls = [
|
|
176
202
|
"tracker.webtorrent.dev",
|
|
177
203
|
"tracker.openwebtorrent.com",
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n createStrategy,\n entries,\n fromJson,\n genId,\n getRelays,\n libName,\n makeSocket,\n pauseRelayReconnection,\n resumeRelayReconnection,\n selfId,\n sha1,\n socketGetter,\n toJson,\n type BaseRoomConfig,\n type JoinRoom,\n type OfferRecord,\n type RelayConfig,\n type SocketClient\n} from '@trystero-p2p/core'\n\nconst clients: Record<string, SocketClient> = {}\nconst topicToInfoHash: Record<string, string> = {}\nconst infoHashToTopic: Record<string, string> = {}\nconst announceIntervals: Record<\n string,\n Record<string, ReturnType<typeof setInterval>>\n> = {}\nconst announceFns: Record<\n string,\n Record<string, () => void | Promise<void>>\n> = {}\nconst subscriptionTokens: Record<string, Record<string, symbol>> = {}\nconst trackerAnnounceMs: Record<string, number> = {}\nconst handledSignals: Record<string, number> = {}\nconst msgHandlers: Record<\n string,\n Record<string, ((data: TrackerMessage) => void) | undefined>\n> = {}\nconst trackerAction = 'announce'\nconst hashLimit = 20\nconst offerPoolSize = 10\nconst defaultAnnounceMs = 10_000\nconst maxAnnounceMs = 20_000\nconst offerRetentionMs = 120_000\nconst signalDedupeWindowMs = 4_000\nconst defaultRedundancy = 3\n\nexport type TorrentRoomConfig = BaseRoomConfig & RelayConfig\n\ntype TrackerMessage = {\n offer?: unknown\n answer?: unknown\n offer_id?: string\n peer_id?: string\n info_hash?: string\n interval?: number\n ['failure reason']?: string\n ['warning message']?: string\n}\n\nconst getInfoHash = async (topic: string): Promise<string> => {\n if (topicToInfoHash[topic]) {\n return topicToInfoHash[topic]\n }\n\n const hash = (await sha1(topic)).slice(0, hashLimit)\n topicToInfoHash[topic] = hash\n infoHashToTopic[hash] = topic\n\n return hash\n}\n\nconst send = async (\n client: SocketClient,\n topic: string,\n payload: Record<string, unknown>\n): Promise<void> => {\n client.send(\n toJson({\n action: trackerAction,\n info_hash: await getInfoHash(topic),\n peer_id: selfId,\n ...payload\n })\n )\n}\n\nconst warn = (url: string, msg: string, didFail = false): void =>\n console.warn(\n `${libName}: torrent tracker ${didFail ? 'failure' : 'warning'} from ${url} - ${msg}`\n )\n\nconst joinRoomStrategy: JoinRoom<TorrentRoomConfig> = createStrategy({\n init: config =>\n getRelays(config, defaultRelayUrls, defaultRedundancy).map(rawUrl => {\n const client = makeSocket(rawUrl, rawData => {\n const data = fromJson<TrackerMessage>(rawData)\n const errMsg = data['failure reason']\n const warnMsg = data['warning message']\n const {interval} = data\n const topic = data.info_hash\n ? infoHashToTopic[data.info_hash]\n : undefined\n\n if (errMsg) {\n warn(client.url, errMsg, true)\n return\n }\n\n if (warnMsg) {\n warn(client.url, warnMsg)\n }\n\n if (\n interval &&\n interval * 1000 >\n (trackerAnnounceMs[client.url] ?? defaultAnnounceMs) &&\n topic &&\n announceFns[client.url]?.[topic]\n ) {\n const nextInterval = Math.min(interval * 1000, maxAnnounceMs)\n const relayIntervals = (announceIntervals[client.url] ??= {})\n const relayFns = (announceFns[client.url] ??= {})\n\n if (relayIntervals[topic]) {\n clearInterval(relayIntervals[topic])\n }\n trackerAnnounceMs[client.url] = nextInterval\n const relayFn = relayFns[topic]\n\n if (relayFn) {\n relayIntervals[topic] = setInterval(relayFn, nextInterval)\n }\n }\n\n if ((data.offer || data.answer) && topic && data.offer_id) {\n if (data.peer_id === selfId) {\n return\n }\n\n const signalType = data.offer ? 'offer' : 'answer'\n const signalKey = `${topic}:${signalType}:${data.offer_id}:${data.peer_id ?? ''}`\n const nowMs = Date.now()\n const lastHandledMs = handledSignals[signalKey]\n\n if (\n typeof lastHandledMs === 'number' &&\n nowMs - lastHandledMs < signalDedupeWindowMs\n ) {\n return\n }\n\n handledSignals[signalKey] = nowMs\n\n entries(handledSignals).forEach(([key, handledAtMs]) => {\n if (nowMs - handledAtMs > signalDedupeWindowMs * 6) {\n delete handledSignals[key]\n }\n })\n\n msgHandlers[client.url]?.[topic]?.(data)\n }\n })\n\n const {url} = client\n\n clients[url] = client\n msgHandlers[url] = {}\n\n return client.ready\n }),\n\n subscribe: (client, rootTopic, _, onMessage, getOffers) => {\n const {url} = client\n const handlers = (msgHandlers[url] ??= {})\n const relayFns = (announceFns[url] ??= {})\n const relayIntervals = (announceIntervals[url] ??= {})\n const activeTokens = (subscriptionTokens[url] ??= {})\n const subscriptionToken = Symbol(rootTopic)\n const outstandingOffers: Record<string, OfferRecord & {createdAt: number}> =\n {}\n\n activeTokens[rootTopic] = subscriptionToken\n\n const claimOutstandingOffer = (\n offerId: string\n ): OfferRecord | undefined => {\n const offer = outstandingOffers[offerId]\n\n if (!offer) {\n return\n }\n\n delete outstandingOffers[offerId]\n offer.claim?.()\n\n return offer\n }\n\n const reclaimOutstandingOffer = (offerId: string): void => {\n const offer = outstandingOffers[offerId]\n\n if (!offer) {\n return\n }\n\n delete outstandingOffers[offerId]\n offer.reclaim?.()\n }\n\n const reclaimAllOutstandingOffers = (): void => {\n entries(outstandingOffers).forEach(([offerId]) => {\n reclaimOutstandingOffer(offerId)\n })\n }\n\n const pruneOutstandingOffers = (): void => {\n const now = Date.now()\n\n entries(outstandingOffers).forEach(([offerId, offer]) => {\n if (now - offer.createdAt > offerRetentionMs) {\n reclaimOutstandingOffer(offerId)\n }\n })\n }\n\n const topicHandler = (data: TrackerMessage): void => {\n if (data.offer && data.peer_id && data.offer_id) {\n void onMessage(\n rootTopic,\n {\n offer: data.offer,\n peerId: data.peer_id,\n hasOutgoingOffer: entries(outstandingOffers).length > 0\n },\n (_, signal) =>\n void send(client, rootTopic, {\n answer: fromJson<Record<string, unknown>>(signal)['answer'],\n offer_id: data.offer_id,\n to_peer_id: data.peer_id\n })\n )\n } else if (data.answer && data.offer_id && data.peer_id) {\n const offer = claimOutstandingOffer(data.offer_id)\n\n if (offer) {\n void onMessage(\n rootTopic,\n {\n answer: data.answer,\n peerId: data.peer_id,\n peer: offer.peer\n },\n () => {}\n )\n }\n }\n }\n\n handlers[rootTopic] = topicHandler\n\n const announce = async (): Promise<void> => {\n if (activeTokens[rootTopic] !== subscriptionToken) {\n return\n }\n\n pruneOutstandingOffers()\n\n const outstandingCount = entries(outstandingOffers).length\n const missingOffers = Math.max(0, offerPoolSize - outstandingCount)\n\n if (missingOffers > 0) {\n ;(await getOffers(missingOffers)).forEach(peerAndOffer => {\n outstandingOffers[genId(hashLimit)] = {\n ...peerAndOffer,\n createdAt: Date.now()\n }\n })\n }\n\n const offers = entries(outstandingOffers).map(([id, {offer}]) => ({\n offer_id: id,\n offer\n }))\n\n void send(client, rootTopic, {\n numwant: offerPoolSize,\n offers\n })\n }\n\n trackerAnnounceMs[url] = defaultAnnounceMs\n relayFns[rootTopic] = announce\n relayIntervals[rootTopic] = setInterval(announce, trackerAnnounceMs[url])\n void announce()\n\n return () => {\n if (activeTokens[rootTopic] !== subscriptionToken) {\n reclaimAllOutstandingOffers()\n\n return\n }\n\n const interval = relayIntervals[rootTopic]\n if (interval) {\n clearInterval(interval)\n delete relayIntervals[rootTopic]\n }\n\n if (handlers[rootTopic] === topicHandler) {\n delete handlers[rootTopic]\n }\n\n if (relayFns[rootTopic] === announce) {\n delete relayFns[rootTopic]\n }\n\n delete activeTokens[rootTopic]\n\n reclaimAllOutstandingOffers()\n }\n },\n\n announce: client => trackerAnnounceMs[client.url]\n})\n\nexport const joinRoom: JoinRoom<TorrentRoomConfig> = (\n config,\n roomId,\n callbacks\n) =>\n joinRoomStrategy(\n {...config, trickleIce: config.trickleIce ?? false},\n roomId,\n callbacks\n )\n\nexport const getRelaySockets = socketGetter(clients)\n\nexport {pauseRelayReconnection, resumeRelayReconnection, selfId}\n\nexport const defaultRelayUrls = [\n 'tracker.webtorrent.dev',\n 'tracker.openwebtorrent.com',\n 'tracker.btorrent.xyz',\n 'tracker.files.fm:7073/announce'\n].map(url => 'wss://' + url)\n\nexport type * from '@trystero-p2p/core'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n createRelayManager,\n createStrategy,\n entries,\n fromJson,\n genId,\n getRelays,\n keys,\n libName,\n makeSocket,\n pauseRelayReconnection,\n resumeRelayReconnection,\n selfId,\n sha1,\n toJson,\n type BaseRoomConfig,\n type JoinRoom,\n type OfferRecord,\n type RelayConfig,\n type SocketClient\n} from '@trystero-p2p/core'\n\nconst relayManager = createRelayManager<SocketClient>(client => client.socket)\nconst topicToInfoHash: Record<string, string> = {}\nconst infoHashToTopic: Record<string, string> = {}\nconst announceIntervals = relayManager.scoped<ReturnType<typeof setInterval>>()\nconst announceFns = relayManager.scoped<() => void | Promise<void>>()\nconst subscriptionTokens = relayManager.scoped<symbol>()\nconst trackerAnnounceMs: Record<string, number> = {}\nconst handledSignals: Record<string, number> = {}\nconst msgHandlers = relayManager.scoped<(data: TrackerMessage) => void>()\nconst roomOutstandingOffers: Record<\n string,\n Record<string, OfferRecord & {createdAt: number}>\n> = {}\nconst roomOfferGenerationPromises: Record<string, Promise<void> | undefined> =\n {}\nconst roomSubscriberCounts: Record<string, number> = {}\nconst trackerAction = 'announce'\nconst hashLimit = 20\nconst offerPoolSize = 3\nconst defaultAnnounceMs = 10_000\nconst maxAnnounceMs = 20_000\nconst offerRetentionMs = 120_000\nconst signalDedupeWindowMs = 4_000\nconst defaultRedundancy = 3\n\nexport type TorrentRoomConfig = BaseRoomConfig & RelayConfig\n\ntype TrackerMessage = {\n offer?: {\n type: 'offer'\n sdp: string\n }\n answer?: {\n type: 'answer'\n sdp: string\n }\n offer_id?: string\n peer_id?: string\n info_hash?: string\n interval?: number\n ['failure reason']?: string\n ['warning message']?: string\n}\n\nconst getInfoHash = async (topic: string): Promise<string> => {\n if (topicToInfoHash[topic]) {\n return topicToInfoHash[topic]\n }\n\n const hash = (await sha1(topic)).slice(0, hashLimit)\n topicToInfoHash[topic] = hash\n infoHashToTopic[hash] = topic\n\n return hash\n}\n\nconst send = async (\n client: SocketClient,\n topic: string,\n payload: Record<string, unknown>\n): Promise<void> =>\n client.send(\n toJson({\n action: trackerAction,\n info_hash: await getInfoHash(topic),\n peer_id: selfId,\n ...payload\n })\n )\n\nconst warn = (url: string, msg: string, didFail = false): void =>\n console.warn(\n `${libName}: torrent tracker ${didFail ? 'failure' : 'warning'} from ${url} - ${msg}`\n )\n\nconst getRoomOutstandingOffers = (\n rootTopic: string\n): Record<string, OfferRecord & {createdAt: number}> =>\n (roomOutstandingOffers[rootTopic] ??= {})\n\nconst deleteRoomOfferBookkeeping = (rootTopic: string): void => {\n delete roomOutstandingOffers[rootTopic]\n delete roomOfferGenerationPromises[rootTopic]\n}\n\nconst claimOutstandingOffer = (\n rootTopic: string,\n offerId: string\n): OfferRecord | undefined => {\n const outstandingOffers = roomOutstandingOffers[rootTopic]\n const offer = outstandingOffers?.[offerId]\n\n if (!offer) {\n return\n }\n\n delete outstandingOffers[offerId]\n offer.claim?.()\n\n if (!keys(outstandingOffers).length && !roomSubscriberCounts[rootTopic]) {\n deleteRoomOfferBookkeeping(rootTopic)\n }\n\n return offer\n}\n\nconst reclaimOutstandingOffer = (rootTopic: string, offerId: string): void => {\n const outstandingOffers = roomOutstandingOffers[rootTopic]\n const offer = outstandingOffers?.[offerId]\n\n if (!offer) {\n return\n }\n\n delete outstandingOffers[offerId]\n offer.reclaim?.()\n\n if (!keys(outstandingOffers).length && !roomSubscriberCounts[rootTopic]) {\n deleteRoomOfferBookkeeping(rootTopic)\n }\n}\n\nconst reclaimAllOutstandingOffers = (rootTopic: string): void => {\n keys(getRoomOutstandingOffers(rootTopic)).forEach(offerId =>\n reclaimOutstandingOffer(rootTopic, offerId)\n )\n deleteRoomOfferBookkeeping(rootTopic)\n}\n\nconst pruneOutstandingOffers = (rootTopic: string): void => {\n const now = Date.now()\n\n entries(getRoomOutstandingOffers(rootTopic)).forEach(([offerId, offer]) => {\n if (now - offer.createdAt > offerRetentionMs) {\n reclaimOutstandingOffer(rootTopic, offerId)\n }\n })\n}\n\nconst ensureOutstandingOffers = async (\n rootTopic: string,\n getOffers: (n: number) => Promise<OfferRecord[]>\n): Promise<Record<string, OfferRecord & {createdAt: number}>> => {\n while (roomOfferGenerationPromises[rootTopic]) {\n await roomOfferGenerationPromises[rootTopic]\n }\n\n const nextPromise = (async () => {\n pruneOutstandingOffers(rootTopic)\n\n const outstandingOffers = getRoomOutstandingOffers(rootTopic)\n const outstandingCount = keys(outstandingOffers).length\n const missingOffers = Math.max(0, offerPoolSize - outstandingCount)\n\n if (missingOffers > 0) {\n ;(await getOffers(missingOffers)).forEach(peerAndOffer => {\n outstandingOffers[genId(hashLimit)] = {\n ...peerAndOffer,\n createdAt: Date.now()\n }\n })\n }\n })().finally(() => {\n if (roomOfferGenerationPromises[rootTopic] === nextPromise) {\n delete roomOfferGenerationPromises[rootTopic]\n }\n })\n\n roomOfferGenerationPromises[rootTopic] = nextPromise\n await nextPromise\n\n return getRoomOutstandingOffers(rootTopic)\n}\n\nconst joinRoomStrategy: JoinRoom<TorrentRoomConfig> = createStrategy({\n init: config =>\n getRelays(config, defaultRelayUrls, defaultRedundancy).map(rawUrl => {\n const client = relayManager.register(\n rawUrl,\n makeSocket(rawUrl, rawData => {\n const data = fromJson<TrackerMessage>(rawData)\n const errMsg = data['failure reason']\n const warnMsg = data['warning message']\n const {interval} = data\n const topic = data.info_hash\n ? infoHashToTopic[data.info_hash]\n : undefined\n\n if (errMsg) {\n warn(client.url, errMsg, true)\n return\n }\n\n if (warnMsg) {\n warn(client.url, warnMsg)\n }\n\n if (\n interval &&\n interval * 1000 >\n (trackerAnnounceMs[client.url] ?? defaultAnnounceMs) &&\n topic &&\n announceFns.forKey(rawUrl)[topic]\n ) {\n const nextInterval = Math.min(interval * 1000, maxAnnounceMs)\n const relayIntervals = announceIntervals.forKey(rawUrl)\n const relayFns = announceFns.forKey(rawUrl)\n\n if (relayIntervals[topic]) {\n clearInterval(relayIntervals[topic])\n }\n trackerAnnounceMs[client.url] = nextInterval\n const relayFn = relayFns[topic]\n\n if (relayFn) {\n relayIntervals[topic] = setInterval(() => {\n void relayFn()\n }, nextInterval)\n }\n }\n\n if ((data.offer || data.answer) && topic && data.offer_id) {\n if (data.peer_id === selfId) {\n return\n }\n\n const signalType = data.offer ? 'offer' : 'answer'\n const signalKey = `${topic}:${signalType}:${data.offer_id}:${data.peer_id ?? ''}`\n const nowMs = Date.now()\n const lastHandledMs = handledSignals[signalKey]\n\n if (\n typeof lastHandledMs === 'number' &&\n nowMs - lastHandledMs < signalDedupeWindowMs\n ) {\n return\n }\n\n handledSignals[signalKey] = nowMs\n\n entries(handledSignals).forEach(([key, handledAtMs]) => {\n if (nowMs - handledAtMs > signalDedupeWindowMs * 6) {\n delete handledSignals[key]\n }\n })\n\n msgHandlers.forKey(rawUrl)[topic]?.(data)\n }\n })\n )\n\n return client.ready\n }),\n\n subscribe: (client, rootTopic, _, onMessage, getOffers) => {\n const handlers = msgHandlers.forRelay(client)\n const relayFns = announceFns.forRelay(client)\n const relayIntervals = announceIntervals.forRelay(client)\n const activeTokens = subscriptionTokens.forRelay(client)\n const subscriptionToken = Symbol(rootTopic)\n\n activeTokens[rootTopic] = subscriptionToken\n roomSubscriberCounts[rootTopic] = (roomSubscriberCounts[rootTopic] ?? 0) + 1\n\n const topicHandler = (data: TrackerMessage): void => {\n if (data.offer && data.peer_id && data.offer_id) {\n void onMessage(\n rootTopic,\n {\n offer: data.offer.sdp,\n peerId: data.peer_id,\n hasOutgoingOffer:\n keys(getRoomOutstandingOffers(rootTopic)).length > 0\n },\n (_, signal) =>\n void send(client, rootTopic, {\n answer: {\n type: 'answer',\n sdp: fromJson<{answer: string}>(signal).answer\n },\n offer_id: data.offer_id,\n to_peer_id: data.peer_id\n })\n )\n } else if (data.answer && data.offer_id && data.peer_id) {\n const offer = claimOutstandingOffer(rootTopic, data.offer_id)\n\n if (offer) {\n void onMessage(\n rootTopic,\n {\n answer: data.answer.sdp,\n peerId: data.peer_id,\n peer: offer.peer\n },\n () => {}\n )\n }\n }\n }\n\n handlers[rootTopic] = topicHandler\n\n const announce = async (): Promise<void> => {\n if (activeTokens[rootTopic] !== subscriptionToken) {\n return\n }\n\n const outstandingOffers = await ensureOutstandingOffers(\n rootTopic,\n getOffers\n )\n const offers = entries(outstandingOffers).map(([id, {offer}]) => ({\n offer_id: id,\n offer: {type: 'offer', sdp: offer}\n }))\n\n void send(client, rootTopic, {\n numwant: offerPoolSize,\n offers\n })\n }\n\n trackerAnnounceMs[client.url] = defaultAnnounceMs\n relayFns[rootTopic] = announce\n relayIntervals[rootTopic] = setInterval(\n announce,\n trackerAnnounceMs[client.url]\n )\n void announce()\n\n return () => {\n roomSubscriberCounts[rootTopic] = Math.max(\n 0,\n (roomSubscriberCounts[rootTopic] ?? 1) - 1\n )\n\n if (!roomSubscriberCounts[rootTopic]) {\n delete roomSubscriberCounts[rootTopic]\n }\n\n if (activeTokens[rootTopic] !== subscriptionToken) {\n if (!roomSubscriberCounts[rootTopic]) {\n reclaimAllOutstandingOffers(rootTopic)\n }\n\n return\n }\n\n const interval = relayIntervals[rootTopic]\n if (interval) {\n clearInterval(interval)\n delete relayIntervals[rootTopic]\n }\n\n if (handlers[rootTopic] === topicHandler) {\n delete handlers[rootTopic]\n }\n\n if (relayFns[rootTopic] === announce) {\n delete relayFns[rootTopic]\n }\n\n delete activeTokens[rootTopic]\n\n if (!roomSubscriberCounts[rootTopic]) {\n reclaimAllOutstandingOffers(rootTopic)\n }\n }\n },\n\n announce: client => trackerAnnounceMs[client.url]\n})\n\nexport const joinRoom: JoinRoom<TorrentRoomConfig> = (\n config,\n roomId,\n callbacks\n) =>\n joinRoomStrategy(\n {\n ...config,\n trickleIce: config.trickleIce ?? false\n },\n roomId,\n callbacks\n )\n\nexport const getRelaySockets = relayManager.getSockets\n\nexport {pauseRelayReconnection, resumeRelayReconnection, selfId}\n\nexport const defaultRelayUrls = [\n 'tracker.webtorrent.dev',\n 'tracker.openwebtorrent.com',\n 'tracker.btorrent.xyz',\n 'tracker.files.fm:7073/announce'\n].map(url => 'wss://' + url)\n\nexport type * from '@trystero-p2p/core'\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trystero-p2p/torrent",
|
|
3
|
-
"version": "0.23.
|
|
3
|
+
"version": "0.23.1",
|
|
4
4
|
"description": "Torrent tracker strategy for Trystero",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bittorrent",
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
30
|
"type": "module",
|
|
31
|
-
"types": "./dist/index.d.
|
|
31
|
+
"types": "./dist/index.d.mts",
|
|
32
32
|
"exports": {
|
|
33
33
|
".": "./dist/index.mjs",
|
|
34
34
|
"./package.json": "./package.json"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@trystero-p2p/core": "0.23.
|
|
37
|
+
"@trystero-p2p/core": "0.23.1"
|
|
38
38
|
}
|
|
39
39
|
}
|