Relay firehose browser tools: https://compare.hose.cam

disconnect timer

10 mins

Changed files
+39 -8
src
+1 -2
index.html
··· 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 - <link rel="icon" type="image/svg+xml" href="/vite.svg" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 7 - <title>Vite + React + TS</title> 8 </head> 9 <body> 10 <div id="root"></div>
··· 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6 + <title>compare hoses</title> 7 </head> 8 <body> 9 <div id="root"></div>
+38 -6
src/App.tsx
··· 7 8 const INTERVAL = 1600; 9 const SERIES_LEN = 6; 10 11 function App() { 12 const [relays, setRelays] = useState([]); 13 const [receiver, setReceiver] = useState(() => () => null); 14 const [rateBars, setRateBars] = useState({ series: [] }); 15 16 useEffect(() => { 17 let lastChangeover = performance.now(); 18 let currentCounts = {}; 19 let series = []; 20 21 setReceiver(() => (url, type, event) => { 22 if (!currentCounts[url]) currentCounts[url] = 0; 23 currentCounts[url] += 1; 24 }); 25 26 const nextBlock = setInterval(() => { 27 let now = performance.now(); 28 let dt = now - lastChangeover; ··· 36 currentCounts = {}; 37 }, INTERVAL); 38 39 - const update = () => { 40 let now = performance.now(); 41 let dt = (now - lastChangeover) / 1000; 42 const relays = Object.keys(series.at(-1)?.counts || {}).toSorted(); ··· 64 65 raf = requestAnimationFrame(update); 66 }; 67 - let raf = requestAnimationFrame(update); 68 69 return () => { 70 setReceiver(() => () => null); 71 clearInterval(nextBlock); 72 cancelAnimationFrame(raf); 73 }; 74 }, []); 75 76 return ( 77 <> 78 <h1>compare hoses</h1> ··· 84 <label> 85 <input 86 type="checkbox" 87 - onInput={e => e.target.checked 88 - ? relays.includes(url) || setRelays([...relays, url]) 89 - : setRelays(relays.filter(u => u !== url)) 90 - } 91 /> 92 { ` ${desc} ` } 93 (<code>{ url.slice('wss://'.length) }</code>) ··· 110 ); 111 })} 112 </div> 113 <div className="throughputs"> 114 <BarChart 115 height={300}
··· 7 8 const INTERVAL = 1600; 9 const SERIES_LEN = 6; 10 + const KEEPALIVE = 10 * 60 * 1000; 11 12 function App() { 13 const [relays, setRelays] = useState([]); 14 const [receiver, setReceiver] = useState(() => () => null); 15 + const [keepalive, setKeepalive] = useState(() => () => null); 16 const [rateBars, setRateBars] = useState({ series: [] }); 17 + const [died, setDied] = useState(false); 18 19 useEffect(() => { 20 let lastChangeover = performance.now(); 21 let currentCounts = {}; 22 let series = []; 23 + let raf = requestAnimationFrame(update); 24 + let ttl = setTimeout(die, KEEPALIVE); 25 26 setReceiver(() => (url, type, event) => { 27 if (!currentCounts[url]) currentCounts[url] = 0; 28 currentCounts[url] += 1; 29 }); 30 31 + setKeepalive(() => () => { 32 + clearTimeout(ttl); 33 + ttl = setTimeout(die, KEEPALIVE); 34 + setDied(false); 35 + console.info('keepalive: disconnection timer reset'); 36 + }); 37 + 38 + function die() { 39 + console.info('disconnecting due to inactivity'); 40 + setRelays([]); 41 + setDied(true); 42 + } 43 + 44 const nextBlock = setInterval(() => { 45 let now = performance.now(); 46 let dt = now - lastChangeover; ··· 54 currentCounts = {}; 55 }, INTERVAL); 56 57 + function update() { 58 let now = performance.now(); 59 let dt = (now - lastChangeover) / 1000; 60 const relays = Object.keys(series.at(-1)?.counts || {}).toSorted(); ··· 82 83 raf = requestAnimationFrame(update); 84 }; 85 86 return () => { 87 setReceiver(() => () => null); 88 + setKeepalive(() => () => null); 89 clearInterval(nextBlock); 90 cancelAnimationFrame(raf); 91 }; 92 }, []); 93 94 + 95 + function showRelay(url, show) { 96 + setDied(false); 97 + if (show) { 98 + setRelays(rs => rs.includes(url) ? rs : [...rs, url]); 99 + } else { 100 + setRelays(rs => rs.includes(url) ? rs.filter(u => u !== url) : rs); 101 + } 102 + keepalive(); 103 + } 104 + 105 return ( 106 <> 107 <h1>compare hoses</h1> ··· 113 <label> 114 <input 115 type="checkbox" 116 + onChange={e => showRelay(url, e.target.checked)} 117 + checked={relays.includes(url)} 118 /> 119 { ` ${desc} ` } 120 (<code>{ url.slice('wss://'.length) }</code>) ··· 137 ); 138 })} 139 </div> 140 + 141 + {died && ( 142 + <p><em>disconnected to save bandwidth due to inactivity</em></p> 143 + )} 144 + 145 <div className="throughputs"> 146 <BarChart 147 height={300}