Skip to content
This repository was archived by the owner on Mar 11, 2020. It is now read-only.

Commit eacfaef

Browse files
committed
chore: add socket concept
1 parent 355e036 commit eacfaef

File tree

2 files changed

+66
-9
lines changed

2 files changed

+66
-9
lines changed

README.md

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,50 @@ Include this badge in your readme if you make a module that is compatible with t
3535

3636
![](https://raw.githubusercontent.com/diasdavid/interface-connection/master/img/badge.png)
3737

38-
# How to use the battery of tests
38+
# Usage
3939

40-
## JS
40+
## Connection
41+
42+
Before creating a connection from a transport compatible with `libp2p` it is important to understand some concepts:
43+
44+
- **socket**: the underlying raw duplex connection between two nodes. It is created by the transports during a dial/listen.
45+
- **connection**: the abstract libp2p duplex connection between two nodes. The transport must pipe the `socket` through the connection.
46+
- **stream**: a single duplex channel of the `connection`. Each connection may have many streams.
47+
48+
A connection stands for the libp2p communication duplex layer between two nodes. It is **not** the underlying raw transport duplex layer (socket), such as a TCP socket, but an abstracted duplex layer that sits on top of the raw socket.
49+
50+
When a libp2p transport creates its socket, a new `connection` instance should be created and the transport should **pipe** both input and output of the socket through this `connection`, i.e. `pipe(socket, connection, socket)`.
51+
52+
The transport must handle the translation of cleanup from the socket to the connection. That is, the errors, resets or closes on the socket **must** be passed to the connection. In the same way, the transport **must** map these actions from the `connection` to the socket. This helps ensuring that the transport is responsible for socket management, while also allowing the application layer to handle the connection management.
53+
54+
```js
55+
const pipe = require('it-pipe')
56+
const { Connection } = require('interface-connection')
57+
58+
class Transport {
59+
async dial () {
60+
// ...
61+
62+
// create the raw socket and the connection
63+
const socket = await this._connect()
64+
const conn = new Connection(remotePeerInfo, remoteMa)
65+
66+
// pipe the socket through the connection (if necessary include a conversion to iterable duplex streams)
67+
pipe(socket, conn, socket)
68+
69+
// bind the necessary handlers to update state changes (error, close, reset, ...)
70+
// ...
71+
72+
return conn
73+
}
74+
75+
_connect () {}
76+
}
77+
```
78+
79+
## Test suite
80+
81+
### JS
4182

4283
```js
4384
describe('your connection', () => {
@@ -52,7 +93,7 @@ describe('your connection', () => {
5293
})
5394
```
5495

55-
## Go
96+
### Go
5697

5798
> WIP
5899
@@ -147,7 +188,7 @@ This property contains the remote peer info of this connection.
147188

148189
- `JavaScript` - `conn.status`
149190

150-
This property contains the status of the connection. It can be either `OPEN`, `CLOSED` or `CLOSING`. Once the creating is created it is in an `OPEN` status. When a `conn.close()` happens, the status will change to `CLOSING` and finally, after all the connection streams are properly closed, the status will be `CLOSED`.
191+
This property contains the status of the connection. It can be either `OPEN`, `CLOSED` or `CLOSING`. Once the connection is created it is in an `OPEN` status. When a `conn.close()` happens, the status will change to `CLOSING` and finally, after all the connection streams are properly closed, the status will be `CLOSED`.
151192

152193
### Endpoints multiaddr
153194

src/connection.js

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict'
22

3+
const { Duplex } = require('stream')
4+
35
const PeerInfo = require('peer-info')
46
const multiaddr = require('multiaddr')
57
const multistream = require('multistream-select')
@@ -16,15 +18,19 @@ const defaultMaxNumberOfAttemptsForHasMultiplexer = 5
1618

1719
/**
1820
* An implementation of the js-libp2p connection.
21+
* This is an abstract duplex connection between two nodes and
22+
* each transport must pipe its socket through this.
1923
*/
20-
class Connection {
24+
class Connection extends Duplex {
2125
/**
2226
* Creates an instance of Connection.
2327
* @param {PeerInfo} peerInfo remote peer PeerInfo
2428
* @param {multiaddr} remoteMa remote peer multiaddr
2529
* @param {boolean} [isInitiator=true] peer initiated the connection
2630
*/
2731
constructor (peerInfo, remoteMa, isInitiator = true) {
32+
super()
33+
2834
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of PeerInfo')
2935
assert(multiaddr.isMultiaddr(remoteMa), 'remoteMa must be an instance of multiaddr')
3036
assert(typeof isInitiator === 'boolean', 'isInitiator must be a boolean')
@@ -190,16 +196,26 @@ class Connection {
190196
return
191197
}
192198

193-
if (this.status !== STATUS.CLOSING) {
194-
this.status = STATUS.CLOSING
195-
this.timeline.close = Date.now()
199+
if (this._closing) {
200+
return this._closing
196201
}
197202

203+
this.status = STATUS.CLOSING
204+
198205
// Close all streams
199-
await Promise.all(this._streams.map((stream) => stream.close()))
206+
this._closing = await this._closeStreams()
200207

208+
this.timeline.close = Date.now()
201209
this.status = STATUS.CLOSED
202210
}
211+
212+
/**
213+
* Close all the streams associated with this connection.
214+
* @return {Promise}
215+
*/
216+
_closeStreams () {
217+
return Promise.all(this._streams.map((stream) => stream.close()))
218+
}
203219
}
204220

205221
module.exports = withIs(Connection, { className: 'Connection', symbolName: '@libp2p/interface-connection/connection' })

0 commit comments

Comments
 (0)