Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: get path and tuples on constructor #329

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 24 additions & 15 deletions src/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import varint from 'varint'
import { convertToBytes, convertToString } from './convert.js'
import { getProtocol } from './protocols-table.js'
import type { StringTuple, Tuple, Protocol } from './index.js'
import type { StringTuple, Tuple, Protocol, MultiaddrInputString, MultiaddrInputStringResult } from './index.js'

/**
* string -> [[str name, str addr]... ]
Expand Down Expand Up @@ -66,19 +66,28 @@ export function stringTuplesToString (tuples: StringTuple[]): string {
}

/**
* [[str name, str addr]... ] -> [[int code, Uint8Array]... ]
* [[str name, str addr]... ] -> {tuples: [[int code, Uint8Array]... ], path: str}
* The logic to get path is the same to DefaultMultiaddr.getPath()
*/
export function stringTuplesToTuples (tuples: Array<string[] | string>): Tuple[] {
return tuples.map((tup) => {
export function stringTuplesToTuples (stringTuples: Array<string[] | string>): Omit<MultiaddrInputStringResult, 'bytes'> {
let path: string | null | undefined
const tuples = stringTuples.map((tup) => {
if (!Array.isArray(tup)) {
tup = [tup]
}
const proto = protoFromTuple(tup)
if (tup.length > 1) {
return [proto.code, convertToBytes(proto.code, tup[1])]
const tuple: Tuple = (tup.length > 1) ? [proto.code, convertToBytes(proto.code, tup[1])] : [proto.code]
if (path === undefined && proto.path === true) {
path = tuple[1] != null ? convertToString(proto.code, tuple[1]) : null
}
return [proto.code]
return tuple
})

if (path === undefined) {
path = null
}

return { tuples, path }
}

/**
Expand Down Expand Up @@ -169,21 +178,21 @@ export function bytesToString (buf: Uint8Array): string {
}

/**
* String -> Uint8Array
* MultiaddrInputString -> MultiaddrInputStringResult
*/
export function stringToBytes (str: string): Uint8Array {
export function parseMultiaddrInputString (str: MultiaddrInputString): MultiaddrInputStringResult {
str = cleanPath(str)
const a = stringToStringTuples(str)
const b = stringTuplesToTuples(a)
const stringTuples = stringToStringTuples(str)
const { tuples, path } = stringTuplesToTuples(stringTuples)

return tuplesToBytes(b)
return { bytes: tuplesToBytes(tuples), tuples, path }
}

/**
* String -> Uint8Array
* MultiaddrInputString -> MultiaddrInputStringResult
*/
export function fromString (str: string): Uint8Array {
return stringToBytes(str)
export function fromMultiaddrInputString (str: MultiaddrInputString): MultiaddrInputStringResult {
return parseMultiaddrInputString(str)
}

/**
Expand Down
19 changes: 17 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,15 @@ export interface NodeAddress {
port: number
}

/**
* Represent a multiaaddr input string
*/
export type MultiaddrInputString = string

/**
* These types can be parsed into a {@link Multiaddr} object
*/
export type MultiaddrInput = string | Multiaddr | Uint8Array | null
export type MultiaddrInput = MultiaddrInputString | Multiaddr | Uint8Array | null

/**
* A Resolver is a function that takes a {@link Multiaddr} and resolves it into one
Expand All @@ -81,6 +86,13 @@ export type Tuple = [number, Uint8Array?]
*/
export type StringTuple = [number, string?]

/** The result of parsing a MultiaddrInput string */
export interface MultiaddrInputStringResult {
bytes: Uint8Array
tuples: Tuple[]
path: string | null
}

/**
* Allows aborting long-lived operations
*/
Expand Down Expand Up @@ -513,7 +525,10 @@ class DefaultMultiaddr implements Multiaddr {
if (addr.length > 0 && addr.charAt(0) !== '/') {
throw new Error(`multiaddr "${addr}" must start with a "/"`)
}
this.bytes = codec.fromString(addr)
const { bytes, tuples, path } = codec.fromMultiaddrInputString(addr)
this.bytes = bytes
this.#tuples = tuples
this.#path = path
} else if (isMultiaddr(addr)) { // Multiaddr
this.bytes = codec.fromBytes(addr.bytes) // validate + copy buffer
} else {
Expand Down
23 changes: 16 additions & 7 deletions test/codec.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { expect } from 'aegir/chai'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import varint from 'varint'
import * as codec from '../src/codec.js'
import { convertToBytes } from '../src/convert.js'

describe('codec', () => {
describe('.stringToStringTuples', () => {
Expand All @@ -16,13 +17,21 @@ describe('codec', () => {
})

describe('.stringTuplesToTuples', () => {
it('handles non array tuples', () => {
expect(
codec.stringTuplesToTuples([['ip4', '0.0.0.0'], 'utp'])
).to.eql(
[[4, Uint8Array.from([0, 0, 0, 0])], [302]]
)
})
const testCases: Array<{ name: string, stringTuples: Array<string[] | string>, tuples: Array<[number, Uint8Array?]>, path: string | null }> = [
{ name: 'handles non array tuples', stringTuples: [['ip4', '0.0.0.0'], 'utp'], tuples: [[4, Uint8Array.from([0, 0, 0, 0])], [302]], path: null },
{ name: 'handle not null path', stringTuples: [['unix', '/tmp/p2p.sock']], tuples: [[400, convertToBytes(400, '/tmp/p2p.sock')]], path: '/tmp/p2p.sock' },
{ name: 'should return the 1st path', stringTuples: [['unix', '/tmp/p2p.sock'], ['unix', '/tmp2/p2p.sock']], tuples: [[400, convertToBytes(400, '/tmp/p2p.sock')], [400, convertToBytes(400, '/tmp2/p2p.sock')]], path: '/tmp/p2p.sock' }
]

for (const { name, stringTuples, tuples, path } of testCases) {
it(name, () => {
expect(
codec.stringTuplesToTuples(stringTuples)
).to.eql(
{ tuples, path }
)
})
}
})

describe('.tuplesToStringTuples', () => {
Expand Down