main
tsx 142 lines 3.57 KB
Raw
1 import { bases } from 'multiformats/basics'
2 import { Component } from 'react'
3 import { Button } from '../button.js'
4 import { Panel } from '../panel.js'
5 import { SmallError, SmallSuccess } from '../status.js'
6 import { TextInput } from '../text-input.js'
7 import type { MetricsRPC } from '@ipshipyard/libp2p-inspector-metrics'
8 import type { FormEvent, JSX } from 'react'
9
10 // @ts-expect-error - Not easy to combine these types.
11 const multibaseDecoder = Object.values(bases).map(b => b.decoder).reduce((d, b) => d.or(b))
12
13 export interface FindProvidersProps {
14 metrics: MetricsRPC
15 }
16
17 export interface FindProvidersState {
18 target: string
19 error: string
20 details: JSX.Element[]
21 }
22
23 export class FindProviders extends Component<FindProvidersProps, FindProvidersState> {
24 constructor (props: FindProvidersProps) {
25 super(props)
26
27 this.state = {
28 target: '',
29 error: '',
30 details: []
31 }
32 }
33
34 componentDidMount (): void {
35 this.setState({
36 target: '',
37 error: '',
38 details: []
39 })
40 }
41
42 private findProviders (evt: FormEvent | Event, target: string): boolean {
43 evt.preventDefault()
44
45 this.setState({
46 error: '',
47 details: []
48 })
49
50 target = target?.trim()
51
52 if (target == null || target === '') {
53 this.setState({
54 error: 'Please enter a key'
55 })
56
57 return false
58 }
59
60 let key: Uint8Array
61
62 try {
63 key = multibaseDecoder.decode(target)
64 } catch {
65 this.setState({
66 error: 'Key invalid'
67 })
68
69 return false
70 }
71
72 this.props.metrics.contentRouting.get(key, {
73 onProgress: (event) => {
74 let message: string = event.type
75
76 if (event.type === 'dial:already-connected') {
77 message = 'Already connected to this peer'
78 } else if (event.type === 'dial:add-to-dial-queue') {
79 message = 'Adding dial to queue'
80 } else if (event.type === 'dial:already-in-dial-queue') {
81 message = 'Dial to this peer already in queue'
82 } else if (event.type === 'dial:calculate-addresses') {
83 message = 'Calculating addresses'
84 } else if (event.type === 'dial:selected-transport') {
85 message = `Selected transport ${event.detail}`
86 }
87
88 this.setState(s => {
89 return {
90 details: [
91 ...s.details,
92 <p key={`event-${s.details.length}`}>{message}</p>
93 ]
94 }
95 })
96 }
97 })
98 .then(() => {
99 this.setState(s => {
100 return {
101 error: '',
102 details: [
103 ...s.details,
104 <SmallSuccess key={`event-${s.details.length}`} message='Get successful' />
105 ]
106 }
107 })
108 })
109 .catch(err => {
110 this.setState(s => {
111 return {
112 details: [
113 ...s.details,
114 <SmallError key={`event-${s.details.length}`} error={err} />
115 ]
116 }
117 })
118 })
119
120 return false
121 }
122
123 render (): JSX.Element {
124 return (
125 <Panel>
126 <p>Enter a CID to find providers of:</p>
127 <form onSubmit={(evt) => this.findProviders(evt, this.state.target)}>
128 <TextInput
129 type='text' value={this.state.target} placeholder='bafyfoo...' onChange={(e) => {
130 this.setState({
131 target: e.target.value
132 })
133 }}
134 />
135 <Button onClick={(evt) => this.findProviders(evt, this.state.target)} primary>Get</Button>
136 </form>
137 {this.state.error ? <SmallError error={this.state.error} /> : undefined}
138 {this.state.details}
139 </Panel>
140 )
141 }
142 }