@libp2p/perf 2.0.1-c960eb659 → 2.0.1-d8f5bc211
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 +19 -5
- package/dist/index.min.js +1 -1
- package/dist/src/index.d.ts +11 -10
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -7
- package/dist/src/index.js.map +1 -1
- package/dist/src/perf-service.d.ts +4 -3
- package/dist/src/perf-service.d.ts.map +1 -1
- package/dist/src/perf-service.js +25 -21
- package/dist/src/perf-service.js.map +1 -1
- package/package.json +7 -7
- package/src/index.ts +13 -12
- package/src/perf-service.ts +38 -27
package/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
[](http://libp2p.io/)
|
2
2
|
[](https://discuss.libp2p.io)
|
3
3
|
[](https://codecov.io/gh/libp2p/js-libp2p)
|
4
|
-
[](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain)
|
5
5
|
|
6
6
|
> Implementation of Perf Protocol
|
7
7
|
|
@@ -17,14 +17,14 @@ import { yamux } from '@chainsafe/libp2p-yamux'
|
|
17
17
|
import { mplex } from '@libp2p/mplex'
|
18
18
|
import { tcp } from '@libp2p/tcp'
|
19
19
|
import { createLibp2p, type Libp2p } from 'libp2p'
|
20
|
-
import { plaintext } from 'libp2p/
|
21
|
-
import {
|
20
|
+
import { plaintext } from '@libp2p/plaintext'
|
21
|
+
import { perf, type Perf } from '@libp2p/perf'
|
22
22
|
|
23
23
|
const ONE_MEG = 1024 * 1024
|
24
24
|
const UPLOAD_BYTES = ONE_MEG * 1024
|
25
25
|
const DOWNLOAD_BYTES = ONE_MEG * 1024
|
26
26
|
|
27
|
-
async function createNode (): Promise<Libp2p<{ perf:
|
27
|
+
async function createNode (): Promise<Libp2p<{ perf: Perf }>> {
|
28
28
|
return createLibp2p({
|
29
29
|
addresses: {
|
30
30
|
listen: [
|
@@ -41,7 +41,7 @@ async function createNode (): Promise<Libp2p<{ perf: PerfService }>> {
|
|
41
41
|
yamux(), mplex()
|
42
42
|
],
|
43
43
|
services: {
|
44
|
-
perf:
|
44
|
+
perf: perf()
|
45
45
|
}
|
46
46
|
})
|
47
47
|
}
|
@@ -57,6 +57,20 @@ await libp2p1.stop()
|
|
57
57
|
await libp2p2.stop()
|
58
58
|
```
|
59
59
|
|
60
|
+
# Install
|
61
|
+
|
62
|
+
```console
|
63
|
+
$ npm i @libp2p/perf
|
64
|
+
```
|
65
|
+
|
66
|
+
## Browser `<script>` tag
|
67
|
+
|
68
|
+
Loading this module through a script tag will make it's exports available as `Libp2pPerf` in the global namespace.
|
69
|
+
|
70
|
+
```html
|
71
|
+
<script src="https://unpkg.com/@libp2p/perf/dist/index.min.js"></script>
|
72
|
+
```
|
73
|
+
|
60
74
|
# API Docs
|
61
75
|
|
62
76
|
- <https://libp2p.github.io/js-libp2p/modules/_libp2p_perf.html>
|
package/dist/index.min.js
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
(function (root, factory) {(typeof module === 'object' && module.exports) ? module.exports = factory() : root.Libp2PPerf = factory()}(typeof self !== 'undefined' ? self : this, function () {
|
2
|
-
"use strict";var Libp2PPerf=(()=>{var le=Object.create;var B=Object.defineProperty;var fe=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var he=Object.getPrototypeOf,pe=Object.prototype.hasOwnProperty;var $=(r,e)=>()=>(e||r((e={exports:{}}).exports,e),e.exports),be=(r,e)=>{for(var t in e)B(r,t,{get:e[t],enumerable:!0})},K=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of de(e))!pe.call(r,o)&&o!==t&&B(r,o,{get:()=>e[o],enumerable:!(n=fe(e,o))||n.enumerable});return r};var me=(r,e,t)=>(t=r!=null?le(he(r)):{},K(e||!r||!r.__esModule?B(t,"default",{value:r,enumerable:!0}):t,r)),we=r=>K(B({},"__esModule",{value:!0}),r);var W=$((qe,G)=>{var k=1e3,I=k*60,M=I*60,N=M*24,ge=N*7,Ce=N*365.25;G.exports=function(r,e){e=e||{};var t=typeof r;if(t==="string"&&r.length>0)return ye(r);if(t==="number"&&isFinite(r))return e.long?ve(r):xe(r);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(r))};function ye(r){if(r=String(r),!(r.length>100)){var e=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(r);if(e){var t=parseFloat(e[1]),n=(e[2]||"ms").toLowerCase();switch(n){case"years":case"year":case"yrs":case"yr":case"y":return t*Ce;case"weeks":case"week":case"w":return t*ge;case"days":case"day":case"d":return t*N;case"hours":case"hour":case"hrs":case"hr":case"h":return t*M;case"minutes":case"minute":case"mins":case"min":case"m":return t*I;case"seconds":case"second":case"secs":case"sec":case"s":return t*k;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return t;default:return}}}}function xe(r){var e=Math.abs(r);return e>=N?Math.round(r/N)+"d":e>=M?Math.round(r/M)+"h":e>=I?Math.round(r/I)+"m":e>=k?Math.round(r/k)+"s":r+"ms"}function ve(r){var e=Math.abs(r);return e>=N?L(r,e,N,"day"):e>=M?L(r,e,M,"hour"):e>=I?L(r,e,I,"minute"):e>=k?L(r,e,k,"second"):r+" ms"}function L(r,e,t,n){var o=e>=t*1.5;return Math.round(r/t)+" "+n+(o?"s":"")}});var Y=$((Je,Q)=>{function Fe(r){t.debug=t,t.default=t,t.coerce=b,t.disable=d,t.enable=o,t.enabled=h,t.humanize=W(),t.destroy=y,Object.keys(r).forEach(s=>{t[s]=r[s]}),t.names=[],t.skips=[],t.formatters={};function e(s){let a=0;for(let f=0;f<s.length;f++)a=(a<<5)-a+s.charCodeAt(f),a|=0;return t.colors[Math.abs(a)%t.colors.length]}t.selectColor=e;function t(s){let a,f=null,O,u;function l(...i){if(!l.enabled)return;let c=l,m=Number(new Date),w=m-(a||m);c.diff=w,c.prev=a,c.curr=m,a=m,i[0]=t.coerce(i[0]),typeof i[0]!="string"&&i.unshift("%O");let g=0;i[0]=i[0].replace(/%([a-zA-Z%])/g,(A,v)=>{if(A==="%%")return"%";g++;let E=t.formatters[v];if(typeof E=="function"){let U=i[g];A=E.call(c,U),i.splice(g,1),g--}return A}),t.formatArgs.call(c,i),(c.log||t.log).apply(c,i)}return l.namespace=s,l.useColors=t.useColors(),l.color=t.selectColor(s),l.extend=n,l.destroy=t.destroy,Object.defineProperty(l,"enabled",{enumerable:!0,configurable:!1,get:()=>f!==null?f:(O!==t.namespaces&&(O=t.namespaces,u=t.enabled(s)),u),set:i=>{f=i}}),typeof t.init=="function"&&t.init(l),l}function n(s,a){let f=t(this.namespace+(typeof a>"u"?":":a)+s);return f.log=this.log,f}function o(s){t.save(s),t.namespaces=s,t.names=[],t.skips=[];let a,f=(typeof s=="string"?s:"").split(/[\s,]+/),O=f.length;for(a=0;a<O;a++)f[a]&&(s=f[a].replace(/\*/g,".*?"),s[0]==="-"?t.skips.push(new RegExp("^"+s.slice(1)+"$")):t.names.push(new RegExp("^"+s+"$")))}function d(){let s=[...t.names.map(p),...t.skips.map(p).map(a=>"-"+a)].join(",");return t.enable(""),s}function h(s){if(s[s.length-1]==="*")return!0;let a,f;for(a=0,f=t.skips.length;a<f;a++)if(t.skips[a].test(s))return!1;for(a=0,f=t.names.length;a<f;a++)if(t.names[a].test(s))return!0;return!1}function p(s){return s.toString().substring(2,s.toString().length-2).replace(/\.\*\?$/,"*")}function b(s){return s instanceof Error?s.stack||s.message:s}function y(){console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.")}return t.enable(t.load()),t}Q.exports=Fe});var H=$((F,R)=>{F.formatArgs=Ae;F.save=Ee;F.load=Oe;F.useColors=Se;F.storage=Ne();F.destroy=(()=>{let r=!1;return()=>{r||(r=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})();F.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function Se(){return typeof window<"u"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs)?!0:typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)?!1:typeof document<"u"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window<"u"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||typeof navigator<"u"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function Ae(r){if(r[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+r[0]+(this.useColors?"%c ":" ")+"+"+R.exports.humanize(this.diff),!this.useColors)return;let e="color: "+this.color;r.splice(1,0,e,"color: inherit");let t=0,n=0;r[0].replace(/%[a-zA-Z%]/g,o=>{o!=="%%"&&(t++,o==="%c"&&(n=t))}),r.splice(n,0,e)}F.log=console.debug||console.log||(()=>{});function Ee(r){try{r?F.storage.setItem("debug",r):F.storage.removeItem("debug")}catch{}}function Oe(){let r;try{r=F.storage.getItem("debug")}catch{}return!r&&typeof process<"u"&&"env"in process&&(r=process.env.DEBUG),r}function Ne(){try{return localStorage}catch{}}R.exports=Y()(F);var{formatters:Ue}=R.exports;Ue.j=function(r){try{return JSON.stringify(r)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}});var je={};be(je,{perfService:()=>$e});var S=me(H(),1);function ke(r,e){if(r.length>=255)throw new TypeError("Alphabet too long");for(var t=new Uint8Array(256),n=0;n<t.length;n++)t[n]=255;for(var o=0;o<r.length;o++){var d=r.charAt(o),h=d.charCodeAt(0);if(t[h]!==255)throw new TypeError(d+" is ambiguous");t[h]=o}var p=r.length,b=r.charAt(0),y=Math.log(p)/Math.log(256),s=Math.log(256)/Math.log(p);function a(u){if(u instanceof Uint8Array||(ArrayBuffer.isView(u)?u=new Uint8Array(u.buffer,u.byteOffset,u.byteLength):Array.isArray(u)&&(u=Uint8Array.from(u))),!(u instanceof Uint8Array))throw new TypeError("Expected Uint8Array");if(u.length===0)return"";for(var l=0,i=0,c=0,m=u.length;c!==m&&u[c]===0;)c++,l++;for(var w=(m-c)*s+1>>>0,g=new Uint8Array(w);c!==m;){for(var x=u[c],A=0,v=w-1;(x!==0||A<i)&&v!==-1;v--,A++)x+=256*g[v]>>>0,g[v]=x%p>>>0,x=x/p>>>0;if(x!==0)throw new Error("Non-zero carry");i=A,c++}for(var E=w-i;E!==w&&g[E]===0;)E++;for(var U=b.repeat(l);E<w;++E)U+=r.charAt(g[E]);return U}function f(u){if(typeof u!="string")throw new TypeError("Expected String");if(u.length===0)return new Uint8Array;var l=0;if(u[l]!==" "){for(var i=0,c=0;u[l]===b;)i++,l++;for(var m=(u.length-l)*y+1>>>0,w=new Uint8Array(m);u[l];){var g=t[u.charCodeAt(l)];if(g===255)return;for(var x=0,A=m-1;(g!==0||x<c)&&A!==-1;A--,x++)g+=p*w[A]>>>0,w[A]=g%256>>>0,g=g/256>>>0;if(g!==0)throw new Error("Non-zero carry");c=x,l++}if(u[l]!==" "){for(var v=m-c;v!==m&&w[v]===0;)v++;for(var E=new Uint8Array(i+(m-v)),U=i;v!==m;)E[U++]=w[v++];return E}}}function O(u){var l=f(u);if(l)return l;throw new Error(`Non-${e} character`)}return{encode:a,decodeUnsafe:f,decode:O}}var Ie=ke,Me=Ie,ee=Me;var Ze=new Uint8Array(0);var te=r=>{if(r instanceof Uint8Array&&r.constructor.name==="Uint8Array")return r;if(r instanceof ArrayBuffer)return new Uint8Array(r);if(ArrayBuffer.isView(r))return new Uint8Array(r.buffer,r.byteOffset,r.byteLength);throw new Error("Unknown type, must be binary type")};var j=class{constructor(e,t,n){this.name=e,this.prefix=t,this.baseEncode=n}encode(e){if(e instanceof Uint8Array)return`${this.prefix}${this.baseEncode(e)}`;throw Error("Unknown type, must be binary type")}},V=class{constructor(e,t,n){if(this.name=e,this.prefix=t,t.codePointAt(0)===void 0)throw new Error("Invalid prefix character");this.prefixCodePoint=t.codePointAt(0),this.baseDecode=n}decode(e){if(typeof e=="string"){if(e.codePointAt(0)!==this.prefixCodePoint)throw Error(`Unable to decode multibase string ${JSON.stringify(e)}, ${this.name} decoder only supports inputs prefixed with ${this.prefix}`);return this.baseDecode(e.slice(this.prefix.length))}else throw Error("Can only multibase decode strings")}or(e){return re(this,e)}},q=class{constructor(e){this.decoders=e}or(e){return re(this,e)}decode(e){let t=e[0],n=this.decoders[t];if(n)return n.decode(e);throw RangeError(`Unable to decode multibase string ${JSON.stringify(e)}, only inputs prefixed with ${Object.keys(this.decoders)} are supported`)}},re=(r,e)=>new q({...r.decoders||{[r.prefix]:r},...e.decoders||{[e.prefix]:e}}),J=class{constructor(e,t,n,o){this.name=e,this.prefix=t,this.baseEncode=n,this.baseDecode=o,this.encoder=new j(e,t,n),this.decoder=new V(e,t,o)}encode(e){return this.encoder.encode(e)}decode(e){return this.decoder.decode(e)}},ne=({name:r,prefix:e,encode:t,decode:n})=>new J(r,e,t,n),X=({prefix:r,name:e,alphabet:t})=>{let{encode:n,decode:o}=ee(t,e);return ne({prefix:r,name:e,encode:n,decode:d=>te(o(d))})},Te=(r,e,t,n)=>{let o={};for(let s=0;s<e.length;++s)o[e[s]]=s;let d=r.length;for(;r[d-1]==="=";)--d;let h=new Uint8Array(d*t/8|0),p=0,b=0,y=0;for(let s=0;s<d;++s){let a=o[r[s]];if(a===void 0)throw new SyntaxError(`Non-${n} character`);b=b<<t|a,p+=t,p>=8&&(p-=8,h[y++]=255&b>>p)}if(p>=t||255&b<<8-p)throw new SyntaxError("Unexpected end of data");return h},ze=(r,e,t)=>{let n=e[e.length-1]==="=",o=(1<<t)-1,d="",h=0,p=0;for(let b=0;b<r.length;++b)for(p=p<<8|r[b],h+=8;h>t;)h-=t,d+=e[o&p>>h];if(h&&(d+=e[o&p<<t-h]),n)for(;d.length*t&7;)d+="=";return d},C=({name:r,prefix:e,bitsPerChar:t,alphabet:n})=>ne({prefix:e,name:r,encode(o){return ze(o,n,t)},decode(o){return Te(o,n,t,r)}});var oe=C({prefix:"b",name:"base32",alphabet:"abcdefghijklmnopqrstuvwxyz234567",bitsPerChar:5}),He=C({prefix:"B",name:"base32upper",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",bitsPerChar:5}),et=C({prefix:"c",name:"base32pad",alphabet:"abcdefghijklmnopqrstuvwxyz234567=",bitsPerChar:5}),tt=C({prefix:"C",name:"base32padupper",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",bitsPerChar:5}),rt=C({prefix:"v",name:"base32hex",alphabet:"0123456789abcdefghijklmnopqrstuv",bitsPerChar:5}),nt=C({prefix:"V",name:"base32hexupper",alphabet:"0123456789ABCDEFGHIJKLMNOPQRSTUV",bitsPerChar:5}),ot=C({prefix:"t",name:"base32hexpad",alphabet:"0123456789abcdefghijklmnopqrstuv=",bitsPerChar:5}),st=C({prefix:"T",name:"base32hexpadupper",alphabet:"0123456789ABCDEFGHIJKLMNOPQRSTUV=",bitsPerChar:5}),it=C({prefix:"h",name:"base32z",alphabet:"ybndrfg8ejkmcpqxot1uwisza345h769",bitsPerChar:5});var se=X({name:"base58btc",prefix:"z",alphabet:"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"}),ct=X({name:"base58flickr",prefix:"Z",alphabet:"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"});var ie=C({prefix:"m",name:"base64",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",bitsPerChar:6}),dt=C({prefix:"M",name:"base64pad",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",bitsPerChar:6}),ht=C({prefix:"u",name:"base64url",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",bitsPerChar:6}),pt=C({prefix:"U",name:"base64urlpad",alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=",bitsPerChar:6});S.default.formatters.b=r=>r==null?"undefined":se.baseEncode(r);S.default.formatters.t=r=>r==null?"undefined":oe.baseEncode(r);S.default.formatters.m=r=>r==null?"undefined":ie.baseEncode(r);S.default.formatters.p=r=>r==null?"undefined":r.toString();S.default.formatters.c=r=>r==null?"undefined":r.toString();S.default.formatters.k=r=>r==null?"undefined":r.toString();S.default.formatters.a=r=>r==null?"undefined":r.toString();function Be(r){let e=()=>{};return e.enabled=!1,e.color="",e.diff=0,e.log=()=>{},e.namespace=r,e.destroy=()=>!0,e.extend=()=>e,e}function ae(r){let e=Be(`${r}:trace`);return S.default.enabled(`${r}:trace`)&&S.default.names.map(t=>t.toString()).find(t=>t.includes(":trace"))!=null&&(e=(0,S.default)(`${r}:trace`)),Object.assign((0,S.default)(r),{error:(0,S.default)(`${r}:error`),trace:e})}function _(){let r={};return r.promise=new Promise((e,t)=>{r.resolve=e,r.reject=t}),r}var D=class{buffer;mask;top;btm;next;constructor(e){if(!(e>0)||e-1&e)throw new Error("Max size for a FixedFIFO should be a power of two");this.buffer=new Array(e),this.mask=e-1,this.top=0,this.btm=0,this.next=null}push(e){return this.buffer[this.top]!==void 0?!1:(this.buffer[this.top]=e,this.top=this.top+1&this.mask,!0)}shift(){let e=this.buffer[this.btm];if(e!==void 0)return this.buffer[this.btm]=void 0,this.btm=this.btm+1&this.mask,e}isEmpty(){return this.buffer[this.btm]===void 0}},T=class{size;hwm;head;tail;constructor(e={}){this.hwm=e.splitLimit??16,this.head=new D(this.hwm),this.tail=this.head,this.size=0}calculateSize(e){return e?.byteLength!=null?e.byteLength:1}push(e){if(e?.value!=null&&(this.size+=this.calculateSize(e.value)),!this.head.push(e)){let t=this.head;this.head=t.next=new D(2*this.head.buffer.length),this.head.push(e)}}shift(){let e=this.tail.shift();if(e===void 0&&this.tail.next!=null){let t=this.tail.next;this.tail.next=null,this.tail=t,e=this.tail.shift()}return e?.value!=null&&(this.size-=this.calculateSize(e.value)),e}isEmpty(){return this.head.isEmpty()}};var Z=class extends Error{type;code;constructor(e,t){super(e??"The operation was aborted"),this.type="aborted",this.code=t??"ABORT_ERR"}};function ue(r={}){return Le(t=>{let n=t.shift();if(n==null)return{done:!0};if(n.error!=null)throw n.error;return{done:n.done===!0,value:n.value}},r)}function Le(r,e){e=e??{};let t=e.onEnd,n=new T,o,d,h,p=_(),b=async()=>{try{return n.isEmpty()?h?{done:!0}:await new Promise((i,c)=>{d=m=>{d=null,n.push(m);try{i(r(n))}catch(w){c(w)}return o}}):r(n)}finally{n.isEmpty()&&queueMicrotask(()=>{p.resolve(),p=_()})}},y=i=>d!=null?d(i):(n.push(i),o),s=i=>(n=new T,d!=null?d({error:i}):(n.push({error:i}),o)),a=i=>{if(h)return o;if(e?.objectMode!==!0&&i?.byteLength==null)throw new Error("objectMode was not true but tried to push non-Uint8Array value");return y({done:!1,value:i})},f=i=>h?o:(h=!0,i!=null?s(i):y({done:!0})),O=()=>(n=new T,f(),{done:!0}),u=i=>(f(i),{done:!0});if(o={[Symbol.asyncIterator](){return this},next:b,return:O,throw:u,push:a,end:f,get readableLength(){return n.size},onEmpty:async i=>{let c=i?.signal;if(c?.throwIfAborted(),n.isEmpty())return;let m,w;c!=null&&(m=new Promise((g,x)=>{w=()=>{x(new Z)},c.addEventListener("abort",w)}));try{await Promise.race([p.promise,m])}finally{w!=null&&c!=null&&c?.removeEventListener("abort",w)}}},t==null)return o;let l=o;return o={[Symbol.asyncIterator](){return this},next(){return l.next()},throw(i){return l.throw(i),t!=null&&(t(i),t=void 0),{done:!0}},return(){return l.return(),t!=null&&(t(),t=void 0),{done:!0}},push:a,end(i){return l.end(i),t!=null&&(t(i),t=void 0),o},get readableLength(){return l.readableLength}},o}var ce="/perf/1.0.0";var z=ae("libp2p:perf"),P=class{protocol;components;started;databuf;writeBlockSize;maxInboundStreams;maxOutboundStreams;runOnTransientConnection;constructor(e,t={}){this.components=e,this.started=!1,this.protocol=t.protocolName??ce,this.writeBlockSize=t.writeBlockSize??65536,this.databuf=new ArrayBuffer(this.writeBlockSize),this.maxInboundStreams=t.maxInboundStreams??1,this.maxOutboundStreams=t.maxOutboundStreams??1,this.runOnTransientConnection=t.runOnTransientConnection??!1}async start(){await this.components.registrar.handle(this.protocol,e=>{this.handleMessage(e).catch(t=>{z.error("error handling perf protocol message",t)})},{maxInboundStreams:this.maxInboundStreams,maxOutboundStreams:this.maxOutboundStreams,runOnTransientConnection:this.runOnTransientConnection}),this.started=!0}async stop(){await this.components.registrar.unhandle(this.protocol),this.started=!1}isStarted(){return this.started}async handleMessage(e){let{stream:t}=e;try{let n=this.writeBlockSize,o;for await(let h of t.source)o==null&&(o=Number(h.getBigUint64(0,!1)));if(o==null)throw new Error("bytesToSendBack was not set");let d=new Uint8Array(this.databuf);await t.sink(async function*(){for(;o>0;){let h=n;h>o&&(h=o),o=o-h,yield d.subarray(0,h)}}())}catch(n){t.abort(n)}}async*measurePerformance(e,t,n,o={}){z("opening stream on protocol %s to %a",this.protocol,e);let d=new Uint8Array(this.databuf),h=this.writeBlockSize,p=Date.now(),b=await this.components.connectionManager.openConnection(e,{...o,force:o.reuseExistingConnection!==!0}),y=await b.newStream(this.protocol,o),s=0,a=Date.now(),f=0;new DataView(this.databuf).setBigUint64(0,BigInt(n),!1),z("sending %i bytes to %p",t,b.remotePeer);try{let u=ue({objectMode:!0});y.sink(async function*(){for(yield d.subarray(0,8);t>0;){o.signal?.throwIfAborted();let c=h;c>t&&(c=t),t=t-c,yield d.subarray(0,c),Date.now()-a>1e3&&(u.push({type:"intermediary",timeSeconds:(Date.now()-a)/1e3,uploadBytes:s,downloadBytes:0}),a=Date.now(),s=0),s+=c,f+=c}u.end()}()).catch(c=>{u.end(c)}),yield*u;let l=0;a=Date.now();let i=0;for await(let c of y.source)o.signal?.throwIfAborted(),Date.now()-a>1e3&&(yield{type:"intermediary",timeSeconds:(Date.now()-a)/1e3,uploadBytes:0,downloadBytes:l},a=Date.now(),l=0),l+=c.byteLength,i+=c.byteLength;if(i!==n)throw new Error(`Expected to receive ${n} bytes, but received ${i}`);yield{type:"final",timeSeconds:(Date.now()-p)/1e3,uploadBytes:f,downloadBytes:i},z("performed %s to %p",this.protocol,b.remotePeer),await y.close()}catch(u){throw z("error sending %d/%d bytes to %p: %s",f,t,b.remotePeer,u),y.abort(u),u}}};function $e(r={}){return e=>new P(e,r)}return we(je);})();
|
2
|
+
"use strict";var Libp2PPerf=(()=>{var O=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var I=Object.prototype.hasOwnProperty;var k=(s,t)=>{for(var e in t)O(s,e,{get:t[e],enumerable:!0})},M=(s,t,e,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of v(t))!I.call(s,n)&&n!==e&&O(s,n,{get:()=>t[n],enumerable:!(o=A(t,n))||o.enumerable});return s};var R=s=>M(O({},"__esModule",{value:!0}),s);var j={};k(j,{perf:()=>X});function S(){let s={};return s.promise=new Promise((t,e)=>{s.resolve=t,s.reject=e}),s}var g=class{buffer;mask;top;btm;next;constructor(t){if(!(t>0)||t-1&t)throw new Error("Max size for a FixedFIFO should be a power of two");this.buffer=new Array(t),this.mask=t-1,this.top=0,this.btm=0,this.next=null}push(t){return this.buffer[this.top]!==void 0?!1:(this.buffer[this.top]=t,this.top=this.top+1&this.mask,!0)}shift(){let t=this.buffer[this.btm];if(t!==void 0)return this.buffer[this.btm]=void 0,this.btm=this.btm+1&this.mask,t}isEmpty(){return this.buffer[this.btm]===void 0}},b=class{size;hwm;head;tail;constructor(t={}){this.hwm=t.splitLimit??16,this.head=new g(this.hwm),this.tail=this.head,this.size=0}calculateSize(t){return t?.byteLength!=null?t.byteLength:1}push(t){if(t?.value!=null&&(this.size+=this.calculateSize(t.value)),!this.head.push(t)){let e=this.head;this.head=e.next=new g(2*this.head.buffer.length),this.head.push(t)}}shift(){let t=this.tail.shift();if(t===void 0&&this.tail.next!=null){let e=this.tail.next;this.tail.next=null,this.tail=e,t=this.tail.shift()}return t?.value!=null&&(this.size-=this.calculateSize(t.value)),t}isEmpty(){return this.head.isEmpty()}};var N=class extends Error{type;code;constructor(t,e){super(t??"The operation was aborted"),this.type="aborted",this.code=e??"ABORT_ERR"}};function B(s={}){return z(e=>{let o=e.shift();if(o==null)return{done:!0};if(o.error!=null)throw o.error;return{done:o.done===!0,value:o.value}},s)}function z(s,t){t=t??{};let e=t.onEnd,o=new b,n,c,u,y=S(),l=async()=>{try{return o.isEmpty()?u?{done:!0}:await new Promise((r,h)=>{c=w=>{c=null,o.push(w);try{r(s(o))}catch(i){h(i)}return n}}):s(o)}finally{o.isEmpty()&&queueMicrotask(()=>{y.resolve(),y=S()})}},d=r=>c!=null?c(r):(o.push(r),n),p=r=>(o=new b,c!=null?c({error:r}):(o.push({error:r}),n)),m=r=>{if(u)return n;if(t?.objectMode!==!0&&r?.byteLength==null)throw new Error("objectMode was not true but tried to push non-Uint8Array value");return d({done:!1,value:r})},f=r=>u?n:(u=!0,r!=null?p(r):d({done:!0})),E=()=>(o=new b,f(),{done:!0}),T=r=>(f(r),{done:!0});if(n={[Symbol.asyncIterator](){return this},next:l,return:E,throw:T,push:m,end:f,get readableLength(){return o.size},onEmpty:async r=>{let h=r?.signal;if(h?.throwIfAborted(),o.isEmpty())return;let w,i;h!=null&&(w=new Promise((K,D)=>{i=()=>{D(new N)},h.addEventListener("abort",i)}));try{await Promise.race([y.promise,w])}finally{i!=null&&h!=null&&h?.removeEventListener("abort",i)}}},e==null)return n;let a=n;return n={[Symbol.asyncIterator](){return this},next(){return a.next()},throw(r){return a.throw(r),e!=null&&(e(r),e=void 0),{done:!0}},return(){return a.return(),e!=null&&(e(),e=void 0),{done:!0}},push:m,end(r){return a.end(r),e!=null&&(e(r),e=void 0),n},get readableLength(){return a.readableLength},onEmpty:r=>a.onEmpty(r)},n}var _="/perf/1.0.0";var x=class{log;protocol;components;started;databuf;writeBlockSize;maxInboundStreams;maxOutboundStreams;runOnTransientConnection;constructor(t,e={}){this.components=t,this.log=t.logger.forComponent("libp2p:perf"),this.started=!1,this.protocol=e.protocolName??_,this.writeBlockSize=e.writeBlockSize??65536,this.databuf=new ArrayBuffer(this.writeBlockSize),this.maxInboundStreams=e.maxInboundStreams??1,this.maxOutboundStreams=e.maxOutboundStreams??1,this.runOnTransientConnection=e.runOnTransientConnection??!1}async start(){await this.components.registrar.handle(this.protocol,t=>{this.handleMessage(t).catch(e=>{this.log.error("error handling perf protocol message",e)})},{maxInboundStreams:this.maxInboundStreams,maxOutboundStreams:this.maxOutboundStreams,runOnTransientConnection:this.runOnTransientConnection}),this.started=!0}async stop(){await this.components.registrar.unhandle(this.protocol),this.started=!1}isStarted(){return this.started}async handleMessage(t){let{stream:e}=t;try{let o=this.writeBlockSize,n;for await(let u of e.source)n==null&&(n=Number(u.getBigUint64(0,!1)));if(n==null)throw new Error("bytesToSendBack was not set");let c=new Uint8Array(this.databuf,0,this.databuf.byteLength);await e.sink(async function*(){for(;n>0;){let u=o;u>n&&(u=n),n=n-u,yield c.subarray(0,u)}}())}catch(o){e.abort(o)}}async*measurePerformance(t,e,o,n={}){this.log("opening stream on protocol %s to %a",this.protocol,t);let c=new Uint8Array(this.databuf),u=this.writeBlockSize,y=Date.now(),l=Date.now(),d=await this.components.connectionManager.openConnection(t,{...n,force:n.reuseExistingConnection!==!0});this.log("opened connection after %d ms",Date.now()-l),l=Date.now();let p=await d.newStream(this.protocol,n);this.log("opened stream after %d ms",Date.now()-l),l=Date.now();let m=0,f=0,E=Date.now();new DataView(this.databuf).setBigUint64(0,BigInt(o),!1),this.log("sending %i bytes to %p",e,d.remotePeer);try{let a=B({objectMode:!0});p.sink(async function*(){for(yield c.subarray(0,8);e>0;){let i=u;i>e&&(i=e),yield c.subarray(0,i),e-=i,Date.now()-l>1e3&&(a.push({type:"intermediary",timeSeconds:(Date.now()-l)/1e3,uploadBytes:m,downloadBytes:0}),l=Date.now(),m=0),m+=i,f+=i}a.end()}()).catch(i=>{a.end(i)}),yield*a,this.log("upload complete after %d ms",Date.now()-E);let r=0;l=Date.now();let h=0,w=Date.now();for await(let i of p.source)Date.now()-l>1e3&&(yield{type:"intermediary",timeSeconds:(Date.now()-l)/1e3,uploadBytes:0,downloadBytes:r},l=Date.now(),r=0),r+=i.byteLength,h+=i.byteLength;if(this.log("download complete after %d ms",Date.now()-w),h!==o)throw new Error(`Expected to receive ${o} bytes, but received ${h}`);yield{type:"final",timeSeconds:(Date.now()-y)/1e3,uploadBytes:f,downloadBytes:h},this.log("performed %s to %p",this.protocol,d.remotePeer),await p.close()}catch(a){throw this.log("error sending %d/%d bytes to %p: %s",f,e,d.remotePeer,a),p.abort(a),a}}};function X(s={}){return t=>new x(t,s)}return R(j);})();
|
3
3
|
return Libp2PPerf}));
|
package/dist/src/index.d.ts
CHANGED
@@ -11,14 +11,14 @@
|
|
11
11
|
* import { mplex } from '@libp2p/mplex'
|
12
12
|
* import { tcp } from '@libp2p/tcp'
|
13
13
|
* import { createLibp2p, type Libp2p } from 'libp2p'
|
14
|
-
* import { plaintext } from 'libp2p/
|
15
|
-
* import {
|
14
|
+
* import { plaintext } from '@libp2p/plaintext'
|
15
|
+
* import { perf, type Perf } from '@libp2p/perf'
|
16
16
|
*
|
17
17
|
* const ONE_MEG = 1024 * 1024
|
18
18
|
* const UPLOAD_BYTES = ONE_MEG * 1024
|
19
19
|
* const DOWNLOAD_BYTES = ONE_MEG * 1024
|
20
20
|
*
|
21
|
-
* async function createNode (): Promise<Libp2p<{ perf:
|
21
|
+
* async function createNode (): Promise<Libp2p<{ perf: Perf }>> {
|
22
22
|
* return createLibp2p({
|
23
23
|
* addresses: {
|
24
24
|
* listen: [
|
@@ -35,7 +35,7 @@
|
|
35
35
|
* yamux(), mplex()
|
36
36
|
* ],
|
37
37
|
* services: {
|
38
|
-
* perf:
|
38
|
+
* perf: perf()
|
39
39
|
* }
|
40
40
|
* })
|
41
41
|
* }
|
@@ -51,7 +51,7 @@
|
|
51
51
|
* await libp2p2.stop()
|
52
52
|
* ```
|
53
53
|
*/
|
54
|
-
import type { AbortOptions } from '@libp2p/interface';
|
54
|
+
import type { AbortOptions, ComponentLogger } from '@libp2p/interface';
|
55
55
|
import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager';
|
56
56
|
import type { Registrar } from '@libp2p/interface-internal/registrar';
|
57
57
|
import type { Multiaddr } from '@multiformats/multiaddr';
|
@@ -65,16 +65,16 @@ export interface PerfOptions extends AbortOptions {
|
|
65
65
|
*/
|
66
66
|
reuseExistingConnection?: boolean;
|
67
67
|
}
|
68
|
-
export interface
|
68
|
+
export interface Perf {
|
69
69
|
measurePerformance(multiaddr: Multiaddr, sendBytes: number, recvBytes: number, options?: PerfOptions): AsyncGenerator<PerfOutput>;
|
70
70
|
}
|
71
71
|
export interface PerfOutput {
|
72
|
-
type: 'intermediary' | 'final';
|
72
|
+
type: 'connection' | 'stream' | 'intermediary' | 'final';
|
73
73
|
timeSeconds: number;
|
74
74
|
uploadBytes: number;
|
75
75
|
downloadBytes: number;
|
76
76
|
}
|
77
|
-
export interface
|
77
|
+
export interface PerfInit {
|
78
78
|
protocolName?: string;
|
79
79
|
maxInboundStreams?: number;
|
80
80
|
maxOutboundStreams?: number;
|
@@ -84,9 +84,10 @@ export interface PerfServiceInit {
|
|
84
84
|
*/
|
85
85
|
writeBlockSize?: number;
|
86
86
|
}
|
87
|
-
export interface
|
87
|
+
export interface PerfComponents {
|
88
88
|
registrar: Registrar;
|
89
89
|
connectionManager: ConnectionManager;
|
90
|
+
logger: ComponentLogger;
|
90
91
|
}
|
91
|
-
export declare function
|
92
|
+
export declare function perf(init?: PerfInit): (components: PerfComponents) => Perf;
|
92
93
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAA;AACtF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAA;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAExD,MAAM,WAAW,WAAY,SAAQ,YAAY;IAC/C;;;;;;OAMG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAClC;AAED,MAAM,WAAW,IAAI;IACnB,kBAAkB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;CAClI;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,cAAc,GAAG,OAAO,CAAA;IACxD,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAElC;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,SAAS,CAAA;IACpB,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,wBAAgB,IAAI,CAAE,IAAI,GAAE,QAAa,GAAG,CAAC,UAAU,EAAE,cAAc,KAAK,IAAI,CAE/E"}
|
package/dist/src/index.js
CHANGED
@@ -11,14 +11,14 @@
|
|
11
11
|
* import { mplex } from '@libp2p/mplex'
|
12
12
|
* import { tcp } from '@libp2p/tcp'
|
13
13
|
* import { createLibp2p, type Libp2p } from 'libp2p'
|
14
|
-
* import { plaintext } from 'libp2p/
|
15
|
-
* import {
|
14
|
+
* import { plaintext } from '@libp2p/plaintext'
|
15
|
+
* import { perf, type Perf } from '@libp2p/perf'
|
16
16
|
*
|
17
17
|
* const ONE_MEG = 1024 * 1024
|
18
18
|
* const UPLOAD_BYTES = ONE_MEG * 1024
|
19
19
|
* const DOWNLOAD_BYTES = ONE_MEG * 1024
|
20
20
|
*
|
21
|
-
* async function createNode (): Promise<Libp2p<{ perf:
|
21
|
+
* async function createNode (): Promise<Libp2p<{ perf: Perf }>> {
|
22
22
|
* return createLibp2p({
|
23
23
|
* addresses: {
|
24
24
|
* listen: [
|
@@ -35,7 +35,7 @@
|
|
35
35
|
* yamux(), mplex()
|
36
36
|
* ],
|
37
37
|
* services: {
|
38
|
-
* perf:
|
38
|
+
* perf: perf()
|
39
39
|
* }
|
40
40
|
* })
|
41
41
|
* }
|
@@ -51,8 +51,8 @@
|
|
51
51
|
* await libp2p2.stop()
|
52
52
|
* ```
|
53
53
|
*/
|
54
|
-
import {
|
55
|
-
export function
|
56
|
-
return (components) => new
|
54
|
+
import { Perf as PerfClass } from './perf-service.js';
|
55
|
+
export function perf(init = {}) {
|
56
|
+
return (components) => new PerfClass(components, init);
|
57
57
|
}
|
58
58
|
//# sourceMappingURL=index.js.map
|
package/dist/src/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,EAAE,
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,mBAAmB,CAAA;AA8CrD,MAAM,UAAU,IAAI,CAAE,OAAiB,EAAE;IACvC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;AACxD,CAAC"}
|
@@ -1,8 +1,9 @@
|
|
1
|
-
import type { PerfOptions, PerfOutput,
|
1
|
+
import type { PerfOptions, PerfOutput, PerfComponents, PerfInit, Perf as PerfInterface } from './index.js';
|
2
2
|
import type { Startable } from '@libp2p/interface/startable';
|
3
3
|
import type { IncomingStreamData } from '@libp2p/interface-internal/registrar';
|
4
4
|
import type { Multiaddr } from '@multiformats/multiaddr';
|
5
|
-
export declare class
|
5
|
+
export declare class Perf implements Startable, PerfInterface {
|
6
|
+
private readonly log;
|
6
7
|
readonly protocol: string;
|
7
8
|
private readonly components;
|
8
9
|
private started;
|
@@ -11,7 +12,7 @@ export declare class PerfService implements Startable, PerfServiceInterface {
|
|
11
12
|
private readonly maxInboundStreams;
|
12
13
|
private readonly maxOutboundStreams;
|
13
14
|
private readonly runOnTransientConnection;
|
14
|
-
constructor(components:
|
15
|
+
constructor(components: PerfComponents, init?: PerfInit);
|
15
16
|
start(): Promise<void>;
|
16
17
|
stop(): Promise<void>;
|
17
18
|
isStarted(): boolean;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"perf-service.d.ts","sourceRoot":"","sources":["../../src/perf-service.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"perf-service.d.ts","sourceRoot":"","sources":["../../src/perf-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAExD,qBAAa,IAAK,YAAW,SAAS,EAAE,aAAa;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,SAAgB,QAAQ,EAAE,MAAM,CAAA;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAa;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAC1C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAQ;IAC3C,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAS;gBAErC,UAAU,EAAE,cAAc,EAAE,IAAI,GAAE,QAAa;IAYtD,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAavB,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;IAK5B,SAAS,IAAK,OAAO;IAIf,aAAa,CAAE,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCrD,kBAAkB,CAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,cAAc,CAAC,UAAU,CAAC;CA6H3I"}
|
package/dist/src/perf-service.js
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
import { logger } from '@libp2p/logger';
|
2
1
|
import { pushable } from 'it-pushable';
|
3
2
|
import { MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, PROTOCOL_NAME, RUN_ON_TRANSIENT_CONNECTION, WRITE_BLOCK_SIZE } from './constants.js';
|
4
|
-
|
5
|
-
|
3
|
+
export class Perf {
|
4
|
+
log;
|
6
5
|
protocol;
|
7
6
|
components;
|
8
7
|
started;
|
@@ -13,6 +12,7 @@ export class PerfService {
|
|
13
12
|
runOnTransientConnection;
|
14
13
|
constructor(components, init = {}) {
|
15
14
|
this.components = components;
|
15
|
+
this.log = components.logger.forComponent('libp2p:perf');
|
16
16
|
this.started = false;
|
17
17
|
this.protocol = init.protocolName ?? PROTOCOL_NAME;
|
18
18
|
this.writeBlockSize = init.writeBlockSize ?? WRITE_BLOCK_SIZE;
|
@@ -24,7 +24,7 @@ export class PerfService {
|
|
24
24
|
async start() {
|
25
25
|
await this.components.registrar.handle(this.protocol, (data) => {
|
26
26
|
void this.handleMessage(data).catch((err) => {
|
27
|
-
log.error('error handling perf protocol message', err);
|
27
|
+
this.log.error('error handling perf protocol message', err);
|
28
28
|
});
|
29
29
|
}, {
|
30
30
|
maxInboundStreams: this.maxInboundStreams,
|
@@ -55,7 +55,7 @@ export class PerfService {
|
|
55
55
|
if (bytesToSendBack == null) {
|
56
56
|
throw new Error('bytesToSendBack was not set');
|
57
57
|
}
|
58
|
-
const uint8Buf = new Uint8Array(this.databuf);
|
58
|
+
const uint8Buf = new Uint8Array(this.databuf, 0, this.databuf.byteLength);
|
59
59
|
await stream.sink(async function* () {
|
60
60
|
while (bytesToSendBack > 0) {
|
61
61
|
let toSend = writeBlockSize;
|
@@ -72,41 +72,43 @@ export class PerfService {
|
|
72
72
|
}
|
73
73
|
}
|
74
74
|
async *measurePerformance(ma, sendBytes, receiveBytes, options = {}) {
|
75
|
-
log('opening stream on protocol %s to %a', this.protocol, ma);
|
75
|
+
this.log('opening stream on protocol %s to %a', this.protocol, ma);
|
76
76
|
const uint8Buf = new Uint8Array(this.databuf);
|
77
77
|
const writeBlockSize = this.writeBlockSize;
|
78
|
-
// start time should include connection establishment
|
79
78
|
const initialStartTime = Date.now();
|
79
|
+
let lastReportedTime = Date.now();
|
80
80
|
const connection = await this.components.connectionManager.openConnection(ma, {
|
81
81
|
...options,
|
82
82
|
force: options.reuseExistingConnection !== true
|
83
83
|
});
|
84
|
+
this.log('opened connection after %d ms', Date.now() - lastReportedTime);
|
85
|
+
lastReportedTime = Date.now();
|
84
86
|
const stream = await connection.newStream(this.protocol, options);
|
87
|
+
this.log('opened stream after %d ms', Date.now() - lastReportedTime);
|
88
|
+
lastReportedTime = Date.now();
|
85
89
|
let lastAmountOfBytesSent = 0;
|
86
|
-
let lastReportedTime = Date.now();
|
87
90
|
let totalBytesSent = 0;
|
91
|
+
const uploadStart = Date.now();
|
88
92
|
// tell the remote how many bytes we will send. Up cast to 64 bit number
|
89
93
|
// as if we send as ui32 we limit total transfer size to 4GB
|
90
94
|
const view = new DataView(this.databuf);
|
91
95
|
view.setBigUint64(0, BigInt(receiveBytes), false);
|
92
|
-
log('sending %i bytes to %p', sendBytes, connection.remotePeer);
|
96
|
+
this.log('sending %i bytes to %p', sendBytes, connection.remotePeer);
|
93
97
|
try {
|
94
|
-
const
|
98
|
+
const output = pushable({
|
95
99
|
objectMode: true
|
96
100
|
});
|
97
|
-
|
98
|
-
// Send the number of bytes to receive
|
101
|
+
stream.sink(async function* () {
|
99
102
|
yield uint8Buf.subarray(0, 8);
|
100
103
|
while (sendBytes > 0) {
|
101
|
-
options.signal?.throwIfAborted();
|
102
104
|
let toSend = writeBlockSize;
|
103
105
|
if (toSend > sendBytes) {
|
104
106
|
toSend = sendBytes;
|
105
107
|
}
|
106
|
-
sendBytes = sendBytes - toSend;
|
107
108
|
yield uint8Buf.subarray(0, toSend);
|
109
|
+
sendBytes -= toSend;
|
108
110
|
if (Date.now() - lastReportedTime > 1000) {
|
109
|
-
|
111
|
+
output.push({
|
110
112
|
type: 'intermediary',
|
111
113
|
timeSeconds: (Date.now() - lastReportedTime) / 1000,
|
112
114
|
uploadBytes: lastAmountOfBytesSent,
|
@@ -120,18 +122,19 @@ export class PerfService {
|
|
120
122
|
lastAmountOfBytesSent += toSend;
|
121
123
|
totalBytesSent += toSend;
|
122
124
|
}
|
123
|
-
|
125
|
+
output.end();
|
124
126
|
}())
|
125
127
|
.catch(err => {
|
126
|
-
|
128
|
+
output.end(err);
|
127
129
|
});
|
128
|
-
yield*
|
130
|
+
yield* output;
|
131
|
+
this.log('upload complete after %d ms', Date.now() - uploadStart);
|
129
132
|
// Read the received bytes
|
130
133
|
let lastAmountOfBytesReceived = 0;
|
131
134
|
lastReportedTime = Date.now();
|
132
135
|
let totalBytesReceived = 0;
|
136
|
+
const downloadStart = Date.now();
|
133
137
|
for await (const buf of stream.source) {
|
134
|
-
options.signal?.throwIfAborted();
|
135
138
|
if (Date.now() - lastReportedTime > 1000) {
|
136
139
|
yield {
|
137
140
|
type: 'intermediary',
|
@@ -147,6 +150,7 @@ export class PerfService {
|
|
147
150
|
lastAmountOfBytesReceived += buf.byteLength;
|
148
151
|
totalBytesReceived += buf.byteLength;
|
149
152
|
}
|
153
|
+
this.log('download complete after %d ms', Date.now() - downloadStart);
|
150
154
|
if (totalBytesReceived !== receiveBytes) {
|
151
155
|
throw new Error(`Expected to receive ${receiveBytes} bytes, but received ${totalBytesReceived}`);
|
152
156
|
}
|
@@ -156,11 +160,11 @@ export class PerfService {
|
|
156
160
|
uploadBytes: totalBytesSent,
|
157
161
|
downloadBytes: totalBytesReceived
|
158
162
|
};
|
159
|
-
log('performed %s to %p', this.protocol, connection.remotePeer);
|
163
|
+
this.log('performed %s to %p', this.protocol, connection.remotePeer);
|
160
164
|
await stream.close();
|
161
165
|
}
|
162
166
|
catch (err) {
|
163
|
-
log('error sending %d/%d bytes to %p: %s', totalBytesSent, sendBytes, connection.remotePeer, err);
|
167
|
+
this.log('error sending %d/%d bytes to %p: %s', totalBytesSent, sendBytes, connection.remotePeer, err);
|
164
168
|
stream.abort(err);
|
165
169
|
throw err;
|
166
170
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"perf-service.js","sourceRoot":"","sources":["../../src/perf-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
1
|
+
{"version":3,"file":"perf-service.js","sourceRoot":"","sources":["../../src/perf-service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
{
|
2
2
|
"name": "@libp2p/perf",
|
3
|
-
"version": "2.0.1-
|
3
|
+
"version": "2.0.1-d8f5bc211",
|
4
4
|
"description": "Implementation of Perf Protocol",
|
5
5
|
"author": "@maschad / @marcopolo",
|
6
6
|
"license": "Apache-2.0 OR MIT",
|
7
|
-
"homepage": "https://github.com/libp2p/js-libp2p/tree/
|
7
|
+
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/protocol-perf#readme",
|
8
8
|
"repository": {
|
9
9
|
"type": "git",
|
10
10
|
"url": "git+https://github.com/libp2p/js-libp2p.git"
|
@@ -48,14 +48,14 @@
|
|
48
48
|
"renderResults": "node dist/src/renderResults.js"
|
49
49
|
},
|
50
50
|
"dependencies": {
|
51
|
-
"@libp2p/interface": "0.1.6-
|
52
|
-
"@libp2p/interface-internal": "0.1.9-
|
53
|
-
"@libp2p/logger": "3.1.0-c960eb659",
|
51
|
+
"@libp2p/interface": "0.1.6-d8f5bc211",
|
52
|
+
"@libp2p/interface-internal": "0.1.9-d8f5bc211",
|
54
53
|
"@multiformats/multiaddr": "^12.1.10",
|
55
|
-
"it-pushable": "^3.2.
|
54
|
+
"it-pushable": "^3.2.3"
|
56
55
|
},
|
57
56
|
"devDependencies": {
|
58
|
-
"@libp2p/interface-compliance-tests": "4.1.5-
|
57
|
+
"@libp2p/interface-compliance-tests": "4.1.5-d8f5bc211",
|
58
|
+
"@libp2p/logger": "3.1.0-d8f5bc211",
|
59
59
|
"aegir": "^41.0.2",
|
60
60
|
"it-last": "^3.0.3",
|
61
61
|
"it-pair": "^2.0.6",
|
package/src/index.ts
CHANGED
@@ -11,14 +11,14 @@
|
|
11
11
|
* import { mplex } from '@libp2p/mplex'
|
12
12
|
* import { tcp } from '@libp2p/tcp'
|
13
13
|
* import { createLibp2p, type Libp2p } from 'libp2p'
|
14
|
-
* import { plaintext } from 'libp2p/
|
15
|
-
* import {
|
14
|
+
* import { plaintext } from '@libp2p/plaintext'
|
15
|
+
* import { perf, type Perf } from '@libp2p/perf'
|
16
16
|
*
|
17
17
|
* const ONE_MEG = 1024 * 1024
|
18
18
|
* const UPLOAD_BYTES = ONE_MEG * 1024
|
19
19
|
* const DOWNLOAD_BYTES = ONE_MEG * 1024
|
20
20
|
*
|
21
|
-
* async function createNode (): Promise<Libp2p<{ perf:
|
21
|
+
* async function createNode (): Promise<Libp2p<{ perf: Perf }>> {
|
22
22
|
* return createLibp2p({
|
23
23
|
* addresses: {
|
24
24
|
* listen: [
|
@@ -35,7 +35,7 @@
|
|
35
35
|
* yamux(), mplex()
|
36
36
|
* ],
|
37
37
|
* services: {
|
38
|
-
* perf:
|
38
|
+
* perf: perf()
|
39
39
|
* }
|
40
40
|
* })
|
41
41
|
* }
|
@@ -52,8 +52,8 @@
|
|
52
52
|
* ```
|
53
53
|
*/
|
54
54
|
|
55
|
-
import {
|
56
|
-
import type { AbortOptions } from '@libp2p/interface'
|
55
|
+
import { Perf as PerfClass } from './perf-service.js'
|
56
|
+
import type { AbortOptions, ComponentLogger } from '@libp2p/interface'
|
57
57
|
import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager'
|
58
58
|
import type { Registrar } from '@libp2p/interface-internal/registrar'
|
59
59
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
@@ -69,18 +69,18 @@ export interface PerfOptions extends AbortOptions {
|
|
69
69
|
reuseExistingConnection?: boolean
|
70
70
|
}
|
71
71
|
|
72
|
-
export interface
|
72
|
+
export interface Perf {
|
73
73
|
measurePerformance(multiaddr: Multiaddr, sendBytes: number, recvBytes: number, options?: PerfOptions): AsyncGenerator<PerfOutput>
|
74
74
|
}
|
75
75
|
|
76
76
|
export interface PerfOutput {
|
77
|
-
type: 'intermediary' | 'final'
|
77
|
+
type: 'connection' | 'stream' | 'intermediary' | 'final'
|
78
78
|
timeSeconds: number
|
79
79
|
uploadBytes: number
|
80
80
|
downloadBytes: number
|
81
81
|
}
|
82
82
|
|
83
|
-
export interface
|
83
|
+
export interface PerfInit {
|
84
84
|
protocolName?: string
|
85
85
|
maxInboundStreams?: number
|
86
86
|
maxOutboundStreams?: number
|
@@ -92,11 +92,12 @@ export interface PerfServiceInit {
|
|
92
92
|
writeBlockSize?: number
|
93
93
|
}
|
94
94
|
|
95
|
-
export interface
|
95
|
+
export interface PerfComponents {
|
96
96
|
registrar: Registrar
|
97
97
|
connectionManager: ConnectionManager
|
98
|
+
logger: ComponentLogger
|
98
99
|
}
|
99
100
|
|
100
|
-
export function
|
101
|
-
return (components) => new
|
101
|
+
export function perf (init: PerfInit = {}): (components: PerfComponents) => Perf {
|
102
|
+
return (components) => new PerfClass(components, init)
|
102
103
|
}
|
package/src/perf-service.ts
CHANGED
@@ -1,16 +1,15 @@
|
|
1
|
-
import { logger } from '@libp2p/logger'
|
2
1
|
import { pushable } from 'it-pushable'
|
3
2
|
import { MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, PROTOCOL_NAME, RUN_ON_TRANSIENT_CONNECTION, WRITE_BLOCK_SIZE } from './constants.js'
|
4
|
-
import type { PerfOptions, PerfOutput,
|
3
|
+
import type { PerfOptions, PerfOutput, PerfComponents, PerfInit, Perf as PerfInterface } from './index.js'
|
4
|
+
import type { Logger } from '@libp2p/interface'
|
5
5
|
import type { Startable } from '@libp2p/interface/startable'
|
6
6
|
import type { IncomingStreamData } from '@libp2p/interface-internal/registrar'
|
7
7
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
export class PerfService implements Startable, PerfServiceInterface {
|
9
|
+
export class Perf implements Startable, PerfInterface {
|
10
|
+
private readonly log: Logger
|
12
11
|
public readonly protocol: string
|
13
|
-
private readonly components:
|
12
|
+
private readonly components: PerfComponents
|
14
13
|
private started: boolean
|
15
14
|
private readonly databuf: ArrayBuffer
|
16
15
|
private readonly writeBlockSize: number
|
@@ -18,8 +17,9 @@ export class PerfService implements Startable, PerfServiceInterface {
|
|
18
17
|
private readonly maxOutboundStreams: number
|
19
18
|
private readonly runOnTransientConnection: boolean
|
20
19
|
|
21
|
-
constructor (components:
|
20
|
+
constructor (components: PerfComponents, init: PerfInit = {}) {
|
22
21
|
this.components = components
|
22
|
+
this.log = components.logger.forComponent('libp2p:perf')
|
23
23
|
this.started = false
|
24
24
|
this.protocol = init.protocolName ?? PROTOCOL_NAME
|
25
25
|
this.writeBlockSize = init.writeBlockSize ?? WRITE_BLOCK_SIZE
|
@@ -32,7 +32,7 @@ export class PerfService implements Startable, PerfServiceInterface {
|
|
32
32
|
async start (): Promise<void> {
|
33
33
|
await this.components.registrar.handle(this.protocol, (data: IncomingStreamData) => {
|
34
34
|
void this.handleMessage(data).catch((err) => {
|
35
|
-
log.error('error handling perf protocol message', err)
|
35
|
+
this.log.error('error handling perf protocol message', err)
|
36
36
|
})
|
37
37
|
}, {
|
38
38
|
maxInboundStreams: this.maxInboundStreams,
|
@@ -64,6 +64,7 @@ export class PerfService implements Startable, PerfServiceInterface {
|
|
64
64
|
// downcast 64 to 52 bits to avoid bigint arithmetic performance penalty
|
65
65
|
bytesToSendBack = Number(buf.getBigUint64(0, false))
|
66
66
|
}
|
67
|
+
|
67
68
|
// Ingest all the bufs and wait for the read side to close
|
68
69
|
}
|
69
70
|
|
@@ -71,7 +72,7 @@ export class PerfService implements Startable, PerfServiceInterface {
|
|
71
72
|
throw new Error('bytesToSendBack was not set')
|
72
73
|
}
|
73
74
|
|
74
|
-
const uint8Buf = new Uint8Array(this.databuf)
|
75
|
+
const uint8Buf = new Uint8Array(this.databuf, 0, this.databuf.byteLength)
|
75
76
|
|
76
77
|
await stream.sink(async function * () {
|
77
78
|
while (bytesToSendBack > 0) {
|
@@ -90,51 +91,58 @@ export class PerfService implements Startable, PerfServiceInterface {
|
|
90
91
|
}
|
91
92
|
|
92
93
|
async * measurePerformance (ma: Multiaddr, sendBytes: number, receiveBytes: number, options: PerfOptions = {}): AsyncGenerator<PerfOutput> {
|
93
|
-
log('opening stream on protocol %s to %a', this.protocol, ma)
|
94
|
+
this.log('opening stream on protocol %s to %a', this.protocol, ma)
|
94
95
|
|
95
96
|
const uint8Buf = new Uint8Array(this.databuf)
|
96
97
|
const writeBlockSize = this.writeBlockSize
|
97
98
|
|
98
|
-
// start time should include connection establishment
|
99
99
|
const initialStartTime = Date.now()
|
100
|
+
let lastReportedTime = Date.now()
|
100
101
|
const connection = await this.components.connectionManager.openConnection(ma, {
|
101
102
|
...options,
|
102
103
|
force: options.reuseExistingConnection !== true
|
103
104
|
})
|
105
|
+
|
106
|
+
this.log('opened connection after %d ms', Date.now() - lastReportedTime)
|
107
|
+
lastReportedTime = Date.now()
|
108
|
+
|
104
109
|
const stream = await connection.newStream(this.protocol, options)
|
105
110
|
|
111
|
+
this.log('opened stream after %d ms', Date.now() - lastReportedTime)
|
112
|
+
lastReportedTime = Date.now()
|
113
|
+
|
106
114
|
let lastAmountOfBytesSent = 0
|
107
|
-
let lastReportedTime = Date.now()
|
108
115
|
let totalBytesSent = 0
|
116
|
+
const uploadStart = Date.now()
|
109
117
|
|
110
118
|
// tell the remote how many bytes we will send. Up cast to 64 bit number
|
111
119
|
// as if we send as ui32 we limit total transfer size to 4GB
|
112
120
|
const view = new DataView(this.databuf)
|
113
121
|
view.setBigUint64(0, BigInt(receiveBytes), false)
|
114
122
|
|
115
|
-
log('sending %i bytes to %p', sendBytes, connection.remotePeer)
|
123
|
+
this.log('sending %i bytes to %p', sendBytes, connection.remotePeer)
|
116
124
|
|
117
125
|
try {
|
118
|
-
const
|
126
|
+
const output = pushable<PerfOutput>({
|
119
127
|
objectMode: true
|
120
128
|
})
|
121
129
|
|
122
|
-
|
123
|
-
// Send the number of bytes to receive
|
130
|
+
stream.sink(async function * () {
|
124
131
|
yield uint8Buf.subarray(0, 8)
|
125
132
|
|
126
133
|
while (sendBytes > 0) {
|
127
|
-
options.signal?.throwIfAborted()
|
128
|
-
|
129
134
|
let toSend: number = writeBlockSize
|
135
|
+
|
130
136
|
if (toSend > sendBytes) {
|
131
137
|
toSend = sendBytes
|
132
138
|
}
|
133
|
-
|
139
|
+
|
134
140
|
yield uint8Buf.subarray(0, toSend)
|
135
141
|
|
142
|
+
sendBytes -= toSend
|
143
|
+
|
136
144
|
if (Date.now() - lastReportedTime > 1000) {
|
137
|
-
|
145
|
+
output.push({
|
138
146
|
type: 'intermediary',
|
139
147
|
timeSeconds: (Date.now() - lastReportedTime) / 1000,
|
140
148
|
uploadBytes: lastAmountOfBytesSent,
|
@@ -151,22 +159,23 @@ export class PerfService implements Startable, PerfServiceInterface {
|
|
151
159
|
totalBytesSent += toSend
|
152
160
|
}
|
153
161
|
|
154
|
-
|
162
|
+
output.end()
|
155
163
|
}())
|
156
164
|
.catch(err => {
|
157
|
-
|
165
|
+
output.end(err)
|
158
166
|
})
|
159
167
|
|
160
|
-
yield *
|
168
|
+
yield * output
|
169
|
+
|
170
|
+
this.log('upload complete after %d ms', Date.now() - uploadStart)
|
161
171
|
|
162
172
|
// Read the received bytes
|
163
173
|
let lastAmountOfBytesReceived = 0
|
164
174
|
lastReportedTime = Date.now()
|
165
175
|
let totalBytesReceived = 0
|
176
|
+
const downloadStart = Date.now()
|
166
177
|
|
167
178
|
for await (const buf of stream.source) {
|
168
|
-
options.signal?.throwIfAborted()
|
169
|
-
|
170
179
|
if (Date.now() - lastReportedTime > 1000) {
|
171
180
|
yield {
|
172
181
|
type: 'intermediary',
|
@@ -185,6 +194,8 @@ export class PerfService implements Startable, PerfServiceInterface {
|
|
185
194
|
totalBytesReceived += buf.byteLength
|
186
195
|
}
|
187
196
|
|
197
|
+
this.log('download complete after %d ms', Date.now() - downloadStart)
|
198
|
+
|
188
199
|
if (totalBytesReceived !== receiveBytes) {
|
189
200
|
throw new Error(`Expected to receive ${receiveBytes} bytes, but received ${totalBytesReceived}`)
|
190
201
|
}
|
@@ -196,10 +207,10 @@ export class PerfService implements Startable, PerfServiceInterface {
|
|
196
207
|
downloadBytes: totalBytesReceived
|
197
208
|
}
|
198
209
|
|
199
|
-
log('performed %s to %p', this.protocol, connection.remotePeer)
|
210
|
+
this.log('performed %s to %p', this.protocol, connection.remotePeer)
|
200
211
|
await stream.close()
|
201
212
|
} catch (err: any) {
|
202
|
-
log('error sending %d/%d bytes to %p: %s', totalBytesSent, sendBytes, connection.remotePeer, err)
|
213
|
+
this.log('error sending %d/%d bytes to %p: %s', totalBytesSent, sendBytes, connection.remotePeer, err)
|
203
214
|
stream.abort(err)
|
204
215
|
throw err
|
205
216
|
}
|