Skip to content
This repository was archived by the owner on May 23, 2025. It is now read-only.

Commit 3bcd352

Browse files
committed
chore: add pubsub debug
1 parent fc8f6ef commit 3bcd352

File tree

17 files changed

+479
-156
lines changed

17 files changed

+479
-156
lines changed

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,10 @@
1919
}
2020
},
2121
"dependencies": {
22-
"@libp2p/devtools-metrics": "^1.0.1",
22+
"@libp2p/interface": "^2.1.2",
23+
"@libp2p/devtools-metrics": "*",
2324
"@multiformats/multiaddr": "^12.2.3",
2425
"@multiformats/multiaddr-matcher": "^1.2.1",
25-
"it-drain": "^3.0.7",
26-
"it-foreach": "^2.1.1",
2726
"it-pipe": "^3.0.1",
2827
"it-pushable": "^3.2.3",
2928
"it-rpc": "^1.0.0",

src/app.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
--action-border-color: #047DB7;
2121

2222
--success-text-colour: #6DD58C;
23+
--dark-success-color: #2c5639;
2324
}
2425

2526
.light {
@@ -29,7 +30,7 @@
2930
--dark-text-color: #8F8F8F;
3031

3132
--warning-text-color: #8a0000;
32-
--dark-warning-text-color: #4a0000;
33+
--dark-warning-color: #4a0000;
3334
}
3435

