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 2 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 == null) {
path = null
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't get it. If value for path is not set, we are resetting it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check this implementation

if (this.#path == null) {

when there is no path in any protocols, it means path = null and we don't need to search for it again the next time getPath() is called

I'll add more comments to this function referring to DefaultMultiaddr.getPath()

Copy link

@nazarhussain nazarhussain Jul 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, with == you are checking for both null and `undefined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nazarhussain yeah it's a bit confused, I changed the condition to if (path === undefined) instead


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