@libp2p/circuit-relay-v2 0.0.0-05b52d69c
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 +4 -0
- package/README.md +69 -0
- package/dist/index.min.js +45 -0
- package/dist/src/constants.d.ts +55 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +61 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/index.d.ts +56 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +39 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/pb/index.d.ts +93 -0
- package/dist/src/pb/index.d.ts.map +1 -0
- package/dist/src/pb/index.js +425 -0
- package/dist/src/pb/index.js.map +1 -0
- package/dist/src/server/advert-service.d.ts +46 -0
- package/dist/src/server/advert-service.d.ts.map +1 -0
- package/dist/src/server/advert-service.js +72 -0
- package/dist/src/server/advert-service.js.map +1 -0
- package/dist/src/server/index.d.ts +67 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +313 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/reservation-store.d.ts +49 -0
- package/dist/src/server/reservation-store.d.ts.map +1 -0
- package/dist/src/server/reservation-store.js +65 -0
- package/dist/src/server/reservation-store.js.map +1 -0
- package/dist/src/server/reservation-voucher.d.ts +18 -0
- package/dist/src/server/reservation-voucher.d.ts.map +1 -0
- package/dist/src/server/reservation-voucher.js +36 -0
- package/dist/src/server/reservation-voucher.js.map +1 -0
- package/dist/src/transport/discovery.d.ts +48 -0
- package/dist/src/transport/discovery.d.ts.map +1 -0
- package/dist/src/transport/discovery.js +97 -0
- package/dist/src/transport/discovery.js.map +1 -0
- package/dist/src/transport/index.d.ts +58 -0
- package/dist/src/transport/index.d.ts.map +1 -0
- package/dist/src/transport/index.js +279 -0
- package/dist/src/transport/index.js.map +1 -0
- package/dist/src/transport/listener.d.ts +11 -0
- package/dist/src/transport/listener.d.ts.map +1 -0
- package/dist/src/transport/listener.js +66 -0
- package/dist/src/transport/listener.js.map +1 -0
- package/dist/src/transport/reservation-store.d.ts +74 -0
- package/dist/src/transport/reservation-store.d.ts.map +1 -0
- package/dist/src/transport/reservation-store.js +209 -0
- package/dist/src/transport/reservation-store.js.map +1 -0
- package/dist/src/utils.d.ts +14 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +106 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +83 -0
- package/src/constants.ts +79 -0
- package/src/index.ts +64 -0
- package/src/pb/index.proto +67 -0
- package/src/pb/index.ts +539 -0
- package/src/server/advert-service.ts +109 -0
- package/src/server/index.ts +446 -0
- package/src/server/reservation-store.ts +116 -0
- package/src/server/reservation-voucher.ts +51 -0
- package/src/transport/discovery.ts +138 -0
- package/src/transport/index.ts +399 -0
- package/src/transport/listener.ts +98 -0
- package/src/transport/reservation-store.ts +312 -0
- package/src/utils.ts +134 -0
@@ -0,0 +1,209 @@
|
|
1
|
+
import { TypedEventEmitter } from '@libp2p/interface/events';
|
2
|
+
import { PeerMap } from '@libp2p/peer-collections';
|
3
|
+
import { PeerJobQueue } from '@libp2p/utils/peer-job-queue';
|
4
|
+
import { multiaddr } from '@multiformats/multiaddr';
|
5
|
+
import { pbStream } from 'it-protobuf-stream';
|
6
|
+
import { DEFAULT_RESERVATION_CONCURRENCY, RELAY_TAG, RELAY_V2_HOP_CODEC } from '../constants.js';
|
7
|
+
import { HopMessage, Status } from '../pb/index.js';
|
8
|
+
import { getExpirationMilliseconds } from '../utils.js';
|
9
|
+
// allow refreshing a relay reservation if it will expire in the next 10 minutes
|
10
|
+
const REFRESH_WINDOW = (60 * 1000) * 10;
|
11
|
+
// try to refresh relay reservations 5 minutes before expiry
|
12
|
+
const REFRESH_TIMEOUT = (60 * 1000) * 5;
|
13
|
+
// minimum duration before which a reservation must not be refreshed
|
14
|
+
const REFRESH_TIMEOUT_MIN = 30 * 1000;
|
15
|
+
export class ReservationStore extends TypedEventEmitter {
|
16
|
+
peerId;
|
17
|
+
connectionManager;
|
18
|
+
transportManager;
|
19
|
+
peerStore;
|
20
|
+
events;
|
21
|
+
reserveQueue;
|
22
|
+
reservations;
|
23
|
+
maxDiscoveredRelays;
|
24
|
+
maxReservationQueueLength;
|
25
|
+
reservationCompletionTimeout;
|
26
|
+
started;
|
27
|
+
log;
|
28
|
+
constructor(components, init) {
|
29
|
+
super();
|
30
|
+
this.log = components.logger.forComponent('libp2p:circuit-relay:transport:reservation-store');
|
31
|
+
this.peerId = components.peerId;
|
32
|
+
this.connectionManager = components.connectionManager;
|
33
|
+
this.transportManager = components.transportManager;
|
34
|
+
this.peerStore = components.peerStore;
|
35
|
+
this.events = components.events;
|
36
|
+
this.reservations = new PeerMap();
|
37
|
+
this.maxDiscoveredRelays = init?.discoverRelays ?? 0;
|
38
|
+
this.maxReservationQueueLength = init?.maxReservationQueueLength ?? 100;
|
39
|
+
this.reservationCompletionTimeout = init?.reservationCompletionTimeout ?? 10000;
|
40
|
+
this.started = false;
|
41
|
+
// ensure we don't listen on multiple relays simultaneously
|
42
|
+
this.reserveQueue = new PeerJobQueue({
|
43
|
+
concurrency: init?.reservationConcurrency ?? DEFAULT_RESERVATION_CONCURRENCY
|
44
|
+
});
|
45
|
+
// When a peer disconnects, if we had a reservation on that peer
|
46
|
+
// remove the reservation and multiaddr and maybe trigger search
|
47
|
+
// for new relays
|
48
|
+
this.events.addEventListener('peer:disconnect', (evt) => {
|
49
|
+
this.#removeRelay(evt.detail);
|
50
|
+
});
|
51
|
+
}
|
52
|
+
isStarted() {
|
53
|
+
return this.started;
|
54
|
+
}
|
55
|
+
async start() {
|
56
|
+
this.started = true;
|
57
|
+
}
|
58
|
+
async stop() {
|
59
|
+
this.reserveQueue.clear();
|
60
|
+
this.reservations.forEach(({ timeout }) => {
|
61
|
+
clearTimeout(timeout);
|
62
|
+
});
|
63
|
+
this.reservations.clear();
|
64
|
+
this.started = false;
|
65
|
+
}
|
66
|
+
/**
|
67
|
+
* If the number of current relays is beneath the configured `maxReservations`
|
68
|
+
* value, and the passed peer id is not our own, and we have a non-relayed connection
|
69
|
+
* to the remote, and the remote peer speaks the hop protocol, try to reserve a slot
|
70
|
+
* on the remote peer
|
71
|
+
*/
|
72
|
+
async addRelay(peerId, type) {
|
73
|
+
if (this.peerId.equals(peerId)) {
|
74
|
+
this.log('not trying to use self as relay');
|
75
|
+
return;
|
76
|
+
}
|
77
|
+
if (this.reserveQueue.size > this.maxReservationQueueLength) {
|
78
|
+
this.log('not adding relay as the queue is full');
|
79
|
+
return;
|
80
|
+
}
|
81
|
+
if (this.reserveQueue.hasJob(peerId)) {
|
82
|
+
this.log('relay peer is already in the reservation queue');
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
this.log('add relay %p', peerId);
|
86
|
+
await this.reserveQueue.add(async () => {
|
87
|
+
try {
|
88
|
+
// allow refresh of an existing reservation if it is about to expire
|
89
|
+
const existingReservation = this.reservations.get(peerId);
|
90
|
+
if (existingReservation != null) {
|
91
|
+
if (getExpirationMilliseconds(existingReservation.reservation.expire) > REFRESH_WINDOW) {
|
92
|
+
this.log('already have reservation on relay peer %p and it expires in more than 10 minutes', peerId);
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
clearTimeout(existingReservation.timeout);
|
96
|
+
this.reservations.delete(peerId);
|
97
|
+
}
|
98
|
+
if (type === 'discovered' && [...this.reservations.values()].reduce((acc, curr) => {
|
99
|
+
if (curr.type === 'discovered') {
|
100
|
+
acc++;
|
101
|
+
}
|
102
|
+
return acc;
|
103
|
+
}, 0) >= this.maxDiscoveredRelays) {
|
104
|
+
this.log('already have enough discovered relays');
|
105
|
+
return;
|
106
|
+
}
|
107
|
+
const signal = AbortSignal.timeout(this.reservationCompletionTimeout);
|
108
|
+
const connection = await this.connectionManager.openConnection(peerId, {
|
109
|
+
signal
|
110
|
+
});
|
111
|
+
if (connection.remoteAddr.protoNames().includes('p2p-circuit')) {
|
112
|
+
this.log('not creating reservation over relayed connection');
|
113
|
+
return;
|
114
|
+
}
|
115
|
+
const reservation = await this.#createReservation(connection, {
|
116
|
+
signal
|
117
|
+
});
|
118
|
+
this.log('created reservation on relay peer %p', peerId);
|
119
|
+
const expiration = getExpirationMilliseconds(reservation.expire);
|
120
|
+
// sets a lower bound on the timeout, and also don't let it go over
|
121
|
+
// 2^31 - 1 (setTimeout will only accept signed 32 bit integers)
|
122
|
+
const timeoutDuration = Math.min(Math.max(expiration - REFRESH_TIMEOUT, REFRESH_TIMEOUT_MIN), Math.pow(2, 31) - 1);
|
123
|
+
const timeout = setTimeout(() => {
|
124
|
+
this.addRelay(peerId, type).catch(err => {
|
125
|
+
this.log.error('could not refresh reservation to relay %p', peerId, err);
|
126
|
+
});
|
127
|
+
}, timeoutDuration);
|
128
|
+
// we've managed to create a reservation successfully
|
129
|
+
this.reservations.set(peerId, {
|
130
|
+
timeout,
|
131
|
+
reservation,
|
132
|
+
type
|
133
|
+
});
|
134
|
+
// ensure we don't close the connection to the relay
|
135
|
+
await this.peerStore.merge(peerId, {
|
136
|
+
tags: {
|
137
|
+
[RELAY_TAG]: {
|
138
|
+
value: 1,
|
139
|
+
ttl: expiration
|
140
|
+
}
|
141
|
+
}
|
142
|
+
});
|
143
|
+
// listen on multiaddr that only the circuit transport is listening for
|
144
|
+
await this.transportManager.listen([multiaddr(`/p2p/${peerId.toString()}/p2p-circuit`)]);
|
145
|
+
}
|
146
|
+
catch (err) {
|
147
|
+
this.log.error('could not reserve slot on %p', peerId, err);
|
148
|
+
// cancel the renewal timeout if it's been set
|
149
|
+
const reservation = this.reservations.get(peerId);
|
150
|
+
if (reservation != null) {
|
151
|
+
clearTimeout(reservation.timeout);
|
152
|
+
}
|
153
|
+
// if listening failed, remove the reservation
|
154
|
+
this.reservations.delete(peerId);
|
155
|
+
}
|
156
|
+
}, {
|
157
|
+
peerId
|
158
|
+
});
|
159
|
+
}
|
160
|
+
hasReservation(peerId) {
|
161
|
+
return this.reservations.has(peerId);
|
162
|
+
}
|
163
|
+
getReservation(peerId) {
|
164
|
+
return this.reservations.get(peerId)?.reservation;
|
165
|
+
}
|
166
|
+
async #createReservation(connection, options) {
|
167
|
+
options.signal?.throwIfAborted();
|
168
|
+
this.log('requesting reservation from %p', connection.remotePeer);
|
169
|
+
const stream = await connection.newStream(RELAY_V2_HOP_CODEC, options);
|
170
|
+
const pbstr = pbStream(stream);
|
171
|
+
const hopstr = pbstr.pb(HopMessage);
|
172
|
+
await hopstr.write({ type: HopMessage.Type.RESERVE }, options);
|
173
|
+
let response;
|
174
|
+
try {
|
175
|
+
response = await hopstr.read(options);
|
176
|
+
}
|
177
|
+
catch (err) {
|
178
|
+
this.log.error('error parsing reserve message response from %p because', connection.remotePeer, err);
|
179
|
+
throw err;
|
180
|
+
}
|
181
|
+
finally {
|
182
|
+
await stream.close();
|
183
|
+
}
|
184
|
+
if (response.status === Status.OK && (response.reservation != null)) {
|
185
|
+
return response.reservation;
|
186
|
+
}
|
187
|
+
const errMsg = `reservation failed with status ${response.status ?? 'undefined'}`;
|
188
|
+
this.log.error(errMsg);
|
189
|
+
throw new Error(errMsg);
|
190
|
+
}
|
191
|
+
/**
|
192
|
+
* Remove listen relay
|
193
|
+
*/
|
194
|
+
#removeRelay(peerId) {
|
195
|
+
const existingReservation = this.reservations.get(peerId);
|
196
|
+
if (existingReservation == null) {
|
197
|
+
return;
|
198
|
+
}
|
199
|
+
this.log('connection to relay %p closed, removing reservation from local store', peerId);
|
200
|
+
clearTimeout(existingReservation.timeout);
|
201
|
+
this.reservations.delete(peerId);
|
202
|
+
this.safeDispatchEvent('relay:removed', { detail: peerId });
|
203
|
+
if (this.reservations.size < this.maxDiscoveredRelays) {
|
204
|
+
this.log('not enough relays %d/%d', this.reservations.size, this.maxDiscoveredRelays);
|
205
|
+
this.safeDispatchEvent('relay:not-enough-relays', {});
|
206
|
+
}
|
207
|
+
}
|
208
|
+
}
|
209
|
+
//# sourceMappingURL=reservation-store.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"reservation-store.js","sourceRoot":"","sources":["../../../src/transport/reservation-store.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { CID } from 'multiformats/cid';
|
2
|
+
import type { Limit } from './pb/index.js';
|
3
|
+
import type { LoggerOptions } from '@libp2p/interface';
|
4
|
+
import type { Stream } from '@libp2p/interface/connection';
|
5
|
+
export declare function createLimitedRelay(src: Stream, dst: Stream, abortSignal: AbortSignal, limit: Limit | undefined, options: LoggerOptions): void;
|
6
|
+
/**
|
7
|
+
* Convert a namespace string into a cid
|
8
|
+
*/
|
9
|
+
export declare function namespaceToCid(namespace: string): Promise<CID>;
|
10
|
+
/**
|
11
|
+
* returns number of ms between now and expiration time
|
12
|
+
*/
|
13
|
+
export declare function getExpirationMilliseconds(expireTimeSeconds: bigint): number;
|
14
|
+
//# sourceMappingURL=utils.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAGtC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAA;AA+B1D,wBAAgB,kBAAkB,CAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CA0E9I;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAKrE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAE,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAM5E"}
|
@@ -0,0 +1,106 @@
|
|
1
|
+
import { CodeError } from '@libp2p/interface/errors';
|
2
|
+
import { anySignal } from 'any-signal';
|
3
|
+
import { CID } from 'multiformats/cid';
|
4
|
+
import { sha256 } from 'multiformats/hashes/sha2';
|
5
|
+
import { ERR_TRANSFER_LIMIT_EXCEEDED } from './constants.js';
|
6
|
+
async function* countStreamBytes(source, limit, options) {
|
7
|
+
const limitBytes = limit.remaining;
|
8
|
+
for await (const buf of source) {
|
9
|
+
const len = BigInt(buf.byteLength);
|
10
|
+
if ((limit.remaining - len) < 0) {
|
11
|
+
// this is a safe downcast since len is guarantee to be in the range for a number
|
12
|
+
const remaining = Number(limit.remaining);
|
13
|
+
limit.remaining = 0n;
|
14
|
+
try {
|
15
|
+
if (remaining !== 0) {
|
16
|
+
yield buf.subarray(0, remaining);
|
17
|
+
}
|
18
|
+
}
|
19
|
+
catch (err) {
|
20
|
+
options.log.error(err);
|
21
|
+
}
|
22
|
+
throw new CodeError(`data limit of ${limitBytes} bytes exceeded`, ERR_TRANSFER_LIMIT_EXCEEDED);
|
23
|
+
}
|
24
|
+
limit.remaining -= len;
|
25
|
+
yield buf;
|
26
|
+
}
|
27
|
+
}
|
28
|
+
export function createLimitedRelay(src, dst, abortSignal, limit, options) {
|
29
|
+
function abortStreams(err) {
|
30
|
+
src.abort(err);
|
31
|
+
dst.abort(err);
|
32
|
+
clearTimeout(timeout);
|
33
|
+
}
|
34
|
+
const abortController = new AbortController();
|
35
|
+
const signal = anySignal([abortSignal, abortController.signal]);
|
36
|
+
let timeout;
|
37
|
+
if (limit?.duration != null) {
|
38
|
+
timeout = setTimeout(() => {
|
39
|
+
abortController.abort();
|
40
|
+
}, limit.duration);
|
41
|
+
}
|
42
|
+
let srcDstFinished = false;
|
43
|
+
let dstSrcFinished = false;
|
44
|
+
let dataLimit;
|
45
|
+
if (limit?.data != null) {
|
46
|
+
dataLimit = {
|
47
|
+
remaining: limit.data
|
48
|
+
};
|
49
|
+
}
|
50
|
+
queueMicrotask(() => {
|
51
|
+
const onAbort = () => {
|
52
|
+
dst.abort(new CodeError(`duration limit of ${limit?.duration} ms exceeded`, ERR_TRANSFER_LIMIT_EXCEEDED));
|
53
|
+
};
|
54
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
55
|
+
void dst.sink(dataLimit == null ? src.source : countStreamBytes(src.source, dataLimit, options))
|
56
|
+
.catch(err => {
|
57
|
+
options.log.error('error while relaying streams src -> dst', err);
|
58
|
+
abortStreams(err);
|
59
|
+
})
|
60
|
+
.finally(() => {
|
61
|
+
srcDstFinished = true;
|
62
|
+
if (dstSrcFinished) {
|
63
|
+
signal.removeEventListener('abort', onAbort);
|
64
|
+
signal.clear();
|
65
|
+
clearTimeout(timeout);
|
66
|
+
}
|
67
|
+
});
|
68
|
+
});
|
69
|
+
queueMicrotask(() => {
|
70
|
+
const onAbort = () => {
|
71
|
+
src.abort(new CodeError(`duration limit of ${limit?.duration} ms exceeded`, ERR_TRANSFER_LIMIT_EXCEEDED));
|
72
|
+
};
|
73
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
74
|
+
void src.sink(dataLimit == null ? dst.source : countStreamBytes(dst.source, dataLimit, options))
|
75
|
+
.catch(err => {
|
76
|
+
options.log.error('error while relaying streams dst -> src', err);
|
77
|
+
abortStreams(err);
|
78
|
+
})
|
79
|
+
.finally(() => {
|
80
|
+
dstSrcFinished = true;
|
81
|
+
if (srcDstFinished) {
|
82
|
+
signal.removeEventListener('abort', onAbort);
|
83
|
+
signal.clear();
|
84
|
+
clearTimeout(timeout);
|
85
|
+
}
|
86
|
+
});
|
87
|
+
});
|
88
|
+
}
|
89
|
+
/**
|
90
|
+
* Convert a namespace string into a cid
|
91
|
+
*/
|
92
|
+
export async function namespaceToCid(namespace) {
|
93
|
+
const bytes = new TextEncoder().encode(namespace);
|
94
|
+
const hash = await sha256.digest(bytes);
|
95
|
+
return CID.createV0(hash);
|
96
|
+
}
|
97
|
+
/**
|
98
|
+
* returns number of ms between now and expiration time
|
99
|
+
*/
|
100
|
+
export function getExpirationMilliseconds(expireTimeSeconds) {
|
101
|
+
const expireTimeMillis = expireTimeSeconds * BigInt(1000);
|
102
|
+
const currentTime = new Date().getTime();
|
103
|
+
// downcast to number to use with setTimeout
|
104
|
+
return Number(expireTimeMillis - BigInt(currentTime));
|
105
|
+
}
|
106
|
+
//# sourceMappingURL=utils.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
{
|
2
|
+
"name": "@libp2p/circuit-relay-v2",
|
3
|
+
"version": "0.0.0-05b52d69c",
|
4
|
+
"description": "Implementation of Circuit Relay v2",
|
5
|
+
"license": "Apache-2.0 OR MIT",
|
6
|
+
"homepage": "https://github.com/libp2p/js-libp2p/tree/master/packages/transport-circuit-relay-v2#readme",
|
7
|
+
"repository": {
|
8
|
+
"type": "git",
|
9
|
+
"url": "git+https://github.com/libp2p/js-libp2p.git"
|
10
|
+
},
|
11
|
+
"bugs": {
|
12
|
+
"url": "https://github.com/libp2p/js-libp2p/issues"
|
13
|
+
},
|
14
|
+
"type": "module",
|
15
|
+
"types": "./dist/src/index.d.ts",
|
16
|
+
"files": [
|
17
|
+
"src",
|
18
|
+
"dist",
|
19
|
+
"!dist/test",
|
20
|
+
"!**/*.tsbuildinfo"
|
21
|
+
],
|
22
|
+
"exports": {
|
23
|
+
".": {
|
24
|
+
"types": "./dist/src/index.d.ts",
|
25
|
+
"import": "./dist/src/index.js"
|
26
|
+
}
|
27
|
+
},
|
28
|
+
"eslintConfig": {
|
29
|
+
"extends": "ipfs",
|
30
|
+
"parserOptions": {
|
31
|
+
"project": true,
|
32
|
+
"sourceType": "module"
|
33
|
+
}
|
34
|
+
},
|
35
|
+
"scripts": {
|
36
|
+
"start": "node dist/src/main.js",
|
37
|
+
"build": "aegir build",
|
38
|
+
"test": "aegir test",
|
39
|
+
"clean": "aegir clean",
|
40
|
+
"generate": "protons ./src/pb/index.proto",
|
41
|
+
"lint": "aegir lint",
|
42
|
+
"test:chrome": "aegir test -t browser --cov",
|
43
|
+
"test:chrome-webworker": "aegir test -t webworker",
|
44
|
+
"test:firefox": "aegir test -t browser -- --browser firefox",
|
45
|
+
"test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
|
46
|
+
"test:node": "aegir test -t node --cov",
|
47
|
+
"dep-check": "aegir dep-check"
|
48
|
+
},
|
49
|
+
"dependencies": {
|
50
|
+
"@libp2p/interface": "0.1.6-05b52d69c",
|
51
|
+
"@libp2p/interface-internal": "0.1.9-05b52d69c",
|
52
|
+
"@libp2p/peer-collections": "4.0.8-05b52d69c",
|
53
|
+
"@libp2p/peer-id": "3.0.6-05b52d69c",
|
54
|
+
"@libp2p/peer-record": "6.0.9-05b52d69c",
|
55
|
+
"@libp2p/utils": "4.0.7-05b52d69c",
|
56
|
+
"@multiformats/mafmt": "^12.1.6",
|
57
|
+
"@multiformats/multiaddr": "^12.1.10",
|
58
|
+
"any-signal": "^4.1.1",
|
59
|
+
"delay": "^6.0.0",
|
60
|
+
"it-protobuf-stream": "^1.0.2",
|
61
|
+
"it-stream-types": "^2.0.1",
|
62
|
+
"multiformats": "^12.1.3",
|
63
|
+
"p-defer": "^4.0.0",
|
64
|
+
"p-retry": "^6.1.0",
|
65
|
+
"protons-runtime": "^5.0.0",
|
66
|
+
"uint8arraylist": "^2.4.3",
|
67
|
+
"uint8arrays": "^4.0.6"
|
68
|
+
},
|
69
|
+
"devDependencies": {
|
70
|
+
"@libp2p/interface-compliance-tests": "4.1.5-05b52d69c",
|
71
|
+
"@libp2p/logger": "3.1.0-05b52d69c",
|
72
|
+
"@libp2p/peer-id-factory": "3.0.8-05b52d69c",
|
73
|
+
"aegir": "^41.0.2",
|
74
|
+
"it-drain": "^3.0.3",
|
75
|
+
"it-pair": "^2.0.6",
|
76
|
+
"it-pushable": "^3.2.1",
|
77
|
+
"it-to-buffer": "^4.0.3",
|
78
|
+
"p-wait-for": "^5.0.2",
|
79
|
+
"protons": "^7.3.0",
|
80
|
+
"sinon": "^17.0.0",
|
81
|
+
"sinon-ts": "^2.0.0"
|
82
|
+
}
|
83
|
+
}
|
package/src/constants.ts
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
const second = 1000
|
2
|
+
const minute = 60 * second
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Delay before HOP relay service is advertised on the network
|
6
|
+
*/
|
7
|
+
export const ADVERTISE_BOOT_DELAY = 15 * minute
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Delay Between HOP relay service advertisements on the network
|
11
|
+
*/
|
12
|
+
export const ADVERTISE_TTL = 30 * minute
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Multicodec code
|
16
|
+
*/
|
17
|
+
export const CIRCUIT_PROTO_CODE = 290
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Relay HOP relay service namespace for discovery
|
21
|
+
*/
|
22
|
+
export const RELAY_RENDEZVOUS_NS = '/libp2p/relay'
|
23
|
+
|
24
|
+
/**
|
25
|
+
* The maximum number of relay reservations the relay server will accept
|
26
|
+
*/
|
27
|
+
export const DEFAULT_MAX_RESERVATION_STORE_SIZE = 15
|
28
|
+
|
29
|
+
/**
|
30
|
+
* How often to check for reservation expiry
|
31
|
+
*/
|
32
|
+
export const DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL = 300 * second
|
33
|
+
|
34
|
+
/**
|
35
|
+
* How often to check for reservation expiry
|
36
|
+
*/
|
37
|
+
export const DEFAULT_MAX_RESERVATION_TTL = 2 * 60 * minute
|
38
|
+
|
39
|
+
export const DEFAULT_RESERVATION_CONCURRENCY = 1
|
40
|
+
|
41
|
+
export const RELAY_SOURCE_TAG = 'circuit-relay-source'
|
42
|
+
|
43
|
+
export const RELAY_TAG = 'circuit-relay-relay'
|
44
|
+
|
45
|
+
// circuit v2 connection limits
|
46
|
+
// https://github.com/libp2p/go-libp2p/blob/master/p2p/protocol/circuitv2/relay/resources.go#L61-L66
|
47
|
+
|
48
|
+
// 2 min is the default connection duration
|
49
|
+
export const DEFAULT_DURATION_LIMIT = 2 * minute
|
50
|
+
|
51
|
+
// 128k is the default data limit
|
52
|
+
export const DEFAULT_DATA_LIMIT = BigInt(1 << 17)
|
53
|
+
|
54
|
+
/**
|
55
|
+
* The hop protocol
|
56
|
+
*/
|
57
|
+
export const RELAY_V2_HOP_CODEC = '/libp2p/circuit/relay/0.2.0/hop'
|
58
|
+
|
59
|
+
/**
|
60
|
+
* the stop protocol
|
61
|
+
*/
|
62
|
+
export const RELAY_V2_STOP_CODEC = '/libp2p/circuit/relay/0.2.0/stop'
|
63
|
+
|
64
|
+
/**
|
65
|
+
* Hop messages must be exchanged inside this timeout
|
66
|
+
*/
|
67
|
+
export const DEFAULT_HOP_TIMEOUT = 30 * second
|
68
|
+
|
69
|
+
/**
|
70
|
+
* How long to wait before starting to advertise the relay service
|
71
|
+
*/
|
72
|
+
export const DEFAULT_ADVERT_BOOT_DELAY = 30 * second
|
73
|
+
|
74
|
+
export const MAX_CONNECTIONS = 300
|
75
|
+
|
76
|
+
export const ERR_NO_ROUTERS_AVAILABLE = 'ERR_NO_ROUTERS_AVAILABLE'
|
77
|
+
export const ERR_RELAYED_DIAL = 'ERR_RELAYED_DIAL'
|
78
|
+
export const ERR_HOP_REQUEST_FAILED = 'ERR_HOP_REQUEST_FAILED'
|
79
|
+
export const ERR_TRANSFER_LIMIT_EXCEEDED = 'ERR_TRANSFER_LIMIT_EXCEEDED'
|
package/src/index.ts
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
/**
|
2
|
+
* @packageDocumentation
|
3
|
+
*
|
4
|
+
* The `circuitRelayTransport` allows libp2p to dial and listen on [Circuit Relay](https://docs.libp2p.io/concepts/nat/circuit-relay/)
|
5
|
+
* addresses.
|
6
|
+
*
|
7
|
+
* @example
|
8
|
+
*
|
9
|
+
* ```typescript
|
10
|
+
* import { createLibp2p } from 'libp2p'
|
11
|
+
* import { circuitRelayTransport } from '@libp2p/circuit-relay-v2'
|
12
|
+
*
|
13
|
+
* const node = await createLibp2p({
|
14
|
+
* transports: [
|
15
|
+
* circuitRelayTransport()
|
16
|
+
* ]
|
17
|
+
* })
|
18
|
+
* ```
|
19
|
+
*
|
20
|
+
* The `circuitRelayServer` function allows libp2p to function as a [Circuit Relay](https://docs.libp2p.io/concepts/nat/circuit-relay/)
|
21
|
+
* server. This will not work in browsers.
|
22
|
+
*
|
23
|
+
* @example
|
24
|
+
*
|
25
|
+
* ```typescript
|
26
|
+
* import { createLibp2p } from 'libp2p'
|
27
|
+
* import { circuitRelayServer } from '@libp2p/circuit-relay-v2'
|
28
|
+
*
|
29
|
+
* const node = await createLibp2p({
|
30
|
+
* services: [
|
31
|
+
* circuitRelay: circuitRelayServer()
|
32
|
+
* ]
|
33
|
+
* })
|
34
|
+
* ```
|
35
|
+
*/
|
36
|
+
|
37
|
+
import type { Limit } from './pb/index.js'
|
38
|
+
import type { TypedEventEmitter } from '@libp2p/interface/events'
|
39
|
+
import type { PeerMap } from '@libp2p/peer-collections'
|
40
|
+
import type { Multiaddr } from '@multiformats/multiaddr'
|
41
|
+
|
42
|
+
export interface RelayReservation {
|
43
|
+
expire: Date
|
44
|
+
addr: Multiaddr
|
45
|
+
limit?: Limit
|
46
|
+
}
|
47
|
+
|
48
|
+
export interface CircuitRelayServiceEvents {
|
49
|
+
'relay:reservation': CustomEvent<RelayReservation>
|
50
|
+
'relay:advert:success': CustomEvent<unknown>
|
51
|
+
'relay:advert:error': CustomEvent<Error>
|
52
|
+
}
|
53
|
+
|
54
|
+
export interface CircuitRelayService extends TypedEventEmitter<CircuitRelayServiceEvents> {
|
55
|
+
reservations: PeerMap<RelayReservation>
|
56
|
+
}
|
57
|
+
|
58
|
+
export { circuitRelayServer } from './server/index.js'
|
59
|
+
export { circuitRelayTransport } from './transport/index.js'
|
60
|
+
|
61
|
+
export {
|
62
|
+
RELAY_V2_HOP_CODEC,
|
63
|
+
RELAY_V2_STOP_CODEC
|
64
|
+
} from './constants.js'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
syntax = "proto3";
|
2
|
+
|
3
|
+
message HopMessage {
|
4
|
+
enum Type {
|
5
|
+
RESERVE = 0;
|
6
|
+
CONNECT = 1;
|
7
|
+
STATUS = 2;
|
8
|
+
}
|
9
|
+
|
10
|
+
// the presence of this field is enforced at application level
|
11
|
+
optional Type type = 1;
|
12
|
+
|
13
|
+
optional Peer peer = 2;
|
14
|
+
optional Reservation reservation = 3;
|
15
|
+
optional Limit limit = 4;
|
16
|
+
|
17
|
+
optional Status status = 5;
|
18
|
+
}
|
19
|
+
|
20
|
+
message StopMessage {
|
21
|
+
enum Type {
|
22
|
+
CONNECT = 0;
|
23
|
+
STATUS = 1;
|
24
|
+
}
|
25
|
+
|
26
|
+
// the presence of this field is enforced at application level
|
27
|
+
optional Type type = 1;
|
28
|
+
|
29
|
+
optional Peer peer = 2;
|
30
|
+
optional Limit limit = 3;
|
31
|
+
|
32
|
+
optional Status status = 4;
|
33
|
+
}
|
34
|
+
|
35
|
+
message Peer {
|
36
|
+
bytes id = 1;
|
37
|
+
repeated bytes addrs = 2;
|
38
|
+
}
|
39
|
+
|
40
|
+
message Reservation {
|
41
|
+
uint64 expire = 1; // Unix expiration time (UTC)
|
42
|
+
repeated bytes addrs = 2; // relay addrs for reserving peer
|
43
|
+
optional bytes voucher = 3; // reservation voucher
|
44
|
+
}
|
45
|
+
|
46
|
+
message Limit {
|
47
|
+
optional uint32 duration = 1; // seconds
|
48
|
+
optional uint64 data = 2; // bytes
|
49
|
+
}
|
50
|
+
|
51
|
+
enum Status {
|
52
|
+
UNUSED = 0;
|
53
|
+
OK = 100;
|
54
|
+
RESERVATION_REFUSED = 200;
|
55
|
+
RESOURCE_LIMIT_EXCEEDED = 201;
|
56
|
+
PERMISSION_DENIED = 202;
|
57
|
+
CONNECTION_FAILED = 203;
|
58
|
+
NO_RESERVATION = 204;
|
59
|
+
MALFORMED_MESSAGE = 400;
|
60
|
+
UNEXPECTED_MESSAGE = 401;
|
61
|
+
}
|
62
|
+
|
63
|
+
message ReservationVoucher {
|
64
|
+
bytes relay = 1;
|
65
|
+
bytes peer = 2;
|
66
|
+
uint64 expiration = 3;
|
67
|
+
}
|