Skip to content

Commit a0f1751

Browse files
authored
fix: refactor to not use deprecated multiaddr functions (#168)
Forwards compatibility fix for upcoming multiaddr changes.
1 parent 9b1f0a7 commit a0f1751

File tree

2 files changed

+98
-108
lines changed

2 files changed

+98
-108
lines changed

src/index.ts

Lines changed: 95 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,31 @@
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

3535
export interface MultiaddrToUriOpts {
3636
assumeHttp?: boolean
3737
}
3838

3939
const 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

9685
const 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

219208
export 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}`

test/test.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ describe('multiaddr-to-uri', () => {
5959
]
6060
]
6161

62-
data.forEach(d => expect(toUri(d[0])).to.equal(d[1]))
62+
data.forEach(d => {
63+
expect(toUri(d[0])).to.equal(d[1])
64+
})
6365
})
6466

6567
it('should convert multiaddr to http(s):// URI when implicit { assumeHttp: true }', () => {

0 commit comments

Comments
 (0)