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

fix types

at least one bug probably

Changed files
+46 -23
src
+33 -17
src/App.tsx
··· 3 3 import './App.css' 4 4 import '@mui/x-charts-vendor/d3-scale' 5 5 import Relay from './Relay' 6 - import knownRelays from './knownRelays' 6 + import knownRelays from './knownRelays.json' 7 7 8 8 const INTERVAL = 1600; 9 9 const SERIES_LEN = 6; 10 10 const KEEPALIVE = 10 * 60 * 1000; 11 11 12 + interface Relay { 13 + url: string, 14 + desc: string, 15 + }; 16 + 17 + interface Counts { 18 + [k: string]: number, 19 + }; 20 + 21 + interface CountBatch { 22 + t: number, 23 + dt: number, 24 + counts: Counts, 25 + }; 26 + 27 + const noopReceiver = (_url: string, _type: string, _event: any) => {}; 28 + 12 29 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: [] }); 30 + const [relays, setRelays] = useState([] as string[]); 31 + const [receiver, setReceiver] = useState(() => noopReceiver); 32 + const [keepalive, setKeepalive] = useState(() => () => {}); 33 + const [rateBars, setRateBars] = useState({ series: [] } as any); 17 34 const [died, setDied] = useState(false); 18 35 19 36 useEffect(() => { 20 37 let lastChangeover = performance.now(); 21 - let currentCounts = {}; 22 - let series = []; 38 + let currentCounts: Counts = {}; 39 + let series: CountBatch[] = []; 23 40 let raf = requestAnimationFrame(update); 24 41 let ttl = setTimeout(die, KEEPALIVE); 25 42 26 - setReceiver(() => (url, type, event) => { 43 + setReceiver(() => (url: string, _type: string, _event: any) => { 27 44 if (!currentCounts[url]) currentCounts[url] = 0; 28 45 currentCounts[url] += 1; 29 46 }); ··· 56 73 57 74 function update() { 58 75 let now = performance.now(); 59 - let dt = (now - lastChangeover) / 1000; 60 76 const relays = Object.keys(series.at(-1)?.counts || {}).toSorted(); 61 77 62 78 setRateBars({ ··· 66 82 .concat(['now']), 67 83 label: 'bucket (seconds ago)', 68 84 }], 69 - series: relays.map(r => ({ 85 + series: relays.map((r: string) => ({ 70 86 label: r, 71 87 data: series 72 88 .map(({ dt, counts }) => { ··· 84 100 }; 85 101 86 102 return () => { 87 - setReceiver(() => () => null); 103 + setReceiver(() => noopReceiver); 88 104 setKeepalive(() => () => null); 89 105 clearInterval(nextBlock); 90 106 cancelAnimationFrame(raf); ··· 92 108 }, []); 93 109 94 110 95 - function showRelay(url, show) { 111 + function showRelay(url: string, show: boolean) { 96 112 setDied(false); 97 113 if (show) { 98 - setRelays(rs => rs.includes(url) ? rs : [...rs, url]); 114 + setRelays((rs: string[]) => rs.includes(url) ? rs : [...rs, url]); 99 115 } else { 100 - setRelays(rs => rs.includes(url) ? rs.filter(u => u !== url) : rs); 116 + setRelays((rs: string[]) => rs.includes(url) ? rs.filter(u => u !== url) : rs); 101 117 } 102 118 keepalive(); 103 119 } ··· 108 124 <p><em>warning: enabling many relay connections requires a lot of bandwidth</em></p> 109 125 110 126 <form style={{ display: 'block', textAlign: 'left' }}> 111 - {knownRelays.map(({ url, desc }) => ( 127 + {knownRelays.map(({ url, desc }: Relay) => ( 112 128 <p key={url} style={{margin: 0}}> 113 129 <label> 114 130 <input ··· 125 141 126 142 <div style={{ display: 'flex', flexWrap: 'wrap', gap: '2em', textAlign: 'left' }}> 127 143 {relays.map(url => { 128 - const { desc } = knownRelays.find(e => e.url === url); 144 + const { desc } = knownRelays.find((r: Relay) => r.url === url)!; 129 145 return ( 130 146 <div key={url}> 131 147 <Relay 132 148 url={url} 133 149 desc={desc} 134 - onRecieveEvent={(type, event) => receiver(url, type, event)} 150 + onRecieveEvent={(type: string, event: any) => receiver(url, type, event)} 135 151 /> 136 152 </div> 137 153 );
+12 -5
src/Relay.tsx
··· 2 2 import { Firehose } from '@skyware/firehose'; 3 3 import './Relay.css'; 4 4 5 - type firehoseState = 'connecting' | 'connected' | 'errored' | 'closed'; 5 + type HoseState = 'connecting' | 'connected' | 'errored' | 'closed'; 6 6 7 - function Relay({ url, desc, onRecieveEvent }) { 8 - const [state, setState] = useState('connecting'); 7 + function Relay({ url, desc, onRecieveEvent }: { 8 + url: string, 9 + desc: string, 10 + onRecieveEvent: (type: string, event: any) => void, 11 + }) { 12 + const [state, setState] = useState('connecting' as HoseState); 9 13 const [commits, setCommits] = useState(0); 10 14 const [reconnects, setReconnects] = useState(0); 11 15 12 16 useEffect(() => { 13 - const sendIt = (type, event) => { 17 + const sendIt = (type: string, event: any) => { 14 18 onRecieveEvent(type, event); 15 19 setCommits(n => n + 1); 16 20 }; ··· 18 22 firehose.on('open', () => setState('connected')); 19 23 firehose.on('close', () => setState('closed')); 20 24 firehose.on('reconnect', () => setReconnects(n => n + 1)); 21 - firehose.on('error', e => console.error('oops', e) || setState('errored')); 25 + firehose.on('error', e => { 26 + console.error('oops', e); 27 + setState('errored'); 28 + }); 22 29 firehose.on('websocketError', () => setState('errored')); 23 30 firehose.on('commit', (ev) => sendIt('commit', ev)); 24 31 firehose.on('sync', (ev) => sendIt('sync', ev));
+1 -1
tsconfig.app.json
··· 3 3 "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 4 4 "target": "ES2020", 5 5 "useDefineForClassFields": true, 6 - "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 + "lib": ["ES2023", "DOM", "DOM.Iterable"], 7 7 "module": "ESNext", 8 8 "skipLibCheck": true, 9 9