@libp2p/fetch 0.0.0-97ab31c0c
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 +68 -0
- package/dist/index.min.js +3 -0
- package/dist/src/constants.d.ts +3 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +4 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/fetch.d.ts +63 -0
- package/dist/src/fetch.d.ts.map +1 -0
- package/dist/src/fetch.js +208 -0
- package/dist/src/fetch.js.map +1 -0
- package/dist/src/index.d.ts +87 -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/proto.d.ts +28 -0
- package/dist/src/pb/proto.d.ts.map +1 -0
- package/dist/src/pb/proto.js +120 -0
- package/dist/src/pb/proto.js.map +1 -0
- package/package.json +66 -0
- package/src/constants.ts +3 -0
- package/src/fetch.ts +236 -0
- package/src/index.ts +98 -0
- package/src/pb/proto.proto +15 -0
- package/src/pb/proto.ts +153 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Codec } from 'protons-runtime';
|
|
2
|
+
import type { Uint8ArrayList } from 'uint8arraylist';
|
|
3
|
+
export interface FetchRequest {
|
|
4
|
+
identifier: string;
|
|
5
|
+
}
|
|
6
|
+
export declare namespace FetchRequest {
|
|
7
|
+
const codec: () => Codec<FetchRequest>;
|
|
8
|
+
const encode: (obj: Partial<FetchRequest>) => Uint8Array;
|
|
9
|
+
const decode: (buf: Uint8Array | Uint8ArrayList) => FetchRequest;
|
|
10
|
+
}
|
|
11
|
+
export interface FetchResponse {
|
|
12
|
+
status: FetchResponse.StatusCode;
|
|
13
|
+
data: Uint8Array;
|
|
14
|
+
}
|
|
15
|
+
export declare namespace FetchResponse {
|
|
16
|
+
enum StatusCode {
|
|
17
|
+
OK = "OK",
|
|
18
|
+
NOT_FOUND = "NOT_FOUND",
|
|
19
|
+
ERROR = "ERROR"
|
|
20
|
+
}
|
|
21
|
+
namespace StatusCode {
|
|
22
|
+
const codec: () => Codec<StatusCode>;
|
|
23
|
+
}
|
|
24
|
+
const codec: () => Codec<FetchResponse>;
|
|
25
|
+
const encode: (obj: Partial<FetchResponse>) => Uint8Array;
|
|
26
|
+
const decode: (buf: Uint8Array | Uint8ArrayList) => FetchResponse;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=proto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proto.d.ts","sourceRoot":"","sources":["../../../src/pb/proto.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,yBAAiB,YAAY,CAAC;IAGrB,MAAM,KAAK,QAAO,MAAM,YAAY,CAwC1C,CAAA;IAEM,MAAM,MAAM,QAAS,QAAQ,YAAY,CAAC,KAAG,UAEnD,CAAA;IAEM,MAAM,MAAM,QAAS,UAAU,GAAG,cAAc,KAAG,YAEzD,CAAA;CACF;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,aAAa,CAAC,UAAU,CAAA;IAChC,IAAI,EAAE,UAAU,CAAA;CACjB;AAED,yBAAiB,aAAa,CAAC;IAC7B,KAAY,UAAU;QACpB,EAAE,OAAO;QACT,SAAS,cAAc;QACvB,KAAK,UAAU;KAChB;IAQD,UAAiB,UAAU,CAAC;QACnB,MAAM,KAAK,QAAO,MAAM,UAAU,CAExC,CAAA;KACF;IAIM,MAAM,KAAK,QAAO,MAAM,aAAa,CAiD3C,CAAA;IAEM,MAAM,MAAM,QAAS,QAAQ,aAAa,CAAC,KAAG,UAEpD,CAAA;IAEM,MAAM,MAAM,QAAS,UAAU,GAAG,cAAc,KAAG,aAEzD,CAAA;CACF"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/* eslint-disable import/export */
|
|
2
|
+
/* eslint-disable complexity */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-namespace */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
|
|
5
|
+
/* eslint-disable @typescript-eslint/no-empty-interface */
|
|
6
|
+
import { encodeMessage, decodeMessage, message, enumeration } from 'protons-runtime';
|
|
7
|
+
export var FetchRequest;
|
|
8
|
+
(function (FetchRequest) {
|
|
9
|
+
let _codec;
|
|
10
|
+
FetchRequest.codec = () => {
|
|
11
|
+
if (_codec == null) {
|
|
12
|
+
_codec = message((obj, w, opts = {}) => {
|
|
13
|
+
if (opts.lengthDelimited !== false) {
|
|
14
|
+
w.fork();
|
|
15
|
+
}
|
|
16
|
+
if ((obj.identifier != null && obj.identifier !== '')) {
|
|
17
|
+
w.uint32(10);
|
|
18
|
+
w.string(obj.identifier);
|
|
19
|
+
}
|
|
20
|
+
if (opts.lengthDelimited !== false) {
|
|
21
|
+
w.ldelim();
|
|
22
|
+
}
|
|
23
|
+
}, (reader, length) => {
|
|
24
|
+
const obj = {
|
|
25
|
+
identifier: ''
|
|
26
|
+
};
|
|
27
|
+
const end = length == null ? reader.len : reader.pos + length;
|
|
28
|
+
while (reader.pos < end) {
|
|
29
|
+
const tag = reader.uint32();
|
|
30
|
+
switch (tag >>> 3) {
|
|
31
|
+
case 1:
|
|
32
|
+
obj.identifier = reader.string();
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
reader.skipType(tag & 7);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return obj;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return _codec;
|
|
43
|
+
};
|
|
44
|
+
FetchRequest.encode = (obj) => {
|
|
45
|
+
return encodeMessage(obj, FetchRequest.codec());
|
|
46
|
+
};
|
|
47
|
+
FetchRequest.decode = (buf) => {
|
|
48
|
+
return decodeMessage(buf, FetchRequest.codec());
|
|
49
|
+
};
|
|
50
|
+
})(FetchRequest || (FetchRequest = {}));
|
|
51
|
+
export var FetchResponse;
|
|
52
|
+
(function (FetchResponse) {
|
|
53
|
+
let StatusCode;
|
|
54
|
+
(function (StatusCode) {
|
|
55
|
+
StatusCode["OK"] = "OK";
|
|
56
|
+
StatusCode["NOT_FOUND"] = "NOT_FOUND";
|
|
57
|
+
StatusCode["ERROR"] = "ERROR";
|
|
58
|
+
})(StatusCode = FetchResponse.StatusCode || (FetchResponse.StatusCode = {}));
|
|
59
|
+
let __StatusCodeValues;
|
|
60
|
+
(function (__StatusCodeValues) {
|
|
61
|
+
__StatusCodeValues[__StatusCodeValues["OK"] = 0] = "OK";
|
|
62
|
+
__StatusCodeValues[__StatusCodeValues["NOT_FOUND"] = 1] = "NOT_FOUND";
|
|
63
|
+
__StatusCodeValues[__StatusCodeValues["ERROR"] = 2] = "ERROR";
|
|
64
|
+
})(__StatusCodeValues || (__StatusCodeValues = {}));
|
|
65
|
+
(function (StatusCode) {
|
|
66
|
+
StatusCode.codec = () => {
|
|
67
|
+
return enumeration(__StatusCodeValues);
|
|
68
|
+
};
|
|
69
|
+
})(StatusCode = FetchResponse.StatusCode || (FetchResponse.StatusCode = {}));
|
|
70
|
+
let _codec;
|
|
71
|
+
FetchResponse.codec = () => {
|
|
72
|
+
if (_codec == null) {
|
|
73
|
+
_codec = message((obj, w, opts = {}) => {
|
|
74
|
+
if (opts.lengthDelimited !== false) {
|
|
75
|
+
w.fork();
|
|
76
|
+
}
|
|
77
|
+
if (obj.status != null && __StatusCodeValues[obj.status] !== 0) {
|
|
78
|
+
w.uint32(8);
|
|
79
|
+
FetchResponse.StatusCode.codec().encode(obj.status, w);
|
|
80
|
+
}
|
|
81
|
+
if ((obj.data != null && obj.data.byteLength > 0)) {
|
|
82
|
+
w.uint32(18);
|
|
83
|
+
w.bytes(obj.data);
|
|
84
|
+
}
|
|
85
|
+
if (opts.lengthDelimited !== false) {
|
|
86
|
+
w.ldelim();
|
|
87
|
+
}
|
|
88
|
+
}, (reader, length) => {
|
|
89
|
+
const obj = {
|
|
90
|
+
status: StatusCode.OK,
|
|
91
|
+
data: new Uint8Array(0)
|
|
92
|
+
};
|
|
93
|
+
const end = length == null ? reader.len : reader.pos + length;
|
|
94
|
+
while (reader.pos < end) {
|
|
95
|
+
const tag = reader.uint32();
|
|
96
|
+
switch (tag >>> 3) {
|
|
97
|
+
case 1:
|
|
98
|
+
obj.status = FetchResponse.StatusCode.codec().decode(reader);
|
|
99
|
+
break;
|
|
100
|
+
case 2:
|
|
101
|
+
obj.data = reader.bytes();
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
reader.skipType(tag & 7);
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return obj;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return _codec;
|
|
112
|
+
};
|
|
113
|
+
FetchResponse.encode = (obj) => {
|
|
114
|
+
return encodeMessage(obj, FetchResponse.codec());
|
|
115
|
+
};
|
|
116
|
+
FetchResponse.decode = (buf) => {
|
|
117
|
+
return decodeMessage(buf, FetchResponse.codec());
|
|
118
|
+
};
|
|
119
|
+
})(FetchResponse || (FetchResponse = {}));
|
|
120
|
+
//# sourceMappingURL=proto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proto.js","sourceRoot":"","sources":["../../../src/pb/proto.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@libp2p/fetch",
|
|
3
|
+
"version": "0.0.0-97ab31c0c",
|
|
4
|
+
"description": "Implementation of the Fetch Protocol",
|
|
5
|
+
"license": "Apache-2.0 OR MIT",
|
|
6
|
+
"homepage": "https://github.com/libp2p/js-libp2p/tree/master/packages/protocol-fetch#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-97ab31c0c",
|
|
51
|
+
"@libp2p/interface-internal": "0.1.9-97ab31c0c",
|
|
52
|
+
"it-protobuf-stream": "^1.0.2",
|
|
53
|
+
"protons-runtime": "^5.0.0",
|
|
54
|
+
"uint8arraylist": "^2.4.3",
|
|
55
|
+
"uint8arrays": "^4.0.6"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@libp2p/logger": "3.1.0-97ab31c0c",
|
|
59
|
+
"@libp2p/peer-id-factory": "3.0.8-97ab31c0c",
|
|
60
|
+
"aegir": "^41.0.2",
|
|
61
|
+
"it-pair": "^2.0.6",
|
|
62
|
+
"protons": "^7.3.0",
|
|
63
|
+
"sinon": "^17.0.0",
|
|
64
|
+
"sinon-ts": "^2.0.0"
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/constants.ts
ADDED
package/src/fetch.ts
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { CodeError, ERR_INVALID_MESSAGE, ERR_INVALID_PARAMETERS, ERR_TIMEOUT } from '@libp2p/interface/errors'
|
|
2
|
+
import { setMaxListeners } from '@libp2p/interface/events'
|
|
3
|
+
import { pbStream } from 'it-protobuf-stream'
|
|
4
|
+
import { fromString as uint8arrayFromString } from 'uint8arrays/from-string'
|
|
5
|
+
import { toString as uint8arrayToString } from 'uint8arrays/to-string'
|
|
6
|
+
import { PROTOCOL_NAME, PROTOCOL_VERSION } from './constants.js'
|
|
7
|
+
import { FetchRequest, FetchResponse } from './pb/proto.js'
|
|
8
|
+
import type { Fetch as FetchInterface, FetchComponents, FetchInit, LookupFunction } from './index.js'
|
|
9
|
+
import type { AbortOptions, Logger } from '@libp2p/interface'
|
|
10
|
+
import type { Stream } from '@libp2p/interface/connection'
|
|
11
|
+
import type { PeerId } from '@libp2p/interface/peer-id'
|
|
12
|
+
import type { Startable } from '@libp2p/interface/startable'
|
|
13
|
+
import type { IncomingStreamData } from '@libp2p/interface-internal/registrar'
|
|
14
|
+
|
|
15
|
+
const DEFAULT_TIMEOUT = 10000
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A simple libp2p protocol for requesting a value corresponding to a key from a peer.
|
|
19
|
+
* Developers can register one or more lookup function for retrieving the value corresponding to
|
|
20
|
+
* a given key. Each lookup function must act on a distinct part of the overall key space, defined
|
|
21
|
+
* by a fixed prefix that all keys that should be routed to that lookup function will start with.
|
|
22
|
+
*/
|
|
23
|
+
export class Fetch implements Startable, FetchInterface {
|
|
24
|
+
public readonly protocol: string
|
|
25
|
+
private readonly components: FetchComponents
|
|
26
|
+
private readonly lookupFunctions: Map<string, LookupFunction>
|
|
27
|
+
private started: boolean
|
|
28
|
+
private readonly init: FetchInit
|
|
29
|
+
private readonly log: Logger
|
|
30
|
+
|
|
31
|
+
constructor (components: FetchComponents, init: FetchInit = {}) {
|
|
32
|
+
this.log = components.logger.forComponent('libp2p:fetch')
|
|
33
|
+
this.started = false
|
|
34
|
+
this.components = components
|
|
35
|
+
this.protocol = `/${init.protocolPrefix ?? 'libp2p'}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}`
|
|
36
|
+
this.lookupFunctions = new Map() // Maps key prefix to value lookup function
|
|
37
|
+
this.handleMessage = this.handleMessage.bind(this)
|
|
38
|
+
this.init = init
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async start (): Promise<void> {
|
|
42
|
+
await this.components.registrar.handle(this.protocol, (data) => {
|
|
43
|
+
void this.handleMessage(data)
|
|
44
|
+
.then(async () => {
|
|
45
|
+
await data.stream.close()
|
|
46
|
+
})
|
|
47
|
+
.catch(err => {
|
|
48
|
+
this.log.error(err)
|
|
49
|
+
})
|
|
50
|
+
}, {
|
|
51
|
+
maxInboundStreams: this.init.maxInboundStreams,
|
|
52
|
+
maxOutboundStreams: this.init.maxOutboundStreams
|
|
53
|
+
})
|
|
54
|
+
this.started = true
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async stop (): Promise<void> {
|
|
58
|
+
await this.components.registrar.unhandle(this.protocol)
|
|
59
|
+
this.started = false
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
isStarted (): boolean {
|
|
63
|
+
return this.started
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Sends a request to fetch the value associated with the given key from the given peer
|
|
68
|
+
*/
|
|
69
|
+
async fetch (peer: PeerId, key: string, options: AbortOptions = {}): Promise<Uint8Array | undefined> {
|
|
70
|
+
this.log('dialing %s to %p', this.protocol, peer)
|
|
71
|
+
|
|
72
|
+
const connection = await this.components.connectionManager.openConnection(peer, options)
|
|
73
|
+
let signal = options.signal
|
|
74
|
+
let stream: Stream | undefined
|
|
75
|
+
let onAbort = (): void => {}
|
|
76
|
+
|
|
77
|
+
// create a timeout if no abort signal passed
|
|
78
|
+
if (signal == null) {
|
|
79
|
+
this.log('using default timeout of %d ms', this.init.timeout)
|
|
80
|
+
signal = AbortSignal.timeout(this.init.timeout ?? DEFAULT_TIMEOUT)
|
|
81
|
+
|
|
82
|
+
setMaxListeners(Infinity, signal)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
stream = await connection.newStream(this.protocol, {
|
|
87
|
+
signal
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
onAbort = () => {
|
|
91
|
+
stream?.abort(new CodeError('fetch timeout', ERR_TIMEOUT))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// make stream abortable
|
|
95
|
+
signal.addEventListener('abort', onAbort, { once: true })
|
|
96
|
+
|
|
97
|
+
this.log('fetch %s', key)
|
|
98
|
+
|
|
99
|
+
const pb = pbStream(stream)
|
|
100
|
+
await pb.write({
|
|
101
|
+
identifier: key
|
|
102
|
+
}, FetchRequest, options)
|
|
103
|
+
|
|
104
|
+
const response = await pb.read(FetchResponse, options)
|
|
105
|
+
await pb.unwrap().close(options)
|
|
106
|
+
|
|
107
|
+
switch (response.status) {
|
|
108
|
+
case (FetchResponse.StatusCode.OK): {
|
|
109
|
+
this.log('received status for %s ok', key)
|
|
110
|
+
return response.data
|
|
111
|
+
}
|
|
112
|
+
case (FetchResponse.StatusCode.NOT_FOUND): {
|
|
113
|
+
this.log('received status for %s not found', key)
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
case (FetchResponse.StatusCode.ERROR): {
|
|
117
|
+
this.log('received status for %s error', key)
|
|
118
|
+
const errmsg = uint8arrayToString(response.data)
|
|
119
|
+
throw new CodeError('Error in fetch protocol response: ' + errmsg, ERR_INVALID_PARAMETERS)
|
|
120
|
+
}
|
|
121
|
+
default: {
|
|
122
|
+
this.log('received status for %s unknown', key)
|
|
123
|
+
throw new CodeError('Unknown response status', ERR_INVALID_MESSAGE)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (err: any) {
|
|
127
|
+
stream?.abort(err)
|
|
128
|
+
throw err
|
|
129
|
+
} finally {
|
|
130
|
+
signal.removeEventListener('abort', onAbort)
|
|
131
|
+
if (stream != null) {
|
|
132
|
+
await stream.close()
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Invoked when a fetch request is received. Reads the request message off the given stream and
|
|
139
|
+
* responds based on looking up the key in the request via the lookup callback that corresponds
|
|
140
|
+
* to the key's prefix.
|
|
141
|
+
*/
|
|
142
|
+
async handleMessage (data: IncomingStreamData): Promise<void> {
|
|
143
|
+
const { stream } = data
|
|
144
|
+
const signal = AbortSignal.timeout(this.init.timeout ?? DEFAULT_TIMEOUT)
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
const pb = pbStream(stream)
|
|
148
|
+
const request = await pb.read(FetchRequest, {
|
|
149
|
+
signal
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
let response: FetchResponse
|
|
153
|
+
const lookup = this._getLookupFunction(request.identifier)
|
|
154
|
+
if (lookup != null) {
|
|
155
|
+
this.log('look up data with identifier %s', request.identifier)
|
|
156
|
+
const data = await lookup(request.identifier)
|
|
157
|
+
if (data != null) {
|
|
158
|
+
this.log('sending status for %s ok', request.identifier)
|
|
159
|
+
response = { status: FetchResponse.StatusCode.OK, data }
|
|
160
|
+
} else {
|
|
161
|
+
this.log('sending status for %s not found', request.identifier)
|
|
162
|
+
response = { status: FetchResponse.StatusCode.NOT_FOUND, data: new Uint8Array(0) }
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
this.log('sending status for %s error', request.identifier)
|
|
166
|
+
const errmsg = uint8arrayFromString(`No lookup function registered for key: ${request.identifier}`)
|
|
167
|
+
response = { status: FetchResponse.StatusCode.ERROR, data: errmsg }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
await pb.write(response, FetchResponse, {
|
|
171
|
+
signal
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
await pb.unwrap().close({
|
|
175
|
+
signal
|
|
176
|
+
})
|
|
177
|
+
} catch (err: any) {
|
|
178
|
+
this.log('error answering fetch request', err)
|
|
179
|
+
stream.abort(err)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Given a key, finds the appropriate function for looking up its corresponding value, based on
|
|
185
|
+
* the key's prefix.
|
|
186
|
+
*/
|
|
187
|
+
_getLookupFunction (key: string): LookupFunction | undefined {
|
|
188
|
+
for (const prefix of this.lookupFunctions.keys()) {
|
|
189
|
+
if (key.startsWith(prefix)) {
|
|
190
|
+
return this.lookupFunctions.get(prefix)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Registers a new lookup callback that can map keys to values, for a given set of keys that
|
|
197
|
+
* share the same prefix
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
*
|
|
201
|
+
* ```js
|
|
202
|
+
* // ...
|
|
203
|
+
* libp2p.fetchService.registerLookupFunction('/prefix', (key) => { ... })
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
registerLookupFunction (prefix: string, lookup: LookupFunction): void {
|
|
207
|
+
if (this.lookupFunctions.has(prefix)) {
|
|
208
|
+
throw new CodeError(`Fetch protocol handler for key prefix '${prefix}' already registered`, 'ERR_KEY_ALREADY_EXISTS')
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this.lookupFunctions.set(prefix, lookup)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Registers a new lookup callback that can map keys to values, for a given set of keys that
|
|
216
|
+
* share the same prefix.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
*
|
|
220
|
+
* ```js
|
|
221
|
+
* // ...
|
|
222
|
+
* libp2p.fetchService.unregisterLookupFunction('/prefix')
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
unregisterLookupFunction (prefix: string, lookup?: LookupFunction): void {
|
|
226
|
+
if (lookup != null) {
|
|
227
|
+
const existingLookup = this.lookupFunctions.get(prefix)
|
|
228
|
+
|
|
229
|
+
if (existingLookup !== lookup) {
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
this.lookupFunctions.delete(prefix)
|
|
235
|
+
}
|
|
236
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
*
|
|
4
|
+
* An implementation of the Fetch protocol as described here: https://github.com/libp2p/specs/tree/master/fetch
|
|
5
|
+
*
|
|
6
|
+
* The fetch protocol is a simple protocol for requesting a value corresponding to a key from a peer.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
*
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { createLibp2p } from 'libp2p'
|
|
12
|
+
* import { fetch } from '@libp2p/fetch'
|
|
13
|
+
*
|
|
14
|
+
* const libp2p = await createLibp2p({
|
|
15
|
+
* services: {
|
|
16
|
+
* fetch: fetch()
|
|
17
|
+
* }
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* // Given a key (as a string) returns a value (as a Uint8Array), or null if the key isn't found.
|
|
21
|
+
* // All keys must be prefixed my the same prefix, which will be used to find the appropriate key
|
|
22
|
+
* // lookup function.
|
|
23
|
+
* async function my_subsystem_key_lookup(key) {
|
|
24
|
+
* // app specific callback to lookup key-value pairs.
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* // Enable this peer to respond to fetch requests for keys that begin with '/my_subsystem_key_prefix/'
|
|
28
|
+
* libp2p.fetch.registerLookupFunction('/my_subsystem_key_prefix/', my_subsystem_key_lookup)
|
|
29
|
+
*
|
|
30
|
+
* const key = '/my_subsystem_key_prefix/{...}'
|
|
31
|
+
* const peerDst = PeerId.parse('Qmfoo...') // or Multiaddr instance
|
|
32
|
+
* const value = await libp2p.fetch(peerDst, key)
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { Fetch as FetchClass } from './fetch.js'
|
|
37
|
+
import type { AbortOptions, ComponentLogger } from '@libp2p/interface'
|
|
38
|
+
import type { PeerId } from '@libp2p/interface/peer-id'
|
|
39
|
+
import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager'
|
|
40
|
+
import type { Registrar } from '@libp2p/interface-internal/registrar'
|
|
41
|
+
|
|
42
|
+
export interface FetchInit {
|
|
43
|
+
protocolPrefix?: string
|
|
44
|
+
maxInboundStreams?: number
|
|
45
|
+
maxOutboundStreams?: number
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* How long we should wait for a remote peer to send any data
|
|
49
|
+
*/
|
|
50
|
+
timeout?: number
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface LookupFunction {
|
|
54
|
+
(key: string): Promise<Uint8Array | undefined>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface FetchComponents {
|
|
58
|
+
registrar: Registrar
|
|
59
|
+
connectionManager: ConnectionManager
|
|
60
|
+
logger: ComponentLogger
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface Fetch {
|
|
64
|
+
/**
|
|
65
|
+
* Sends a request to fetch the value associated with the given key from the given peer
|
|
66
|
+
*/
|
|
67
|
+
fetch(peer: PeerId, key: string, options?: AbortOptions): Promise<Uint8Array | undefined>
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Registers a new lookup callback that can map keys to values, for a given set of keys that
|
|
71
|
+
* share the same prefix
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
*
|
|
75
|
+
* ```js
|
|
76
|
+
* // ...
|
|
77
|
+
* libp2p.fetchService.registerLookupFunction('/prefix', (key) => { ... })
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
registerLookupFunction(prefix: string, lookup: LookupFunction): void
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Registers a new lookup callback that can map keys to values, for a given set of keys that
|
|
84
|
+
* share the same prefix.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
*
|
|
88
|
+
* ```js
|
|
89
|
+
* // ...
|
|
90
|
+
* libp2p.fetchService.unregisterLookupFunction('/prefix')
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
unregisterLookupFunction(prefix: string, lookup?: LookupFunction): void
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function fetch (init: FetchInit = {}): (components: FetchComponents) => Fetch {
|
|
97
|
+
return (components) => new FetchClass(components, init)
|
|
98
|
+
}
|