@trystero-p2p/torrent 0.23.0-beta.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2021 Dan Motzenbecker
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,11 @@
1
+ import { BaseRoomConfig, JoinRoom, RelayConfig, pauseRelayReconnection, resumeRelayReconnection, selfId } from "@trystero-p2p/core";
2
+ export * from "@trystero-p2p/core";
3
+
4
+ //#region src/index.d.ts
5
+ type TorrentRoomConfig = BaseRoomConfig & RelayConfig;
6
+ declare const joinRoom: JoinRoom<TorrentRoomConfig>;
7
+ declare const getRelaySockets: any;
8
+ declare const defaultRelayUrls: string[];
9
+ //#endregion
10
+ export { TorrentRoomConfig, defaultRelayUrls, getRelaySockets, joinRoom, pauseRelayReconnection, resumeRelayReconnection, selfId };
11
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;KAgDY,iBAAA,GAAoB,cAAA,GAAiB,WAAA;AAAA,cAuRpC,QAAA,EAAU,QAAA,CAAS,iBAAA;AAAA,cAWnB,eAAA;AAAA,cAIA,gBAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,184 @@
1
+ import { createStrategy, entries, fromJson, genId, getRelays, libName, makeSocket, pauseRelayReconnection, resumeRelayReconnection, selfId, sha1, socketGetter, toJson } from "@trystero-p2p/core";
2
+ //#region src/index.ts
3
+ const clients = {};
4
+ const topicToInfoHash = {};
5
+ const infoHashToTopic = {};
6
+ const announceIntervals = {};
7
+ const announceFns = {};
8
+ const subscriptionTokens = {};
9
+ const trackerAnnounceMs = {};
10
+ const handledSignals = {};
11
+ const msgHandlers = {};
12
+ const trackerAction = "announce";
13
+ const hashLimit = 20;
14
+ const offerPoolSize = 10;
15
+ const defaultAnnounceMs = 1e4;
16
+ const maxAnnounceMs = 2e4;
17
+ const offerRetentionMs = 12e4;
18
+ const signalDedupeWindowMs = 4e3;
19
+ const defaultRedundancy = 3;
20
+ const getInfoHash = async (topic) => {
21
+ if (topicToInfoHash[topic]) return topicToInfoHash[topic];
22
+ const hash = (await sha1(topic)).slice(0, hashLimit);
23
+ topicToInfoHash[topic] = hash;
24
+ infoHashToTopic[hash] = topic;
25
+ return hash;
26
+ };
27
+ const send = async (client, topic, payload) => {
28
+ client.send(toJson({
29
+ action: trackerAction,
30
+ info_hash: await getInfoHash(topic),
31
+ peer_id: selfId,
32
+ ...payload
33
+ }));
34
+ };
35
+ const warn = (url, msg, didFail = false) => console.warn(`${libName}: torrent tracker ${didFail ? "failure" : "warning"} from ${url} - ${msg}`);
36
+ const joinRoomStrategy = createStrategy({
37
+ init: (config) => getRelays(config, defaultRelayUrls, defaultRedundancy).map((rawUrl) => {
38
+ const client = makeSocket(rawUrl, (rawData) => {
39
+ const data = fromJson(rawData);
40
+ const errMsg = data["failure reason"];
41
+ const warnMsg = data["warning message"];
42
+ const { interval } = data;
43
+ const topic = data.info_hash ? infoHashToTopic[data.info_hash] : void 0;
44
+ if (errMsg) {
45
+ warn(client.url, errMsg, true);
46
+ return;
47
+ }
48
+ if (warnMsg) warn(client.url, warnMsg);
49
+ if (interval && interval * 1e3 > (trackerAnnounceMs[client.url] ?? defaultAnnounceMs) && topic && announceFns[client.url]?.[topic]) {
50
+ const nextInterval = Math.min(interval * 1e3, maxAnnounceMs);
51
+ const relayIntervals = announceIntervals[client.url] ??= {};
52
+ const relayFns = announceFns[client.url] ??= {};
53
+ if (relayIntervals[topic]) clearInterval(relayIntervals[topic]);
54
+ trackerAnnounceMs[client.url] = nextInterval;
55
+ const relayFn = relayFns[topic];
56
+ if (relayFn) relayIntervals[topic] = setInterval(relayFn, nextInterval);
57
+ }
58
+ if ((data.offer || data.answer) && topic && data.offer_id) {
59
+ if (data.peer_id === selfId) return;
60
+ const signalKey = `${topic}:${data.offer ? "offer" : "answer"}:${data.offer_id}:${data.peer_id ?? ""}`;
61
+ const nowMs = Date.now();
62
+ const lastHandledMs = handledSignals[signalKey];
63
+ if (typeof lastHandledMs === "number" && nowMs - lastHandledMs < signalDedupeWindowMs) return;
64
+ handledSignals[signalKey] = nowMs;
65
+ entries(handledSignals).forEach(([key, handledAtMs]) => {
66
+ if (nowMs - handledAtMs > signalDedupeWindowMs * 6) delete handledSignals[key];
67
+ });
68
+ msgHandlers[client.url]?.[topic]?.(data);
69
+ }
70
+ });
71
+ const { url } = client;
72
+ clients[url] = client;
73
+ msgHandlers[url] = {};
74
+ return client.ready;
75
+ }),
76
+ subscribe: (client, rootTopic, _, onMessage, getOffers) => {
77
+ const { url } = client;
78
+ const handlers = msgHandlers[url] ??= {};
79
+ const relayFns = announceFns[url] ??= {};
80
+ const relayIntervals = announceIntervals[url] ??= {};
81
+ const activeTokens = subscriptionTokens[url] ??= {};
82
+ const subscriptionToken = Symbol(rootTopic);
83
+ const outstandingOffers = {};
84
+ activeTokens[rootTopic] = subscriptionToken;
85
+ const claimOutstandingOffer = (offerId) => {
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
+ };
109
+ const topicHandler = (data) => {
110
+ if (data.offer && data.peer_id && data.offer_id) onMessage(rootTopic, {
111
+ offer: data.offer,
112
+ peerId: data.peer_id,
113
+ hasOutgoingOffer: entries(outstandingOffers).length > 0
114
+ }, (_, signal) => void send(client, rootTopic, {
115
+ answer: fromJson(signal)["answer"],
116
+ offer_id: data.offer_id,
117
+ to_peer_id: data.peer_id
118
+ }));
119
+ else if (data.answer && data.offer_id && data.peer_id) {
120
+ const offer = claimOutstandingOffer(data.offer_id);
121
+ if (offer) onMessage(rootTopic, {
122
+ answer: data.answer,
123
+ peerId: data.peer_id,
124
+ peer: offer.peer
125
+ }, () => {});
126
+ }
127
+ };
128
+ handlers[rootTopic] = topicHandler;
129
+ const announce = async () => {
130
+ 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
+ send(client, rootTopic, {
141
+ numwant: offerPoolSize,
142
+ offers: entries(outstandingOffers).map(([id, { offer }]) => ({
143
+ offer_id: id,
144
+ offer
145
+ }))
146
+ });
147
+ };
148
+ trackerAnnounceMs[url] = defaultAnnounceMs;
149
+ relayFns[rootTopic] = announce;
150
+ relayIntervals[rootTopic] = setInterval(announce, trackerAnnounceMs[url]);
151
+ announce();
152
+ return () => {
153
+ if (activeTokens[rootTopic] !== subscriptionToken) {
154
+ reclaimAllOutstandingOffers();
155
+ return;
156
+ }
157
+ const interval = relayIntervals[rootTopic];
158
+ if (interval) {
159
+ clearInterval(interval);
160
+ delete relayIntervals[rootTopic];
161
+ }
162
+ if (handlers[rootTopic] === topicHandler) delete handlers[rootTopic];
163
+ if (relayFns[rootTopic] === announce) delete relayFns[rootTopic];
164
+ delete activeTokens[rootTopic];
165
+ reclaimAllOutstandingOffers();
166
+ };
167
+ },
168
+ announce: (client) => trackerAnnounceMs[client.url]
169
+ });
170
+ const joinRoom = (config, roomId, callbacks) => joinRoomStrategy({
171
+ ...config,
172
+ trickleIce: config.trickleIce ?? false
173
+ }, roomId, callbacks);
174
+ const getRelaySockets = socketGetter(clients);
175
+ const defaultRelayUrls = [
176
+ "tracker.webtorrent.dev",
177
+ "tracker.openwebtorrent.com",
178
+ "tracker.btorrent.xyz",
179
+ "tracker.files.fm:7073/announce"
180
+ ].map((url) => "wss://" + url);
181
+ //#endregion
182
+ export { defaultRelayUrls, getRelaySockets, joinRoom, pauseRelayReconnection, resumeRelayReconnection, selfId };
183
+
184
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +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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"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@trystero-p2p/torrent",
3
+ "version": "0.23.0-beta.1",
4
+ "description": "Torrent tracker strategy for Trystero",
5
+ "keywords": [
6
+ "bittorrent",
7
+ "chat",
8
+ "decentralized",
9
+ "matchmaking",
10
+ "p2p",
11
+ "pairing",
12
+ "peer to peer",
13
+ "react",
14
+ "realtime",
15
+ "serverless",
16
+ "signaling",
17
+ "torrent",
18
+ "webrtc",
19
+ "webtorrent"
20
+ ],
21
+ "license": "MIT",
22
+ "author": {
23
+ "name": "Dan Motzenbecker",
24
+ "email": "dan@oxism.com",
25
+ "url": "https://oxism.com"
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "type": "module",
31
+ "types": "./dist/index.d.ts",
32
+ "exports": {
33
+ ".": "./dist/index.mjs",
34
+ "./package.json": "./package.json"
35
+ },
36
+ "dependencies": {
37
+ "@trystero-p2p/core": "0.23.0-beta.1"
38
+ }
39
+ }