3536
body {

src/app.tsx

Lines changed: 61 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
import './app.css'
22
import 'react'
3-
import { Component } from 'react'
4-
import { createRoot } from 'react-dom/client'
5-
import { getBrowserTheme } from './utils/get-theme.js'
6-
import { Inspector } from './panels/inspector.js'
7-
import { FloatingPanel } from './panels/floating-panel.js'
83
import { LIBP2P_DEVTOOLS_METRICS_KEY } from '@libp2p/devtools-metrics'
9-
import type { DevToolsEvents, MetricsRPC, Peer, RPCMessage } from '@libp2p/devtools-metrics'
10-
import { evalOnPage } from './utils/eval-on-page.js'
4+
import { valueCodecs } from '@libp2p/devtools-metrics/rpc'
5+
import { TypedEventEmitter } from '@libp2p/interface'
6+
import { pipe } from 'it-pipe'
7+
import { pushable } from 'it-pushable'
8+
import { rpc } from 'it-rpc'
9+
import { base64 } from 'multiformats/bases/base64'
10+
import { Component, type ReactElement } from 'react'
11+
import { createRoot } from 'react-dom/client'
1112
import SyntaxHighlighter from 'react-syntax-highlighter'
1213
import { dark } from 'react-syntax-highlighter/dist/esm/styles/hljs'
13-
import { sendMessage, events } from './utils/send-message.js'
14-
import { defer, type DeferredPromise } from './utils/defer.js'
15-
import { getPlatform } from './utils/get-platform.js'
14+
import { DetectingPanel } from './panels/detecting.js'
15+
import { FloatingPanel } from './panels/floating-panel.js'
1616
import { GrantPermissions } from './panels/grant-permissions.js'
17-
import { pushable, type Pushable } from 'it-pushable'
18-
import { rpc, type RPC } from 'it-rpc'
19-
import { valueCodecs } from '@libp2p/devtools-metrics/rpc'
20-
import { base64 } from 'multiformats/bases/base64'
21-
import { pipe } from 'it-pipe'
22-
import { TypedEventEmitter } from '@libp2p/interface'
23-
import { DetectingPanel } from './panels/detecting'
24-
import type { TypedEventTarget } from '@libp2p/interface'
17+
import { Inspector } from './panels/inspector.js'
18+
import { defer } from './utils/defer.js'
19+
import { evalOnPage } from './utils/eval-on-page.js'
20+
import { getPlatform } from './utils/get-platform.js'
21+
import { getBrowserTheme } from './utils/get-theme.js'
22+
import { sendMessage, events } from './utils/send-message.js'
23+
import type { DeferredPromise } from './utils/defer.js'
24+
import type { DevToolsEvents, MetricsRPC, Peer, RPCMessage } from '@libp2p/devtools-metrics'
25+
import type { TypedEventTarget, Message } from '@libp2p/interface'
26+
import type { Pushable } from 'it-pushable'
27+
import type { RPC } from 'it-rpc'
2528

2629
const theme = getBrowserTheme()
2730
const platform = getPlatform()
2831

29-
console.info('theme is', theme, 'browser is', platform)
30-
31-
3232
interface OfflineAppState {
3333
status: 'init' | 'missing' | 'permissions'
3434
}
@@ -43,11 +43,13 @@ interface OnlineAppState {
4343
self: Peer
4444
peers: Peer[]
4545
debug: string
46+
capabilities: Record<string, string[]>
47+
pubsub: Record<string, Message[]>
4648
}
4749

4850
type AppState = OfflineAppState | ErrorAppState | OnlineAppState
4951

50-
const ErrorPanel = ({ error }: { error: Error }) => {
52+
const ErrorPanel = ({ error }: { error: Error }): ReactElement => {
5153
return (
5254
<>
5355
<FloatingPanel>
@@ -61,7 +63,7 @@ const ErrorPanel = ({ error }: { error: Error }) => {
6163
)
6264
}
6365

64-
const MissingPanel = () => {
66+
const MissingPanel = (): ReactElement => {
6567
return (
6668
<>
6769
<FloatingPanel>
@@ -82,17 +84,19 @@ const node = await createLibp2p({
8284
)
8385
}
8486

85-
const GrantPermissionsPanel = () => {
87+
const GrantPermissionsPanel = (): ReactElement => {
8688
return (
8789
<>
8890
<FloatingPanel>
8991
<h2>Permissions</h2>
9092
<p>No data has been received from the libp2p node running on the page.</p>
9193
<p>You may need to grant this extension access to the current page.</p>
9294
{
93-
platform === 'unknown' ? (
94-
<p>Please see your browser documentation for how to do this.</p>
95-
) : <GrantPermissions />
95+
platform === 'unknown'
96+
? (
97+
<p>Please see your browser documentation for how to do this.</p>
98+
)
99+
: <GrantPermissions />
96100
}
97101
</FloatingPanel>
98102
</>
@@ -141,11 +145,24 @@ class App extends Component {
141145
}))
142146
})
143147

148+
this.events.addEventListener('pubsub:message', (evt) => {
149+
this.setState(s => ({
150+
...s,
151+
pubsub: {
152+
...(s.pubsub ?? {}),
153+
[evt.detail.topic ?? '']: [
154+
...(s.pubsub[evt.detail.topic] ?? []),
155+
evt.detail
156+
]
157+
}
158+
}))
159+
})
160+
144161
this.rpc.createTarget('devTools', this.events)
145162

146163
// send RPC messages
147164
Promise.resolve()
148-
.then(async () => {
165+
.then(async () => {
149166
await pipe(
150167
this.rpcQueue,
151168
this.rpc,
@@ -158,10 +175,10 @@ class App extends Component {
158175
}
159176
}
160177
)
161-
})
162-
.catch(err => {
163-
console.error('error while reading RPC messages', err)
164-
})
178+
})
179+
.catch(err => {
180+
console.error('error while reading RPC messages', err)
181+
})
165182

166183
// receive RPC messages
167184
events.addEventListener('libp2p-rpc', (event) => {
@@ -183,7 +200,7 @@ class App extends Component {
183200
this.init()
184201
}
185202

186-
init () {
203+
init (): void {
187204
Promise.resolve().then(async () => {
188205
const metricsPresent = await evalOnPage<boolean>(`${LIBP2P_DEVTOOLS_METRICS_KEY} === true`)
189206

@@ -197,15 +214,17 @@ class App extends Component {
197214
const signal = AbortSignal.timeout(2000)
198215

199216
try {
200-
const { self, peers, debug } = await this.metrics.init({
217+
const { self, peers, debug, capabilities } = await this.metrics.init({
201218
signal
202219
})
203220

204221
this.setState({
205222
status: 'online',
206223
self,
207224
peers,
208-
debug
225+
debug,
226+
capabilities,
227+
pubsub: {}
209228
})
210229
} catch (err: any) {
211230
if (signal.aborted) {
@@ -221,17 +240,17 @@ class App extends Component {
221240
})
222241
}
223242
})
224-
.catch(err => {
225-
console.error('error communicating with page', err)
243+
.catch(err => {
244+
console.error('error communicating with page', err)
226245

227-
this.setState({
228-
status: 'error',
229-
error: err
246+
this.setState({
247+
status: 'error',
248+
error: err
249+
})
230250
})
231-
})
232251
}
233252

234-
render() {
253+
render (): ReactElement {
235254
if (this.state.status === 'init') {
236255
return (
237256
<DetectingPanel />

src/panels/debug.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
1-
import 'react'
2-
import { useState } from 'react'
3-
import { Panel } from './panel.js'
1+
import { useState, type ReactElement } from 'react'
42
import { Button } from './button.js'
3+
import { Panel } from './panel.js'
4+
import { SmallError, SmallSuccess } from './status.js'
55
import { TextInput } from './text-input.js'
66
import type { MetricsRPC } from '@libp2p/devtools-metrics'
7-
import { SmallError, SmallSuccess } from './status.js'
87

98
export interface DebugProps {
109
metrics: MetricsRPC
1110
debug: string
1211
}
1312

14-
export function Debug ({ metrics, debug }: DebugProps) {
13+
export function Debug ({ metrics, debug }: DebugProps): ReactElement {
1514
const [namespace, setNamespace] = useState(debug)
1615
const [result, setResult] = useState(<small>E.g. `libp2p:*`, `libp2p:kad-dht*,*:trace`, etc</small>)
1716

18-
function sendDebug (evt: { preventDefault: () => void }, namespace: string): boolean {
17+
function sendDebug (evt: { preventDefault(): void }, namespace: string): boolean {
1918
evt.preventDefault()
2019

2120
metrics.setDebug(namespace)
@@ -35,7 +34,7 @@ export function Debug ({ metrics, debug }: DebugProps) {
3534
<h2>Debug</h2>
3635
<p>Enter the name of one or more libp2p components to enable logging in the console tab or disable it completely</p>
3736
<form onSubmit={(evt) => sendDebug(evt, namespace)}>
38-
<TextInput type="text" value={namespace} placeholder="libp2p:*" onChange={(e) => setNamespace(e.target.value)} />
37+
<TextInput type="text" value={namespace} placeholder="libp2p:*" onChange={(e) => { setNamespace(e.target.value) }} />
3938
<Button onClick={(evt) => sendDebug(evt, namespace)} primary={true}>Go</Button>
4039
<Button onClick={(evt) => sendDebug(evt, '')} danger={true}>Disable</Button>
4140
</form>

src/panels/inspector.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,54 @@
1-
import 'react'
21
import { useState } from 'react'
2+
import libp2pLogo from '../../public/img/libp2p.svg'
3+
import { Debug } from './debug.js'
34
import { Menu } from './menu.js'
5+
import { Node } from './node.js'
46
import { Peers } from './peers/index.js'
7+
import { PubSub } from './pubsub/index.js'
58
import { Routing } from './routing/index.js'
6-
import { Node } from './node.js'
7-
import { Debug } from './debug.js'
89
import type { MetricsRPC, Peer } from '@libp2p/devtools-metrics'
9-
import libp2pLogo from '../../public/img/libp2p.svg'
10+
import type { Message } from '@libp2p/interface'
11+
import type { ReactElement } from 'react'
1012

1113
export interface InspectorProps {
1214
self: Peer
1315
peers: Peer[]
1416
debug: string
1517
metrics: MetricsRPC
18+
capabilities: Record<string, string[]>
19+
pubsub: Record<string, Message[]>
1620
}
1721

18-
export function Inspector ({ self, peers, debug, metrics }: InspectorProps) {
19-
const [panel, setPanel] = useState('Node')
22+
export function Inspector ({ self, peers, debug, metrics, capabilities, pubsub }: InspectorProps): ReactElement {
23+
const panels = ['Node', 'Peers', 'Debug', 'Routing']
24+
const [panel, setPanel] = useState(panels[0])
2025

2126
const logo = (
2227
<img src={libp2pLogo} height={24} width={24} className={'Icon'} />
2328
)
2429

30+
const pubSubComponent = findPubSubComponent(capabilities)
31+
32+
if (pubSubComponent != null) {
33+
panels.push('PubSub')
34+
}
35+
2536
return (
2637
<>
27-
<Menu logo={logo} onClick={(panel) => setPanel(panel)} panel={panel} options={['Node', 'Peers', 'Debug', 'Routing']} />
38+
<Menu logo={logo} onClick={(panel) => { setPanel(panel) }} panel={panel} options={panels} />
2839
{ panel === 'Node' ? <Node self={self} /> : undefined }
2940
{ panel === 'Peers' ? <Peers peers={peers} metrics={metrics} /> : undefined }
3041
{ panel === 'Debug' ? <Debug metrics={metrics} debug={debug} /> : undefined }
3142
{ panel === 'Routing' ? <Routing metrics={metrics} /> : undefined }
43+
{ panel === 'PubSub' ? <PubSub component={pubSubComponent ?? ''} metrics={metrics} pubsub={pubsub} /> : undefined}
3244
</>
3345
)
3446
}
47+
48+
function findPubSubComponent (capabilities: Record<string, string[]>): string | undefined {
49+
for (const component of Object.keys(capabilities)) {
50+
if (capabilities[component].includes('@libp2p/pubsub')) {
51+
return component
52+
}
53+
}
54+
}

src/panels/menu.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
import 'react'
22
import './menu.css'
3+
import type { ReactElement } from 'react'
34

45
export interface MenuProps {
5-
onClick: (arg: string) => void
6+
onClick(arg: string): void
67
panel: string
78
options: string[]
89
logo?: JSX.Element
910
}
1011

11-
export function Menu ({ onClick, panel, options, logo }: MenuProps) {
12+
export function Menu ({ onClick, panel, options, logo }: MenuProps): ReactElement {
1213
return (
1314
<div className='Menu'>
1415
{logo}
1516
{
1617
options.map(option => (
17-
<button key={option} onClick={() => onClick(option)} className={panel === option ? 'selected' : ''}>{option}</button>
18+
<button key={option} onClick={() => { onClick(option) }} className={panel === option ? 'selected' : ''}>{option}</button>
1819
))
1920
}
2021
</div>

0 commit comments

Comments
 (0)