+1
-1
docs/assets/index-KS4_m-xo.js
docs/assets/index-TkW73U8w.js
+1
-1
docs/assets/index-KS4_m-xo.js
docs/assets/index-TkW73U8w.js
···
229
229
const firehose = new Firehose({
230
230
ws: WebSocket,
231
231
});`);const a=e.ws??globalThis.WebSocket;this.ws=new a(`${this.relay}/xrpc/com.atproto.sync.subscribeRepos${r}`)}start(){this.ws.addEventListener("open",()=>{this.emitter.emit("open")}),this.ws.addEventListener("message",async({data:e})=>{try{const r=await this.parseMessage(e);switch("seq"in r&&r.seq&&!isNaN(r.seq)&&(this.cursor=`${r.seq}`),r.$type){case"com.atproto.sync.subscribeRepos#identity":this.emitter.emit("identity",r);break;case"com.atproto.sync.subscribeRepos#account":this.emitter.emit("account",r);break;case"com.atproto.sync.subscribeRepos#info":this.emitter.emit("info",r);break;case"com.atproto.sync.subscribeRepos#sync":this.emitter.emit("sync",r);break;case"com.atproto.sync.subscribeRepos#commit":this.emitter.emit("commit",r);break;default:this.emitter.emit("unknown",r);break}}catch(r){this.emitter.emit("error",{cursor:this.cursor,error:r})}finally{this.autoReconnect&&this.preventReconnect()}}),this.ws.addEventListener("close",()=>{this.emitter.emit("close",this.cursor)}),this.ws.addEventListener("error",e=>{this.emitter.emit("websocketError",{cursor:this.cursor,error:e})})}close(){var e;(e=this.ws)==null||e.close()}on(e,r){return this.emitter.on(e,r)}async parseMessage(e){var d,m;const r=new Uint8Array(await new Blob(Array.isArray(e)?e:[e]).arrayBuffer()),[a,s]=Xp(r),[l,c]=Xp(s);if(c.length>0)throw new Error("Excess bytes in message");const{t:f,op:p}=RL(a);if(p===-1)throw new Error(`Error: ${l.message}
232
-
Error code: ${l.error}`);if(f==="#commit"){const{seq:y,repo:v,commit:b,rev:x,since:S,blocks:A,ops:w,prevData:D,time:O}=l;if(!((d=A==null?void 0:A.$bytes)!=null&&d.length))return{$type:"com.atproto.sync.subscribeRepos#commit",seq:y,repo:v,commit:b.$link,rev:x,since:S,blocks:new Uint8Array,ops:[],...D?{prevData:D.$link}:{},time:O};const R=Rx(A),E=kL(R),k=[];for(const z of w){const H=z.action;if(H==="create"){if(!z.cid)continue;const L=E.get(z.cid.$link);if(!L)continue;k.push({action:H,path:z.path,cid:z.cid.$link,record:L})}else if(H==="update"){if(!z.cid)continue;const L=E.get(z.cid.$link);if(!L)continue;k.push({action:H,path:z.path,cid:z.cid.$link,...z.prev?{prev:z.prev.$link}:{},record:L})}else if(H==="delete")k.push({action:H,path:z.path,...z.prev?{prev:z.prev.$link}:{}});else throw new Error(`Unknown action: ${H}`)}return{$type:"com.atproto.sync.subscribeRepos#commit",seq:y,repo:v,commit:b.$link,rev:x,since:S,blocks:R,ops:k,...D?{prevData:D.$link}:{},time:O}}else if(f==="#sync"){const{seq:y,did:v,blocks:b,rev:x,time:S}=l,A=(m=b==null?void 0:b.$bytes)!=null&&m.length?Rx(b):new Uint8Array;return{$type:"com.atproto.sync.subscribeRepos#sync",seq:y,did:v,blocks:A,rev:x,time:S}}return{$type:`com.atproto.sync.subscribeRepos${f}`,...l}}preventReconnect(){this.reconnectTimeout&&clearTimeout(this.reconnectTimeout),this.reconnectTimeout=setTimeout(()=>{this.reconnect()},5e3)}reconnect(){var e;(e=this.ws)==null||e.close(),this.start(),this.emitter.emit("reconnect")}}function RL(t){if(!t||typeof t!="object"||!t.t||typeof t.t!="string"||!t.op||typeof t.op!="number")throw new Error("Invalid header received");return{t:t.t,op:t.op}}function kL(t){const e=new Map;for(const{cid:r,bytes:a}of wL(t).iterate())e.set(cL(r).$link,YT(a));return e}const DL="234567abcdefghijklmnopqrstuvwxyz",_x=t=>{let e=0;for(const r of t)e=e*32+DL.indexOf(r);return e},_L=/^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$/,zL=t=>{if(!$L(t))throw new Error("invalid TID");const e=_x(t.slice(0,11)),r=_x(t.slice(11,13));return{timestamp:e,clockid:r}},$L=t=>t.length===13&&_L.test(t),NL="app.bsky.feed.like",Ys=32,Gi=32,ec=Ys*Gi;function LL({url:t,desc:e,includeEvents:r,onRecieveEvent:a}){const[s,l]=U.useState("connecting"),[c,f]=U.useState(0),[p,d]=U.useState(0),[m,y]=U.useState({idx:Array.from({length:Gi+2}).map(()=>0),recv:Array.from({length:Gi+2}).map(()=>0)});return U.useEffect(()=>{const v=(x,S)=>{if(r.has(x)&&(a(x,S),f(A=>A+1),x==="commit"&&S.ops.length===1)){const A=S.ops[0];try{const[w,D]=A.path.split("/");if(w===NL){const O=zL(D).timestamp/1e3,R=Date.parse(S.time),E=R-O,k=+new Date-R;let z,H;E<0?z=-1:E>=ec?z=Gi:z=Math.min(Math.floor(E/Ys),ec),k<0?H=-1:k>=ec?H=Gi:H=Math.min(Math.floor(k/Ys),ec),y(({idx:L,recv:C})=>(L=L.slice(),C=C.slice(),L[z+1]+=1,C[H+1]+=1,{idx:L,recv:C}))}}catch{}}},b=new OL({relay:t});return b.on("open",()=>l("connected")),b.on("close",()=>l("closed")),b.on("reconnect",()=>d(x=>x+1)),b.on("error",x=>{console.error("oops",x),l("errored")}),b.on("websocketError",()=>l("errored")),b.on("commit",x=>v("commit",x)),b.on("sync",x=>v("sync",x)),b.on("account",x=>v("account",x)),b.on("identity",x=>v("identity",x)),b.on("info",(...x)=>console.info("info event",...x)),b.on("unknown",x=>console.warn(`unknown event from ${t}`,x)),b.start(),()=>{b.close()}},[t,r]),N.jsxs("div",{className:"relay",children:[N.jsx("h2",{children:e}),N.jsx("p",{children:N.jsx("code",{children:t})}),N.jsxs("p",{children:["[",N.jsx("code",{children:s}),"] (",N.jsx("code",{children:c.toLocaleString()})," events)"]}),p>0&&N.jsxs("p",{children:["reconnects: ",N.jsx("code",{children:p})]}),N.jsx(Vp,{height:180,width:420,yAxis:[{label:"events",scaleType:"symlog"}],skipAnimation:!0,xAxis:[{data:[-1].concat(Array.from({length:Gi}).map((v,b)=>b*Ys)).concat(["+"]),label:"index latency (ms)"}],series:[{data:m.idx}]}),N.jsx(Vp,{height:180,width:420,yAxis:[{label:"events",scaleType:"symlog"}],skipAnimation:!0,xAxis:[{data:[-1].concat(Array.from({length:Gi}).map((v,b)=>b*Ys)).concat(["+"]),label:"receive latency (ms)"}],series:[{data:m.recv}]})]})}const zx=[{url:"wss://atproto.africa",desc:"Blacksky"},{url:"wss://bsky.network",desc:"Bluesky primary (+Rainbow)"},{url:"wss://relay1.us-east.bsky.network",desc:"Bluesky sync1.1 east (+Rainbow)"},{url:"wss://relay1.us-west.bsky.network",desc:"Bluesky sync1.1 west (+Rainbow)"},{url:"wss://relay.fire.hose.cam",desc:"microcosm Montreal"},{url:"wss://relay3.fr.hose.cam",desc:"microcosm France"},{url:"wss://relay.hayescmd.net",desc:"@edavis.dev's relay"},{url:"wss://relay.xero.systems",desc:"@dane.is.extraordinarily.cool's relay"}],$x=1600,jL=6,Nx=10*60*1e3,Lx=(t,e,r)=>{};function UL(){const[t,e]=U.useState([]),[r,a]=U.useState(["commit","sync","account","identity","unknown"]),[s,l]=U.useState(new Set(r)),[c,f]=U.useState(()=>Lx),[p,d]=U.useState(()=>()=>{}),[m,y]=U.useState({series:[]}),[v,b]=U.useState(!1),[x,S]=U.useState("");U.useEffect(()=>{let D=performance.now(),O={},R=[],E=requestAnimationFrame(L),k=setTimeout(z,Nx);f(()=>(C,_,I)=>{O[C]||(O[C]=0),O[C]+=1}),d(()=>()=>{clearTimeout(k),k=setTimeout(z,Nx),b(!1),console.info("keepalive: disconnection timer reset")});function z(){console.info("disconnecting due to inactivity"),e([]),b(!0)}const H=setInterval(()=>{let C=performance.now(),_=C-D;R.length>=jL-1&&R.shift(),R.push({t:C,dt:_,counts:O}),D=C,O={}},$x);function L(){var I;let C=performance.now();const _=Object.keys(((I=R.at(-1))==null?void 0:I.counts)||{}).toSorted();y({xAxis:[{data:R.map(({t:q})=>(-(C-q)/1e3).toFixed(1)).concat(["now"]),label:"bucket (seconds ago)"}],series:_.map(q=>({label:q,data:R.map(({dt:it,counts:lt})=>lt[q]?(lt[q]/(it/1e3)).toFixed(1):null).concat([O[q]?(O[q]/($x/1e3)).toFixed(1):null])}))}),E=requestAnimationFrame(L)}return()=>{f(()=>Lx),d(()=>()=>null),clearInterval(H),cancelAnimationFrame(E)}},[]);function A(D,O){b(!1),e(O?R=>R.includes(D)?R:[...R,D]:R=>R.includes(D)?R.filter(E=>E!==D):R),p()}function w(){if(!x)return"";try{let D;return x.includes("://")?D=new URL(x):D=new URL("https://"+x),D.protocol==="https:"?D.protocol="wss:":D.protocol==="http:"&&(D.protocol="ws:"),D.origin}catch{return""}}return N.jsxs(N.Fragment,{children:[N.jsx("h1",{children:"compare hoses"}),N.jsx("p",{children:N.jsxs("em",{children:["warning: enabling many relay connections requires a ",N.jsx("strong",{children:"lot"})," of bandwidth"]})}),N.jsxs("form",{style:{display:"block",textAlign:"left"},children:[zx.map(({url:D,desc:O})=>N.jsx("p",{style:{margin:0},children:N.jsxs("label",{children:[N.jsx("input",{type:"checkbox",onChange:R=>A(D,R.target.checked),checked:t.includes(D)}),` ${O} `,"(",N.jsx("code",{children:D.slice(6)}),")"]})},D)),N.jsx("p",{style:{margin:0},children:N.jsxs("label",{children:[N.jsx("input",{type:"checkbox",onChange:D=>{const O=w();O&&A(O,D.target.checked)},checked:t.includes(w())})," ",N.jsx("input",{type:"text",placeholder:"wss://…",value:x,onChange:D=>{const O=w();e(R=>R.includes(O)?R.filter(E=>E!==O):R),S(D.target.value)},onKeyDown:D=>{if(D.key!=="Enter")return;D.preventDefault();const O=w();O&&A(O,!0)}})," ",x&&N.jsx("code",{children:w()})]})})]}),N.jsxs("form",{style:{display:"block",margin:"1rem 0"},children:[N.jsx("span",{children:"events: "}),r.map(D=>N.jsxs("label",{children:[N.jsx("input",{type:"checkbox",checked:s.has(D),onChange:O=>{l(R=>{const E=new Set(R);return O.target.checked?E.add(D):E.delete(D),E})}})," ",D]},D))]}),N.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:"2em",textAlign:"left"},children:t.map(D=>{const{desc:O}=zx.find(R=>R.url===D)??{desc:"custom relay"};return N.jsx("div",{children:N.jsx(LL,{url:D,desc:O,includeEvents:s,onRecieveEvent:(R,E)=>c(D,R,E)})},D)})}),v&&N.jsx("p",{children:N.jsx("em",{children:"disconnected to save bandwidth due to inactivity"})}),N.jsx("div",{className:"throughputs",children:N.jsx(Vp,{height:300,yAxis:[{label:"events / sec"}],skipAnimation:!0,...m})})]})}const BL=gm({colorSchemes:{dark:!0}});gE.createRoot(document.getElementById("root")).render(N.jsx(mw,{injectFirst:!0,children:N.jsx(qO,{theme:BL,children:N.jsx(UL,{})})}));
232
+
Error code: ${l.error}`);if(f==="#commit"){const{seq:y,repo:v,commit:b,rev:x,since:S,blocks:A,ops:w,prevData:D,time:O}=l;if(!((d=A==null?void 0:A.$bytes)!=null&&d.length))return{$type:"com.atproto.sync.subscribeRepos#commit",seq:y,repo:v,commit:b.$link,rev:x,since:S,blocks:new Uint8Array,ops:[],...D?{prevData:D.$link}:{},time:O};const R=Rx(A),E=kL(R),k=[];for(const z of w){const H=z.action;if(H==="create"){if(!z.cid)continue;const L=E.get(z.cid.$link);if(!L)continue;k.push({action:H,path:z.path,cid:z.cid.$link,record:L})}else if(H==="update"){if(!z.cid)continue;const L=E.get(z.cid.$link);if(!L)continue;k.push({action:H,path:z.path,cid:z.cid.$link,...z.prev?{prev:z.prev.$link}:{},record:L})}else if(H==="delete")k.push({action:H,path:z.path,...z.prev?{prev:z.prev.$link}:{}});else throw new Error(`Unknown action: ${H}`)}return{$type:"com.atproto.sync.subscribeRepos#commit",seq:y,repo:v,commit:b.$link,rev:x,since:S,blocks:R,ops:k,...D?{prevData:D.$link}:{},time:O}}else if(f==="#sync"){const{seq:y,did:v,blocks:b,rev:x,time:S}=l,A=(m=b==null?void 0:b.$bytes)!=null&&m.length?Rx(b):new Uint8Array;return{$type:"com.atproto.sync.subscribeRepos#sync",seq:y,did:v,blocks:A,rev:x,time:S}}return{$type:`com.atproto.sync.subscribeRepos${f}`,...l}}preventReconnect(){this.reconnectTimeout&&clearTimeout(this.reconnectTimeout),this.reconnectTimeout=setTimeout(()=>{this.reconnect()},5e3)}reconnect(){var e;(e=this.ws)==null||e.close(),this.start(),this.emitter.emit("reconnect")}}function RL(t){if(!t||typeof t!="object"||!t.t||typeof t.t!="string"||!t.op||typeof t.op!="number")throw new Error("Invalid header received");return{t:t.t,op:t.op}}function kL(t){const e=new Map;for(const{cid:r,bytes:a}of wL(t).iterate())e.set(cL(r).$link,YT(a));return e}const DL="234567abcdefghijklmnopqrstuvwxyz",_x=t=>{let e=0;for(const r of t)e=e*32+DL.indexOf(r);return e},_L=/^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$/,zL=t=>{if(!$L(t))throw new Error("invalid TID");const e=_x(t.slice(0,11)),r=_x(t.slice(11,13));return{timestamp:e,clockid:r}},$L=t=>t.length===13&&_L.test(t),NL="app.bsky.feed.like",Ys=32,Gi=32,ec=Ys*Gi;function LL({url:t,desc:e,includeEvents:r,onRecieveEvent:a}){const[s,l]=U.useState("connecting"),[c,f]=U.useState(0),[p,d]=U.useState(0),[m,y]=U.useState({idx:Array.from({length:Gi+2}).map(()=>0),recv:Array.from({length:Gi+2}).map(()=>0)});return U.useEffect(()=>{const v=(x,S)=>{if(r.has(x)&&(a(x,S),f(A=>A+1),x==="commit"&&S.ops.length===1)){const A=S.ops[0];try{const[w,D]=A.path.split("/");if(w===NL){const O=zL(D).timestamp/1e3,R=Date.parse(S.time),E=R-O,k=+new Date-R;let z,H;E<0?z=-1:E>=ec?z=Gi:z=Math.min(Math.floor(E/Ys),ec),k<0?H=-1:k>=ec?H=Gi:H=Math.min(Math.floor(k/Ys),ec),y(({idx:L,recv:C})=>(L=L.slice(),C=C.slice(),L[z+1]+=1,C[H+1]+=1,{idx:L,recv:C}))}}catch{}}},b=new OL({relay:t});return b.on("open",()=>l("connected")),b.on("close",()=>l("closed")),b.on("reconnect",()=>d(x=>x+1)),b.on("error",x=>{console.error("oops",x),l("errored")}),b.on("websocketError",()=>l("errored")),b.on("commit",x=>v("commit",x)),b.on("sync",x=>v("sync",x)),b.on("account",x=>v("account",x)),b.on("identity",x=>v("identity",x)),b.on("info",(...x)=>console.info("info event",...x)),b.on("unknown",x=>console.warn(`unknown event from ${t}`,x)),b.start(),()=>{b.close()}},[t,r]),N.jsxs("div",{className:"relay",children:[N.jsx("h2",{children:e}),N.jsx("p",{children:N.jsx("code",{children:t})}),N.jsxs("p",{children:["[",N.jsx("code",{children:s}),"] (",N.jsx("code",{children:c.toLocaleString()})," events)"]}),p>0&&N.jsxs("p",{children:["reconnects: ",N.jsx("code",{children:p})]}),N.jsx(Vp,{height:180,width:420,yAxis:[{label:"events",scaleType:"symlog"}],skipAnimation:!0,xAxis:[{data:[-1].concat(Array.from({length:Gi}).map((v,b)=>b*Ys)).concat(["+"]),label:"index latency (ms)"}],series:[{data:m.idx}]}),N.jsx(Vp,{height:180,width:420,yAxis:[{label:"events",scaleType:"symlog"}],skipAnimation:!0,xAxis:[{data:[-1].concat(Array.from({length:Gi}).map((v,b)=>b*Ys)).concat(["+"]),label:"receive latency (ms)"}],series:[{data:m.recv}]})]})}const zx=[{url:"wss://atproto.africa",desc:"Blacksky"},{url:"wss://bsky.network",desc:"Bluesky primary (+Rainbow)"},{url:"wss://relay1.us-east.bsky.network",desc:"Bluesky sync1.1 east (+Rainbow)"},{url:"wss://relay1.us-west.bsky.network",desc:"Bluesky sync1.1 west (+Rainbow)"},{url:"wss://relay.fire.hose.cam",desc:"microcosm Montreal"},{url:"wss://relay3.fr.hose.cam",desc:"microcosm France"},{url:"wss://relay.upcloud.world",desc:"UpCloud relay"},{url:"wss://relay.hayescmd.net",desc:"@edavis.dev's relay"},{url:"wss://relay.xero.systems",desc:"@dane.is.extraordinarily.cool's relay"}],$x=1600,jL=6,Nx=10*60*1e3,Lx=(t,e,r)=>{};function UL(){const[t,e]=U.useState([]),[r,a]=U.useState(["commit","sync","account","identity","unknown"]),[s,l]=U.useState(new Set(r)),[c,f]=U.useState(()=>Lx),[p,d]=U.useState(()=>()=>{}),[m,y]=U.useState({series:[]}),[v,b]=U.useState(!1),[x,S]=U.useState("");U.useEffect(()=>{let D=performance.now(),O={},R=[],E=requestAnimationFrame(L),k=setTimeout(z,Nx);f(()=>(C,_,I)=>{O[C]||(O[C]=0),O[C]+=1}),d(()=>()=>{clearTimeout(k),k=setTimeout(z,Nx),b(!1),console.info("keepalive: disconnection timer reset")});function z(){console.info("disconnecting due to inactivity"),e([]),b(!0)}const H=setInterval(()=>{let C=performance.now(),_=C-D;R.length>=jL-1&&R.shift(),R.push({t:C,dt:_,counts:O}),D=C,O={}},$x);function L(){var I;let C=performance.now();const _=Object.keys(((I=R.at(-1))==null?void 0:I.counts)||{}).toSorted();y({xAxis:[{data:R.map(({t:q})=>(-(C-q)/1e3).toFixed(1)).concat(["now"]),label:"bucket (seconds ago)"}],series:_.map(q=>({label:q,data:R.map(({dt:it,counts:lt})=>lt[q]?(lt[q]/(it/1e3)).toFixed(1):null).concat([O[q]?(O[q]/($x/1e3)).toFixed(1):null])}))}),E=requestAnimationFrame(L)}return()=>{f(()=>Lx),d(()=>()=>null),clearInterval(H),cancelAnimationFrame(E)}},[]);function A(D,O){b(!1),e(O?R=>R.includes(D)?R:[...R,D]:R=>R.includes(D)?R.filter(E=>E!==D):R),p()}function w(){if(!x)return"";try{let D;return x.includes("://")?D=new URL(x):D=new URL("https://"+x),D.protocol==="https:"?D.protocol="wss:":D.protocol==="http:"&&(D.protocol="ws:"),D.origin}catch{return""}}return N.jsxs(N.Fragment,{children:[N.jsx("h1",{children:"compare hoses"}),N.jsx("p",{children:N.jsxs("em",{children:["warning: enabling many relay connections requires a ",N.jsx("strong",{children:"lot"})," of bandwidth"]})}),N.jsxs("form",{style:{display:"block",textAlign:"left"},children:[zx.map(({url:D,desc:O})=>N.jsx("p",{style:{margin:0},children:N.jsxs("label",{children:[N.jsx("input",{type:"checkbox",onChange:R=>A(D,R.target.checked),checked:t.includes(D)}),` ${O} `,"(",N.jsx("code",{children:D.slice(6)}),")"]})},D)),N.jsx("p",{style:{margin:0},children:N.jsxs("label",{children:[N.jsx("input",{type:"checkbox",onChange:D=>{const O=w();O&&A(O,D.target.checked)},checked:t.includes(w())})," ",N.jsx("input",{type:"text",placeholder:"wss://…",value:x,onChange:D=>{const O=w();e(R=>R.includes(O)?R.filter(E=>E!==O):R),S(D.target.value)},onKeyDown:D=>{if(D.key!=="Enter")return;D.preventDefault();const O=w();O&&A(O,!0)}})," ",x&&N.jsx("code",{children:w()})]})})]}),N.jsxs("form",{style:{display:"block",margin:"1rem 0"},children:[N.jsx("span",{children:"events: "}),r.map(D=>N.jsxs("label",{children:[N.jsx("input",{type:"checkbox",checked:s.has(D),onChange:O=>{l(R=>{const E=new Set(R);return O.target.checked?E.add(D):E.delete(D),E})}})," ",D]},D))]}),N.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:"2em",textAlign:"left"},children:t.map(D=>{const{desc:O}=zx.find(R=>R.url===D)??{desc:"custom relay"};return N.jsx("div",{children:N.jsx(LL,{url:D,desc:O,includeEvents:s,onRecieveEvent:(R,E)=>c(D,R,E)})},D)})}),v&&N.jsx("p",{children:N.jsx("em",{children:"disconnected to save bandwidth due to inactivity"})}),N.jsx("div",{className:"throughputs",children:N.jsx(Vp,{height:300,yAxis:[{label:"events / sec"}],skipAnimation:!0,...m})})]})}const BL=gm({colorSchemes:{dark:!0}});gE.createRoot(document.getElementById("root")).render(N.jsx(mw,{injectFirst:!0,children:N.jsx(qO,{theme:BL,children:N.jsx(UL,{})})}));
+1
-1
docs/index.html
+1
-1
docs/index.html
···
4
4
<meta charset="UTF-8" />
5
5
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
<title>compare hoses</title>
7
-
<script type="module" crossorigin src="/assets/index-KS4_m-xo.js"></script>
7
+
<script type="module" crossorigin src="/assets/index-TkW73U8w.js"></script>
8
8
<link rel="stylesheet" crossorigin href="/assets/index-Br90oyGg.css">
9
9
</head>
10
10
<body>