Skip to content
This repository was archived by the owner on Jul 21, 2023. It is now read-only.

Commit 4b0f9e2

Browse files
authored
Merge pull request #18 from libp2p/pull
[WIP] Move to pull-streams
2 parents be4f059 + b62560e commit 4b0f9e2

File tree

8 files changed

+248
-211
lines changed

8 files changed

+248
-211
lines changed

README.md

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,61 @@
1-
js-libp2p-websockets
2-
====================
1+
# js-libp2p-websockets
32

43
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
4+
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/)
55
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
6-
![](https://img.shields.io/badge/coverage-%3F-yellow.svg?style=flat-square)
7-
[![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets)
8-
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
6+
[![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-websockets/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-websockets?branch=master)
7+
[![Travis CI](https://travis-ci.org/libp2p/js-libp2p-websockets.svg?branch=master)](https://travis-ci.org/libp2p/js-libp2p-websockets)
8+
[![Circle CI](https://circleci.com/gh/libp2p/js-libp2p-websockets.svg?style=svg)](https://circleci.com/gh/libp2p/js-libp2p-websockets)
9+
[![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
910

1011
![](https://github.com/raw/libp2p/interface-connection/master/img/badge.png)
1112
![](https://github.com/raw/libp2p/interface-transport/master/img/badge.png)
12-
1313
> JavaScript implementation of the WebSockets module that libp2p uses and that implements the interface-transport interface
14+
15+
## Description
16+
17+
`libp2p-websockets` is the WebSockets implementation compatible with libp2p.
18+
19+
**Note:** This module uses [pull-streams](https://pull-stream.github.io) for all stream based interfaces.
20+
21+
## Example
22+
23+
```
24+
TODO
25+
```
26+
27+
## Installation
28+
29+
### npm
30+
31+
```sh
32+
> npm i libp2p-websockets
33+
```
34+
35+
## This module uses `pull-streams`
36+
37+
We expose a streaming interface based on `pull-streams`, rather then on the Node.js core streams implementation (aka Node.js streams). `pull-streams` offers us a better mechanism for error handling and flow control guarantees. If you would like to know more about what took us to make this migration, see the discussion at this [issue](https://github.com/ipfs/js-ipfs/issues/362).
38+
39+
You can learn more about pull-streams at:
40+
41+
- [The history of Node.js streams, nodebp April 2014](https://www.youtube.com/watch?v=g5ewQEuXjsQ)
42+
- [The history of streams, 2016](http://dominictarr.com/post/145135293917/history-of-streams)
43+
- [pull-streams, the simple streaming primitive](http://dominictarr.com/post/149248845122/pull-streams-pull-streams-are-a-very-simple)
44+
- [pull-streams documentation](https://pull-stream.github.io/)
45+
46+
### Converting `pull-streams` to Node.js Streams
47+
48+
If you are a Node.js streams user, you can convert a pull-stream to Node.js Stream using the module `pull-stream-to-stream`, giving you an instance of a Node.js stream that is linked to the pull-stream. Example:
49+
50+
```
51+
const pullToStream = require('pull-stream-to-stream')
52+
53+
const nodeStreamInstance = pullToStream(pullStreamInstance)
54+
// nodeStreamInstance is an instance of a Node.js Stream
55+
```
56+
57+
To learn more about his utility, visit https://pull-stream.github.io/#pull-stream-to-stream
58+
59+
## API
60+
61+
[![](https://github.com/raw/diasdavid/interface-transport/master/img/badge.png)](https://github.com/diasdavid/interface-transport)

gulpfile.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
const gulp = require('gulp')
44
const multiaddr = require('multiaddr')
5+
const pull = require('pull-stream')
6+
57
const WS = require('./src')
68

79
let listener
@@ -10,7 +12,7 @@ gulp.task('test:browser:before', (done) => {
1012
const ws = new WS()
1113
const ma = multiaddr('/ip4/127.0.0.1/tcp/9090/ws')
1214
listener = ws.createListener((conn) => {
13-
conn.pipe(conn)
15+
pull(conn, conn)
1416
})
1517
listener.listen(ma, done)
1618
})

package.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,38 @@
2222
],
2323
"repository": {
2424
"type": "git",
25-
"url": "git+https://github.com/diasdavid/js-libp2p-websockets.git"
25+
"url": "git+https://github.com/libp2p/js-libp2p-websockets.git"
2626
},
2727
"keywords": [
2828
"IPFS"
2929
],
3030
"author": "David Dias <[email protected]>",
3131
"license": "MIT",
3232
"bugs": {
33-
"url": "https://github.com/diasdavid/js-libp2p-websockets/issues"
33+
"url": "https://github.com/libp2p/js-libp2p-websockets/issues"
3434
},
35-
"homepage": "https://github.com/diasdavid/js-libp2p-websockets#readme",
35+
"homepage": "https://github.com/libp2p/js-libp2p-websockets#readme",
3636
"dependencies": {
3737
"detect-node": "^2.0.3",
38-
"interface-connection": "^0.1.8",
38+
"interface-connection": "^0.2.1",
3939
"lodash.contains": "^2.4.3",
40-
"mafmt": "^2.1.0",
41-
"run-parallel": "^1.1.6",
42-
"simple-websocket": "^4.1.0",
43-
"simple-websocket-server": "^0.1.4"
40+
"mafmt": "^2.1.1",
41+
"pull-ws": "^3.2.3"
4442
},
4543
"devDependencies": {
46-
"aegir": "^6.0.0",
47-
"multiaddr": "^2.0.2",
44+
"aegir": "^6.0.1",
4845
"chai": "^3.5.0",
4946
"gulp": "^3.9.1",
50-
"interface-transport": "^0.2.0",
51-
"pre-commit": "^1.1.2"
47+
"interface-transport": "^0.3.3",
48+
"multiaddr": "^2.0.2",
49+
"pre-commit": "^1.1.3",
50+
"pull-goodbye": "0.0.1",
51+
"pull-stream": "^3.4.3"
5252
},
5353
"contributors": [
5454
"David Dias <[email protected]>",
5555
"Francisco Baio Dias <[email protected]>",
5656
"Friedel Ziegelmayer <[email protected]>",
5757
"greenkeeperio-bot <[email protected]>"
5858
]
59-
}
59+
}

src/index.js

Lines changed: 19 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,147 +1,55 @@
11
'use strict'
22

3-
const debug = require('debug')
4-
const log = debug('libp2p:websockets')
5-
const SW = require('simple-websocket')
6-
const isNode = require('detect-node')
7-
let SWS
8-
if (isNode) {
9-
SWS = require('simple-websocket-server')
10-
} else {
11-
SWS = {}
12-
}
3+
const connect = require('pull-ws/client')
134
const mafmt = require('mafmt')
145
const contains = require('lodash.contains')
156
const Connection = require('interface-connection').Connection
7+
const debug = require('debug')
8+
const log = debug('libp2p:websockets:dialer')
169

17-
const CLOSE_TIMEOUT = 2000
18-
// const IPFS_CODE = 421
19-
20-
exports = module.exports = WebSockets
21-
22-
function WebSockets () {
23-
if (!(this instanceof WebSockets)) {
24-
return new WebSockets()
25-
}
10+
const createListener = require('./listener')
2611

27-
this.dial = function (ma, options, callback) {
12+
module.exports = class WebSockets {
13+
dial (ma, options, callback) {
2814
if (typeof options === 'function') {
2915
callback = options
3016
options = {}
3117
}
3218

3319
if (!callback) {
34-
callback = function noop () {}
20+
callback = () => {}
3521
}
3622

3723
const maOpts = ma.toOptions()
3824

39-
const socket = new SW('ws://' + maOpts.host + ':' + maOpts.port)
40-
41-
const conn = new Connection(socket)
42-
43-
socket.on('timeout', () => {
44-
conn.emit('timeout')
45-
})
46-
47-
socket.on('error', (err) => {
48-
callback(err)
49-
conn.emit('error', err)
50-
})
51-
52-
socket.on('connect', () => {
53-
callback(null, conn)
54-
conn.emit('connect')
25+
const url = `ws://${maOpts.host}:${maOpts.port}`
26+
log('dialing %s', url)
27+
const socket = connect(url, {
28+
binary: true,
29+
onConnect: callback
5530
})
5631

57-
conn.getObservedAddrs = (cb) => {
58-
return cb(null, [ma])
59-
}
32+
const conn = new Connection(socket)
33+
conn.getObservedAddrs = (cb) => cb(null, [ma])
34+
conn.close = (cb) => socket.close(cb)
6035

6136
return conn
6237
}
6338

64-
this.createListener = (options, handler) => {
39+
createListener (options, handler) {
6540
if (typeof options === 'function') {
6641
handler = options
6742
options = {}
6843
}
6944

70-
const listener = SWS.createServer((socket) => {
71-
const conn = new Connection(socket)
72-
73-
conn.getObservedAddrs = (cb) => {
74-
// TODO research if we can reuse the address in anyway
75-
return cb(null, [])
76-
}
77-
handler(conn)
78-
})
79-
80-
let listeningMultiaddr
81-
82-
listener._listen = listener.listen
83-
listener.listen = (ma, callback) => {
84-
if (!callback) {
85-
callback = function noop () {}
86-
}
87-
88-
listeningMultiaddr = ma
89-
90-
if (contains(ma.protoNames(), 'ipfs')) {
91-
ma = ma.decapsulate('ipfs')
92-
}
93-
94-
listener._listen(ma.toOptions(), callback)
95-
}
96-
97-
listener._close = listener.close
98-
listener.close = (options, callback) => {
99-
if (typeof options === 'function') {
100-
callback = options
101-
options = { timeout: CLOSE_TIMEOUT }
102-
}
103-
if (!callback) { callback = function noop () {} }
104-
if (!options) { options = { timeout: CLOSE_TIMEOUT } }
105-
106-
let closed = false
107-
listener.once('close', () => {
108-
closed = true
109-
})
110-
listener._close(callback)
111-
setTimeout(() => {
112-
if (closed) {
113-
return
114-
}
115-
log('unable to close graciously, destroying conns')
116-
Object.keys(listener.__connections).forEach((key) => {
117-
log('destroying %s', key)
118-
listener.__connections[key].destroy()
119-
})
120-
}, options.timeout || CLOSE_TIMEOUT)
121-
}
122-
123-
// Keep track of open connections to destroy in case of timeout
124-
listener.__connections = {}
125-
listener.on('connection', (socket) => {
126-
const key = (~~(Math.random() * 1e9)).toString(36) + Date.now()
127-
listener.__connections[key] = socket
128-
129-
socket.on('close', () => {
130-
delete listener.__connections[key]
131-
})
132-
})
133-
134-
listener.getAddrs = (callback) => {
135-
callback(null, [listeningMultiaddr])
136-
}
137-
138-
return listener
45+
return createListener(options, handler)
13946
}
14047

141-
this.filter = (multiaddrs) => {
48+
filter (multiaddrs) {
14249
if (!Array.isArray(multiaddrs)) {
14350
multiaddrs = [multiaddrs]
14451
}
52+
14553
return multiaddrs.filter((ma) => {
14654
if (contains(ma.protoNames(), 'ipfs')) {
14755
ma = ma.decapsulate('ipfs')

src/listener.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict'
2+
3+
const isNode = require('detect-node')
4+
const Connection = require('interface-connection').Connection
5+
const contains = require('lodash.contains')
6+
7+
// const IPFS_CODE = 421
8+
9+
let createServer
10+
11+
if (isNode) {
12+
createServer = require('pull-ws/server')
13+
} else {
14+
createServer = () => {}
15+
}
16+
17+
module.exports = (options, handler) => {
18+
const listener = createServer((socket) => {
19+
socket.getObservedAddrs = (cb) => {
20+
// TODO research if we can reuse the address in anyway
21+
return cb(null, [])
22+
}
23+
24+
handler(new Connection(socket))
25+
})
26+
27+
let listeningMultiaddr
28+
29+
listener._listen = listener.listen
30+
listener.listen = (ma, cb) => {
31+
cb = cb || (() => {})
32+
listeningMultiaddr = ma
33+
34+
if (contains(ma.protoNames(), 'ipfs')) {
35+
ma = ma.decapsulate('ipfs')
36+
}
37+
38+
listener._listen(ma.toOptions(), cb)
39+
}
40+
41+
listener.getAddrs = (cb) => {
42+
cb(null, [listeningMultiaddr])
43+
}
44+
45+
return listener
46+
}

0 commit comments

Comments
 (0)