Skip to content

Commit

Permalink
fix: cache string and tuple representations (#275)
Browse files Browse the repository at this point in the history
Converting multiaddrs to strings and tuples is expensive and done in many places so cache these representations when they are first requested.
  • Loading branch information
achingbrain authored Sep 29, 2022
1 parent b81e6c0 commit 9b18ff4
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 14 deletions.
11 changes: 6 additions & 5 deletions src/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import varint from 'varint'
import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import type { Protocol } from './protocols-table.js'
import type { StringTuple, Tuple } from './index.js'

/**
* string -> [[str name, str addr]... ]
Expand Down Expand Up @@ -50,7 +51,7 @@ export function stringToStringTuples (str: string) {
/**
* [[str name, str addr]... ] -> string
*/
export function stringTuplesToString (tuples: Array<[number, string?]>) {
export function stringTuplesToString (tuples: StringTuple[]) {
const parts: string[] = []
tuples.map((tup) => {
const proto = protoFromTuple(tup)
Expand All @@ -67,7 +68,7 @@ export function stringTuplesToString (tuples: Array<[number, string?]>) {
/**
* [[str name, str addr]... ] -> [[int code, Uint8Array]... ]
*/
export function stringTuplesToTuples (tuples: Array<string[] | string>): Array<[number, Uint8Array?]> {
export function stringTuplesToTuples (tuples: Array<string[] | string>): Tuple[] {
return tuples.map((tup) => {
if (!Array.isArray(tup)) {
tup = [tup]
Expand All @@ -85,7 +86,7 @@ export function stringTuplesToTuples (tuples: Array<string[] | string>): Array<[
*
* [[int code, Uint8Array]... ] -> [[int code, str addr]... ]
*/
export function tuplesToStringTuples (tuples: Array<[number, Uint8Array?]>): Array<[number, string?]> {
export function tuplesToStringTuples (tuples: Tuple[]): StringTuple[] {
return tuples.map(tup => {
const proto = protoFromTuple(tup)
if (tup[1] != null) {
Expand All @@ -98,7 +99,7 @@ export function tuplesToStringTuples (tuples: Array<[number, Uint8Array?]>): Arr
/**
* [[int code, Uint8Array ]... ] -> Uint8Array
*/
export function tuplesToBytes (tuples: Array<[number, Uint8Array?]>) {
export function tuplesToBytes (tuples: Tuple[]) {
return fromBytes(uint8ArrayConcat(tuples.map((tup) => {
const proto = protoFromTuple(tup)
let buf = Uint8Array.from(varint.encode(proto.code))
Expand All @@ -122,7 +123,7 @@ export function sizeForAddr (p: Protocol, addr: Uint8Array | number[]) {
}
}

export function bytesToTuples (buf: Uint8Array): Array<[number, Uint8Array?]> {
export function bytesToTuples (buf: Uint8Array): Tuple[] {
const tuples: Array<[number, Uint8Array?]> = []
let i = 0
while (i < buf.length) {
Expand Down
30 changes: 24 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export type MultiaddrInput = string | Multiaddr | Uint8Array | null

export interface Resolver { (addr: Multiaddr, options?: AbortOptions): Promise<string[]> }

export type Tuple = [number, Uint8Array?]

export type StringTuple = [number, string?]

export interface AbortOptions {
signal?: AbortSignal
}
Expand Down Expand Up @@ -137,7 +141,7 @@ export interface Multiaddr {
* // [ [ 4, <Buffer 7f 00 00 01> ], [ 6, <Buffer 0f a1> ] ]
* ```
*/
tuples: () => Array<[number, Uint8Array?]>
tuples: () => Tuple[]

/**
* Returns a tuple of string/number parts
Expand All @@ -150,7 +154,7 @@ export interface Multiaddr {
* // [ [ 4, '127.0.0.1' ], [ 6, '4001' ] ]
* ```
*/
stringTuples: () => Array<[number, string?]>
stringTuples: () => StringTuple[]

/**
* Encapsulates a Multiaddr in another Multiaddr
Expand Down Expand Up @@ -396,6 +400,9 @@ export function isMultiaddr (value: any): value is Multiaddr {
*/
class DefaultMultiaddr implements Multiaddr {
public bytes: Uint8Array
private _string?: string
private _tuples?: Tuple[]
private _stringTuples?: StringTuple[]

[symbol]: boolean = true

Expand Down Expand Up @@ -429,7 +436,11 @@ class DefaultMultiaddr implements Multiaddr {
}

toString () {
return codec.bytesToString(this.bytes)
if (this._string == null) {
this._string = codec.bytesToString(this.bytes)
}

return this._string
}

toJSON () {
Expand Down Expand Up @@ -495,12 +506,19 @@ class DefaultMultiaddr implements Multiaddr {
}

tuples (): Array<[number, Uint8Array?]> {
return codec.bytesToTuples(this.bytes)
if (this._tuples == null) {
this._tuples = codec.bytesToTuples(this.bytes)
}

return this._tuples
}

stringTuples (): Array<[number, string?]> {
const t = codec.bytesToTuples(this.bytes)
return codec.tuplesToStringTuples(t)
if (this._stringTuples == null) {
this._stringTuples = codec.tuplesToStringTuples(this.tuples())
}

return this._stringTuples
}

encapsulate (addr: MultiaddrInput): Multiaddr {
Expand Down
6 changes: 3 additions & 3 deletions test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -702,13 +702,13 @@ describe('helpers', () => {
const relay = relayTCP.encapsulate('/p2p/QmZR5a9AAXGqQF2ADqoDdGS8zvqv8n3Pag6TDDnTNMcFW6/p2p-circuit')
const target = multiaddr('/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC')
const original = relay.encapsulate(target)
expect(original.decapsulateCode(421)).to.eql(relay)
expect(relay.decapsulateCode(421)).to.eql(relayTCP)
expect(original.decapsulateCode(421).toJSON()).to.eql(relay.toJSON())
expect(relay.decapsulateCode(421).toJSON()).to.eql(relayTCP.toJSON())
})

it('ignores missing codes', () => {
const tcp = multiaddr('/ip4/0.0.0.0/tcp/8080')
expect(tcp.decapsulateCode(421)).to.eql(tcp)
expect(tcp.decapsulateCode(421).toJSON()).to.eql(tcp.toJSON())
})
})

Expand Down

0 comments on commit 9b18ff4

Please sign in to comment.