2929 * - is not supported as a URI e.g. circuit
3030 */
3131
32- import { multiaddr , protocols } from '@multiformats/multiaddr'
33- import type { Multiaddr , StringTuple } from '@multiformats/multiaddr'
32+ import { CODE_TCP , CODE_DNS , CODE_DNS4 , CODE_DNS6 , CODE_DNSADDR , multiaddr , CODE_TLS , CODE_IP6 } from '@multiformats/multiaddr'
33+ import type { Component , Multiaddr } from '@multiformats/multiaddr'
3434
3535export interface MultiaddrToUriOpts {
3636 assumeHttp ?: boolean
3737}
3838
3939const ASSUME_HTTP_CODES = [
40- protocols ( 'tcp' ) . code ,
41- protocols ( 'dns' ) . code ,
42- protocols ( 'dnsaddr' ) . code ,
43- protocols ( 'dns4' ) . code ,
44- protocols ( 'dns6' ) . code
40+ CODE_TCP ,
41+ CODE_DNS ,
42+ CODE_DNSADDR ,
43+ CODE_DNS4 ,
44+ CODE_DNS6
4545]
4646
47- interface Interpreter { ( value : string , ma : StringTuple [ ] ) : string }
47+ interface Interpreter {
48+ ( head : Component , rest : Component [ ] ) : string | undefined
49+ }
4850
49- function extractSNI ( ma : StringTuple [ ] ) : string | undefined {
50- return extractTuple ( 'sni' , ma ) ?. [ 1 ]
51+ function extractSNI ( ma : Component [ ] ) : string | undefined {
52+ return extractTuple ( 'sni' , ma ) ?. value
5153}
5254
53- function extractPort ( ma : StringTuple [ ] ) : string {
54- const port = extractTuple ( 'tcp' , ma ) ?. [ 1 ]
55+ function extractPort ( ma : Component [ ] ) : string {
56+ const port = extractTuple ( 'tcp' , ma ) ?. value
5557
5658 if ( port == null ) {
5759 return ''
@@ -60,184 +62,170 @@ function extractPort (ma: StringTuple[]): string {
6062 return `:${ port } `
6163}
6264
63- function extractTuple ( name : string , ma : StringTuple [ ] ) : StringTuple | undefined {
64- let code : number
65-
66- try {
67- code = protocols ( name ) . code
68- } catch ( e ) {
69- // No support for protocol in multiaddr
70- return
71- }
72-
73- for ( const [ proto , value ] of ma ) {
74- if ( proto === code && value != null ) {
75- return [ proto , value ]
76- }
77- }
65+ function extractTuple ( name : string , ma : Component [ ] ) : Component | undefined {
66+ return ma . find ( component => component . name === name )
7867}
7968
80- function hasTLS ( ma : StringTuple [ ] ) : boolean {
81- return ma . some ( ( [ proto , _ ] ) => proto === protocols ( 'tls' ) . code )
69+ function hasTLS ( ma : Component [ ] ) : boolean {
70+ return ma . some ( ( { code } ) => code === CODE_TLS )
8271}
8372
84- function interpretNext ( headProtoCode : number , headProtoVal : string , restMa : StringTuple [ ] ) : string {
85- const interpreter = interpreters [ protocols ( headProtoCode ) . name ]
73+ function interpretNext ( head : Component , rest : Component [ ] ) : string | undefined {
74+ const interpreter = interpreters [ head . name ]
8675 if ( interpreter == null ) {
87- throw new Error ( `Can't interpret protocol ${ protocols ( headProtoCode ) . name } ` )
76+ throw new Error ( `Can't interpret protocol ${ head . name } ` )
8877 }
89- const restVal = interpreter ( headProtoVal , restMa )
90- if ( headProtoCode === protocols ( 'ip6' ) . code ) {
78+ const restVal = interpreter ( head , rest )
79+ if ( head . code === CODE_IP6 ) {
9180 return `[${ restVal } ]`
9281 }
9382 return restVal
9483}
9584
9685const interpreters : Record < string , Interpreter > = {
97- ip4 : ( value : string , restMa : StringTuple [ ] ) => value ,
98- ip6 : ( value : string , restMa : StringTuple [ ] ) => {
99- if ( restMa . length === 0 ) {
100- return value
86+ ip4 : ( head , rest ) => head . value ,
87+ ip6 : ( head , rest ) => {
88+ if ( rest . length === 0 ) {
89+ return head . value
10190 }
102- return `[${ value } ]`
91+ return `[${ head . value } ]`
10392 } ,
104- tcp : ( value : string , restMa : StringTuple [ ] ) => {
105- const tailProto = restMa . pop ( )
106- if ( tailProto == null ) {
93+ tcp : ( head , rest ) => {
94+ const tail = rest . pop ( )
95+ if ( tail == null ) {
10796 throw new Error ( 'Unexpected end of multiaddr' )
10897 }
109- return `tcp://${ interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa ) } :${ value } `
98+ return `tcp://${ interpretNext ( tail , rest ) } :${ head . value } `
11099 } ,
111- udp : ( value : string , restMa : StringTuple [ ] ) => {
112- const tailProto = restMa . pop ( )
113- if ( tailProto == null ) {
100+ udp : ( head , rest ) => {
101+ const tail = rest . pop ( )
102+ if ( tail == null ) {
114103 throw new Error ( 'Unexpected end of multiaddr' )
115104 }
116- return `udp://${ interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa ) } :${ value } `
105+ return `udp://${ interpretNext ( tail , rest ) } :${ head . value } `
117106 } ,
118- dnsaddr : ( value : string , restMa : StringTuple [ ] ) => value ,
119- dns4 : ( value : string , restMa : StringTuple [ ] ) => value ,
120- dns6 : ( value : string , restMa : StringTuple [ ] ) => value ,
121- dns : ( value : string , restMa : StringTuple [ ] ) => value ,
122- ipfs : ( value : string , restMa : StringTuple [ ] ) => {
123- const tailProto = restMa . pop ( )
124- if ( tailProto == null ) {
107+ dnsaddr : ( head , rest ) => head . value ,
108+ dns4 : ( head , rest ) => head . value ,
109+ dns6 : ( head , rest ) => head . value ,
110+ dns : ( head , rest ) => head . value ,
111+ ipfs : ( head , rest ) => {
112+ const tail = rest . pop ( )
113+ if ( tail == null ) {
125114 throw new Error ( 'Unexpected end of multiaddr' )
126115 }
127- return `${ interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa ) } `
116+ return `${ interpretNext ( tail , rest ) } `
128117 } ,
129- p2p : ( value : string , restMa : StringTuple [ ] ) => {
130- const tailProto = restMa . pop ( )
131- if ( tailProto == null ) {
118+ p2p : ( head , rest ) => {
119+ const tail = rest . pop ( )
120+ if ( tail == null ) {
132121 throw new Error ( 'Unexpected end of multiaddr' )
133122 }
134- return `${ interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa ) } `
123+ return `${ interpretNext ( tail , rest ) } `
135124 } ,
136- http : ( value : string , restMa : StringTuple [ ] ) => {
137- const maHasTLS = hasTLS ( restMa )
138- const sni = extractSNI ( restMa )
139- const port = extractPort ( restMa )
125+ http : ( head , rest ) => {
126+ const maHasTLS = hasTLS ( rest )
127+ const sni = extractSNI ( rest )
128+ const port = extractPort ( rest )
140129 if ( maHasTLS && sni != null ) {
141130 return `https://${ sni } ${ port } `
142131 }
143132 const protocol = maHasTLS ? 'https://' : 'http://'
144- const tailProto = restMa . pop ( )
145- if ( tailProto == null ) {
133+ const tail = rest . pop ( )
134+ if ( tail == null ) {
146135 throw new Error ( 'Unexpected end of multiaddr' )
147136 }
148- let baseVal = interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa )
137+ let baseVal = interpretNext ( tail , rest )
149138 // We are reinterpreting the base as http, so we need to remove the tcp:// if it's there
150- baseVal = baseVal . replace ( 'tcp://' , '' )
139+ baseVal = baseVal ? .replace ( 'tcp://' , '' )
151140 return `${ protocol } ${ baseVal } `
152141 } ,
153- 'http-path' : ( value : string , restMa : StringTuple [ ] ) => {
154- const tailProto = restMa . pop ( )
155- if ( tailProto == null ) {
142+ 'http-path' : ( head , rest ) => {
143+ const tail = rest . pop ( )
144+ if ( tail == null ) {
156145 throw new Error ( 'Unexpected end of multiaddr' )
157146 }
158- const baseVal = interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa )
159- const decodedValue = decodeURIComponent ( value )
160- return `${ baseVal } / ${ decodedValue } `
147+ const baseVal = interpretNext ( tail , rest )
148+ const decodedValue = decodeURIComponent ( head . value ?? '' )
149+ return `${ baseVal } ${ decodedValue } `
161150 } ,
162- tls : ( value : string , restMa : StringTuple [ ] ) => {
151+ tls : ( head , rest ) => {
163152 // Noop, the parent context knows that it's tls. We don't need to do
164153 // anything here
165- const tailProto = restMa . pop ( )
166- if ( tailProto == null ) {
154+ const tail = rest . pop ( )
155+ if ( tail == null ) {
167156 throw new Error ( 'Unexpected end of multiaddr' )
168157 }
169- return interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa )
158+ return interpretNext ( tail , rest )
170159 } ,
171- sni : ( value : string , restMa : StringTuple [ ] ) => {
160+ sni : ( head , rest ) => {
172161 // Noop, the parent context uses the sni information, we don't need to do
173162 // anything here
174- const tailProto = restMa . pop ( )
175- if ( tailProto == null ) {
163+ const tail = rest . pop ( )
164+ if ( tail == null ) {
176165 throw new Error ( 'Unexpected end of multiaddr' )
177166 }
178- return interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa )
167+ return interpretNext ( tail , rest )
179168 } ,
180- https : ( value : string , restMa : StringTuple [ ] ) => {
181- const tailProto = restMa . pop ( )
182- if ( tailProto == null ) {
169+ https : ( head , rest ) => {
170+ const tail = rest . pop ( )
171+ if ( tail == null ) {
183172 throw new Error ( 'Unexpected end of multiaddr' )
184173 }
185- let baseVal = interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa )
174+ let baseVal = interpretNext ( tail , rest )
186175 // We are reinterpreting the base as http, so we need to remove the tcp:// if it's there
187- baseVal = baseVal . replace ( 'tcp://' , '' )
176+ baseVal = baseVal ? .replace ( 'tcp://' , '' )
188177 return `https://${ baseVal } `
189178 } ,
190- ws : ( value : string , restMa : StringTuple [ ] ) => {
191- const maHasTLS = hasTLS ( restMa )
192- const sni = extractSNI ( restMa )
193- const port = extractPort ( restMa )
179+ ws : ( head , rest ) => {
180+ const maHasTLS = hasTLS ( rest )
181+ const sni = extractSNI ( rest )
182+ const port = extractPort ( rest )
194183 if ( maHasTLS && sni != null ) {
195184 return `wss://${ sni } ${ port } `
196185 }
197186 const protocol = maHasTLS ? 'wss://' : 'ws://'
198- const tailProto = restMa . pop ( )
199- if ( tailProto == null ) {
187+ const tail = rest . pop ( )
188+ if ( tail == null ) {
200189 throw new Error ( 'Unexpected end of multiaddr' )
201190 }
202- let baseVal = interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa )
191+ let baseVal = interpretNext ( tail , rest )
203192 // We are reinterpreting the base, so we need to remove the tcp:// if it's there
204- baseVal = baseVal . replace ( 'tcp://' , '' )
193+ baseVal = baseVal ? .replace ( 'tcp://' , '' )
205194 return `${ protocol } ${ baseVal } `
206195 } ,
207- wss : ( value : string , restMa : StringTuple [ ] ) => {
208- const tailProto = restMa . pop ( )
209- if ( tailProto == null ) {
196+ wss : ( head , rest ) => {
197+ const tail = rest . pop ( )
198+ if ( tail == null ) {
210199 throw new Error ( 'Unexpected end of multiaddr' )
211200 }
212- let baseVal = interpretNext ( tailProto [ 0 ] , tailProto [ 1 ] ?? '' , restMa )
201+ let baseVal = interpretNext ( tail , rest )
213202 // We are reinterpreting the base as http, so we need to remove the tcp:// if it's there
214- baseVal = baseVal . replace ( 'tcp://' , '' )
203+ baseVal = baseVal ? .replace ( 'tcp://' , '' )
215204 return `wss://${ baseVal } `
216205 }
217206}
218207
219208export function multiaddrToUri ( input : Multiaddr | string | Uint8Array , opts ?: MultiaddrToUriOpts ) : string {
220209 const ma = multiaddr ( input )
221- const parts = ma . stringTuples ( )
222- const head = parts . pop ( )
210+ const components = ma . getComponents ( )
211+ const head = components . pop ( )
223212 if ( head == null ) {
224213 throw new Error ( 'Unexpected end of multiaddr' )
225214 }
226215
227- const protocol = protocols ( head [ 0 ] )
228- const interpreter = interpreters [ protocol . name ]
216+ const interpreter = interpreters [ head . name ]
229217
230218 if ( interpreter == null ) {
231- throw new Error ( `No interpreter found for ${ protocol . name } ` )
219+ throw new Error ( `No interpreter found for ${ head . name } ` )
232220 }
233221
234- let uri = interpreter ( head [ 1 ] ?? '' , parts )
222+ let uri = interpreter ( head , components ) ?? ''
235223
236- if ( opts ?. assumeHttp !== false && ASSUME_HTTP_CODES . includes ( head [ 0 ] ) ) {
224+ if ( opts ?. assumeHttp !== false && ASSUME_HTTP_CODES . includes ( head . code ) ) {
237225 // strip any declared protocol
238226 uri = uri . replace ( / ^ .* : \/ \/ / , '' )
239227
240- if ( head [ 1 ] === '443' ) {
228+ if ( head . value === '443' ) {
241229 uri = `https://${ uri } `
242230 } else {
243231 uri = `http://${ uri } `
0 commit comments