-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'feat/stream-reuse' into 'dev'
feat(rosenet-node): implement stream reuse Closes #61 See merge request ergo/rosen-bridge/p2p!22
- Loading branch information
Showing
12 changed files
with
268 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@rosen-bridge/rosenet-node': minor | ||
--- | ||
|
||
implement stream reuse |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { AbstractLogger } from '@rosen-bridge/logger-interface'; | ||
|
||
const RoseNetNodeTools = { | ||
logger: console as AbstractLogger, | ||
init(logger: AbstractLogger) { | ||
this.logger = logger; | ||
}, | ||
}; | ||
|
||
export default RoseNetNodeTools; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import { Stream } from '@libp2p/interface'; | ||
import { peerIdFromString } from '@libp2p/peer-id'; | ||
import { shuffle } from 'fast-shuffle'; | ||
import { Libp2p } from 'libp2p'; | ||
|
||
import RoseNetNodeTools from './RoseNetNodeTools'; | ||
import createPushable, { Pushable } from './pushable'; | ||
|
||
import { ROSENET_DIRECT_PROTOCOL_V1 } from './constants'; | ||
|
||
const cache = new Map< | ||
string, | ||
{ | ||
stream: Stream; | ||
pushable: Pushable<string>; | ||
} | ||
>(); | ||
|
||
/** | ||
* get a stream and a pushable to the `to` remotePeer with | ||
* ROSENET_DIRECT_PROTOCOL_V1 protocol, caching the pair for future use | ||
* | ||
* @param to remotePeer | ||
* @param node | ||
*/ | ||
async function getStreamAndPushable(to: string, node: Libp2p) { | ||
const cacheHit = cache.get(to); | ||
if (cacheHit?.stream.status === 'open') { | ||
RoseNetNodeTools.logger.debug( | ||
`Found existing stream and pushable in the cache to peer ${to}`, | ||
{ | ||
stream: { | ||
direction: cacheHit.stream.direction, | ||
protocol: cacheHit.stream.protocol, | ||
remotePeer: to, | ||
id: cacheHit.stream.id, | ||
}, | ||
}, | ||
); | ||
return cacheHit; | ||
} | ||
|
||
const peerId = peerIdFromString(to); | ||
|
||
const allConnectionsToPeer = shuffle(node.getConnections(peerId)); | ||
const possibleOpenConnectionToPeer = allConnectionsToPeer.find( | ||
(connection) => connection.status === 'open', | ||
); | ||
const connection = possibleOpenConnectionToPeer ?? (await node.dial(peerId)); | ||
|
||
RoseNetNodeTools.logger.debug( | ||
possibleOpenConnectionToPeer | ||
? `Found an open connection to peer ${to}` | ||
: `Established a new connection to peer ${to}`, | ||
{ | ||
connection: { | ||
id: connection.id, | ||
transient: connection.transient, | ||
}, | ||
}, | ||
); | ||
|
||
const connectionStream = shuffle(connection.streams); | ||
const possibleWritableStream = connectionStream.find( | ||
(stream) => | ||
stream.writeStatus === 'ready' && | ||
stream.protocol === ROSENET_DIRECT_PROTOCOL_V1, | ||
); | ||
const stream = | ||
possibleWritableStream ?? | ||
(await connection.newStream(ROSENET_DIRECT_PROTOCOL_V1, { | ||
runOnTransientConnection: true, | ||
})); | ||
|
||
RoseNetNodeTools.logger.debug( | ||
possibleWritableStream | ||
? `Found an open stream to peer ${to}` | ||
: `Created a new stream to peer ${to}`, | ||
{ | ||
stream: { | ||
direction: stream.direction, | ||
protocol: stream.protocol, | ||
remotePeer: to, | ||
id: stream.id, | ||
}, | ||
}, | ||
); | ||
|
||
const pushable = createPushable<string>(); | ||
|
||
const pair = { | ||
stream, | ||
pushable, | ||
}; | ||
|
||
cache.set(to, pair); | ||
|
||
return pair; | ||
} | ||
|
||
export default getStreamAndPushable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/** | ||
* create an infinite, never ending, FIFO async iterable that can be pushed into | ||
* after consumption | ||
*/ | ||
const createPushable = <T>(): Pushable<T> => { | ||
const iterable: T[] = []; | ||
|
||
let resolveLastYield: () => void | undefined; | ||
|
||
return { | ||
async *[Symbol.asyncIterator](): AsyncGenerator<T, never, unknown> { | ||
while (true) { | ||
/** | ||
* if there is any item in the iterable, yield it, otherwise wait for such | ||
* an item to be pushed and yield it immediately | ||
*/ | ||
if (iterable.length) { | ||
yield Promise.resolve(iterable.shift()!); | ||
} else { | ||
yield new Promise((resolve: (value: T) => void) => { | ||
resolveLastYield = () => { | ||
resolve(iterable.shift()!); | ||
}; | ||
}); | ||
} | ||
} | ||
}, | ||
push: (value: T) => { | ||
iterable.push(value); | ||
if (iterable.length === 1) { | ||
resolveLastYield?.(); | ||
} | ||
}, | ||
}; | ||
}; | ||
|
||
export interface Pushable<T> extends AsyncIterable<T> { | ||
push: (value: T) => void; | ||
} | ||
|
||
export default createPushable; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.