Compare commits

...

243 Commits

Author SHA1 Message Date
c01c49d5e2 chore: release version v0.22.1 2016-06-27 18:50:56 +01:00
ceb640cca0 chore: update contributors 2016-06-27 18:50:56 +01:00
3712c16e08 update identify 2016-06-27 18:48:31 +01:00
4737493d26 chore: release version v0.22.0 2016-06-27 11:56:36 +01:00
bb95ef119c chore: update contributors 2016-06-27 11:56:36 +01:00
d6e1b96a09 Merge pull request #80 from libp2p/new/identify
The new Identify™
2016-06-27 11:52:16 +01:00
071cdefd83 new identify 2016-06-27 10:48:21 +01:00
84d3471c01 chore: release version v0.21.0 2016-06-24 09:22:25 +01:00
64375d034d chore: update contributors 2016-06-24 09:22:25 +01:00
ca75c3ca4d Merge pull request #79 from libp2p/update-transports
update the transports
2016-06-23 21:49:29 +01:00
0ff3a0a3cd update the transports 2016-06-23 18:58:42 +01:00
edee20ba1a chore: release version v0.20.0 2016-06-04 19:55:53 +01:00
d793469311 chore: update contributors 2016-06-04 19:55:53 +01:00
0c869041b9 Merge pull request #76 from diasdavid/switch-to-lps
switch to lpm stream to match go
2016-06-04 20:53:09 +02:00
cb822757c1 switch to lpm stream to match go 2016-06-04 19:43:56 +01:00
ce86b7b4fb Merge pull request #73 from diasdavid/test/blow-up-websockets
add a test that blows up a WebSockets socket to make sure that spdy does not crash
2016-06-04 20:13:41 +02:00
0c9cba3a5c Merge pull request #74 from RichardLitt/feature/standardize-readme
Standardized README, fixed some grammar
2016-05-31 11:25:26 +01:00
066a157235 Standardized README, fixed some grammar 2016-05-31 11:15:37 +01:00
b917054acc add a test that blows up a WebSockets socket to make sure that spdy does not crash 2016-05-30 22:36:55 +01:00
a579ff818a chore: release version v0.19.5 2016-05-30 15:25:22 +01:00
6fa9dfc2f5 chore: update contributors 2016-05-30 15:25:22 +01:00
cad6d04295 update aegir 2016-05-30 15:18:10 +01:00
215fa08cc8 Merge pull request #72 from diasdavid/fix/spdy-blows-up
fix: Uncaught Error: socket hang up
2016-05-30 15:17:31 +01:00
834a15ddca propagete error and close events properly 2016-05-30 15:05:57 +01:00
33172f5850 chore: release version v0.19.4 2016-05-29 10:40:09 +01:00
6519e0ebd7 chore: update contributors 2016-05-29 10:40:09 +01:00
8341249aa6 Merge pull request #71 from diasdavid/fix/lost-getObservedAddrs-call
if there more than a multiaddr option, we would lose the ability to call getObservedAddrs
2016-05-29 10:33:38 +01:00
4eed2700b0 if there more than a multiaddr option, we would lose the ability to call getObservedAddrs 2016-05-29 10:21:56 +01:00
d10166cdcb chore: release version v0.19.3 2016-05-29 09:12:53 +01:00
9faba46061 chore: update contributors 2016-05-29 09:12:53 +01:00
ad3fd30cf3 update-deps 2016-05-29 09:06:59 +01:00
744061b7d2 chore: release version v0.19.2 2016-05-28 19:22:41 +01:00
aa80c86b0a chore: update contributors 2016-05-28 19:22:41 +01:00
0d53d93149 spdy sends too many closes, listen to only one 2016-05-28 19:14:54 +01:00
12e15ef236 chore: release version v0.19.1 2016-05-28 18:49:06 +01:00
d92bad28a0 chore: update contributors 2016-05-28 18:49:06 +01:00
a997237a2d Merge pull request #70 from diasdavid/feat/hangUp
add hangup feature
2016-05-28 18:46:22 +01:00
bcc669028e add hangup feature 2016-05-28 18:26:48 +01:00
896fe7ab0e chore: release version v0.19.0 2016-05-27 10:08:59 +01:00
e78f035a1c chore: update contributors 2016-05-27 10:08:59 +01:00
d32e52fb11 Merge pull request #69 from diasdavid/update-deps
update deps
2016-05-27 10:03:05 +01:00
5393b25b22 update deps 2016-05-27 09:51:33 +01:00
665f7c6d66 chore: release version v0.18.2 2016-05-24 14:08:13 +01:00
03e02dfba9 chore: update contributors 2016-05-24 14:08:12 +01:00
019f84885d Merge pull request #68 from diasdavid/fix/identify
Make identify not freak out on missing pubkey, it is ok.. this enables webrtc-star discovery to work fine
2016-05-24 14:04:48 +01:00
ceaae4c53f Make identify not freak out on missing pubkey, it is ok.. this enables webrtc-star discovery to work fine 2016-05-24 13:51:34 +01:00
8e5d5c5694 chore: release version v0.18.1 2016-05-23 18:16:38 +01:00
53bb2d3e07 chore: update contributors 2016-05-23 18:16:37 +01:00
47f72296ed kick the machine 2016-05-23 16:47:32 +01:00
2d20a75114 fix everything™ 2016-05-23 16:46:35 +01:00
8212c09088 This makes things go nuts 2016-05-23 11:09:48 +01:00
c69254b00e chore: release version v0.18.0 2016-05-23 08:38:08 +01:00
4f36eda28f chore: update contributors 2016-05-23 08:38:08 +01:00
c53068c803 Merge pull request #64 from diasdavid/add/webrtc-star
restructure and add spdy to browser tests
2016-05-23 08:06:36 +01:00
d771a12d86 add webrtc-star transport tests 2016-05-22 18:32:05 +01:00
3cd5cbb8ec restructure and add spdy to browser tests 2016-05-22 14:52:08 +01:00
09acdab0d3 chore: release version v0.17.0 2016-05-21 11:47:07 +01:00
54128c228c chore: update contributors 2016-05-21 11:47:07 +01:00
872dfb2c03 s/identify/id/ 2016-05-21 11:32:28 +01:00
5f406c6ea0 chore: release version v0.16.0 2016-05-20 12:00:39 +01:00
8f785284dc chore: update contributors 2016-05-20 12:00:39 +01:00
ee0b1eaea5 Merge pull request #61 from diasdavid/update-spdy
update spdy
2016-05-20 11:57:50 +01:00
1791c19c8c update spdy 2016-05-20 11:03:22 +01:00
ea94a81a52 chore: release version v0.15.0 2016-05-19 00:50:59 +01:00
f3e705acc7 chore: update contributors 2016-05-19 00:50:59 +01:00
510b458de2 Merge pull request #60 from diasdavid/feat/crypto-not-crypto
plaintext proto to be compatible with go-ipfs
2016-05-18 23:14:37 +01:00
5aa74ee25d plaintext proto to be compatible with go-ipfs 2016-05-18 22:59:58 +01:00
d991c475df chore: release version v0.14.0 2016-05-18 11:16:01 +01:00
40da1ec2b1 chore: update contributors 2016-05-18 11:16:01 +01:00
7789f5da19 Merge pull request #59 from diasdavid/update/multistream
WIP add new version of multistream
2016-05-18 10:56:48 +01:00
a224b0bc54 add new version of multistream 2016-05-18 10:47:55 +01:00
9d958c3209 chore: release version v0.13.0 2016-05-18 04:23:59 +01:00
dc518f4178 chore: update contributors 2016-05-18 04:23:59 +01:00
1eacc5bc7b Merge pull request #58 from diasdavid/update-deps
update deps to support latest multiaddr
2016-05-18 04:21:32 +01:00
f6193301a5 update deps to support latest multiaddr 2016-05-17 23:28:25 +01:00
8d792fe954 chore: release version v0.12.11 2016-05-11 12:54:39 +01:00
de506873e7 chore: update contributors 2016-05-11 12:54:39 +01:00
61340e3909 Merge pull request #56 from diasdavid/fix/ws-ipfs
fix: handling of ipfs addresses in available transports
2016-05-11 12:52:33 +01:00
8e1413b984 fix: handling of ipfs addresses in available transports
and some refactoring into multiple files
2016-05-11 13:29:52 +02:00
163624c218 chore: release version v0.12.10 2016-05-10 10:26:54 +01:00
6fd8b076e2 chore: update contributors 2016-05-10 10:26:53 +01:00
e54ebb65fe Merge pull request #54 from diasdavid/feat/listen
Feat/listen
2016-05-10 11:14:04 +02:00
9c8a8bb26b feat: add .listen method 2016-05-10 11:06:48 +02:00
3f29ff5d33 chore: release version v0.12.9 2016-05-09 10:59:04 +01:00
a712fd6d22 chore: update contributors 2016-05-09 10:59:04 +01:00
7079f10bcc Merge pull request #53 from diasdavid/test-fixes
test: cleanup and fix hanging tests
2016-05-09 10:52:40 +01:00
1210a9f613 test: cleanup and fix hanging tests 2016-05-09 11:37:24 +02:00
5c76907f3d Merge pull request #52 from diasdavid/fix/warm-a-warm-up-the-other-way-around
make sure it does not try to dial on empty proto and write tests for it
2016-05-09 08:16:41 +01:00
074e7e323b make sure it does not try to dial on empty proto and write tests for it 2016-05-09 07:56:06 +01:00
20994f5320 chore: release version v0.12.8 2016-05-08 22:48:43 +01:00
eac00292f2 chore: update contributors 2016-05-08 22:48:43 +01:00
bf768d3585 Merge pull request #51 from diasdavid/fix-errs
Cleaning up some things
2016-05-08 22:22:23 +01:00
05f799f983 update deps 2016-05-08 23:10:09 +02:00
a81c328bf7 actually fix things 2016-05-08 22:58:08 +02:00
a6ba60a5c4 handle errors when closing 2016-05-08 22:22:46 +02:00
594b770d8e try to appease the travis gods 2016-05-08 22:19:43 +02:00
dbf0d2c422 fix dependencies 2016-05-08 21:44:22 +02:00
275434f873 cleanup close handling 2016-05-08 21:35:04 +02:00
631dad8647 chore: release version v0.12.7 2016-05-06 18:28:37 +01:00
3eac0e0dd6 chore: update contributors 2016-05-06 18:28:37 +01:00
30d4bb641e one more test to check if connected endpoints are closed correctly 2016-05-06 18:27:19 +01:00
b0aeff8f53 chore: release version v0.12.6 2016-05-06 14:29:24 +01:00
998c71fc84 chore: update contributors 2016-05-06 14:29:24 +01:00
b31245adc8 Merge pull request #49 from diasdavid/fix/close-count
fix: call cb in close after all transport are closed
2016-05-06 14:19:13 +01:00
85a064765a fix: call cb in close after all transport are closed 2016-05-06 15:05:34 +02:00
fb56cc3c30 Merge pull request #48 from diasdavid/feat/unhandle
unhandle a protocol
2016-05-06 13:11:58 +01:00
03d0c52d4d unhandle a protocol 2016-05-06 12:49:31 +01:00
0aa7bb72e7 Merge pull request #47 from diasdavid/test/swarm-dial-no-proto
dialing in no proto is fine
2016-05-06 12:43:26 +01:00
e9b3d3496f dialing in no proto is fine 2016-05-06 12:31:23 +01:00
58e18dd01b chore: release version v0.12.5 2016-05-05 00:44:53 +01:00
fb017ebb07 chore: update contributors 2016-05-05 00:44:53 +01:00
08c4c169d6 remove unnecessary console.log 2016-05-05 00:13:48 +01:00
de927e8052 chore: release version v0.12.4 2016-05-04 20:13:00 +01:00
df8e61632b chore: update contributors 2016-05-04 20:13:00 +01:00
b453bd4f83 Merge pull request #46 from diasdavid/feat/improve-identify
Freeze handling conns till identify is finished on the incomming multiplexed streams
2016-05-04 21:11:22 +02:00
0143ab6449 freeze handling conns till identify is finished on the incomming multiplexed streams 2016-05-04 19:42:53 +01:00
02dd32e7df chore: release version v0.12.3 2016-05-04 16:57:00 +01:00
4fe91796cd chore: update contributors 2016-05-04 16:57:00 +01:00
352876cade Merge pull request #45 from diasdavid/feat/id-on-conns
attach peerId to the conn
2016-05-04 17:11:50 +02:00
41b700f509 attach peerId to the conn 2016-05-04 14:55:40 +01:00
eea7e91b15 chore: release version v0.12.2 2016-04-27 10:09:24 +01:00
b11a7972f5 chore: update contributors 2016-04-27 10:09:24 +01:00
15d5bc53fb update deps and npm scripts 2016-04-27 10:08:02 +01:00
9d911af8e0 Merge pull request #44 from diasdavid/feature/events
feature/events
2016-04-27 10:03:29 +01:00
9f1f3c82dc add peer-mux-closed event 2016-04-27 09:44:16 +01:00
d6a1f52962 add peer-mux-established event 2016-04-26 20:47:31 +01:00
7b536819b1 chore: update contributors 2016-04-25 02:29:18 +01:00
7158aaf702 chore: release version v0.12.1 2016-04-25 02:29:18 +01:00
bc87fad5f9 update deps 2016-04-25 02:27:34 +01:00
c9418399a7 bump version manually 2016-04-25 00:20:23 +01:00
2cac123405 chore: update contributors 2016-04-25 00:18:30 +01:00
ff47a9c228 chore: release version v0.11.8 2016-04-25 00:18:30 +01:00
f86a981eb2 update npm scripts 2016-04-25 00:17:07 +01:00
674d68000b chore: update contributors 2016-04-24 23:29:15 +01:00
ae371085c1 chore: release version v0.10.7 2016-04-24 23:29:15 +01:00
770bee3c66 Merge pull request #42 from diasdavid/fix/multiaddr
fix(identify): convert all addresses to multiaddr
2016-04-24 23:19:34 +01:00
6943e3e90b fix(identify): convert all addresses to multiaddr
Fixes #37
2016-04-24 18:39:35 +02:00
a008ebd5b9 chore: update contributors 2016-04-20 13:25:16 +01:00
20108d2de8 chore: release version v0.10.6 2016-04-20 13:25:16 +01:00
15fcfb737c Merge pull request #41 from diasdavid/feat/ipfs-multiaddr
feat: handle ipfs multiaddrs
2016-04-20 13:13:02 +01:00
0fa14c9608 feat: handle ipfs multiaddrs
Closes #38
2016-04-20 13:35:36 +02:00
ac7c8a150e Merge pull request #39 from diasdavid/fix/require
fix: always use fs.readFileSync
2016-04-19 21:43:44 +01:00
851c8ee2a3 fix: always use fs.readFileSync 2016-04-19 13:35:02 +02:00
7a3f9d08d5 chore: update contributors 2016-04-14 21:57:08 +01:00
52d60a7391 chore: release version v0.10.5 2016-04-14 21:57:08 +01:00
165068d05c add circle and bump up timeout, cause travis is slow 2016-04-14 20:52:03 +01:00
9baae15dcf Merge pull request #36 from dignifiedquire/cover
chore: Enable auto coverage reporting
2016-04-14 20:48:12 +01:00
b87524f36a chore: Enable auto coverage reporting 2016-04-14 15:25:30 +02:00
b0484c678e chore: release version v0.10.4 2016-04-14 13:30:49 +01:00
b6c498055f update deps 2016-04-14 12:15:50 +01:00
93fdedf67b chore: release version v0.10.3 2016-04-14 11:42:30 +01:00
9e3b6a80af update npm scripts 2016-04-14 11:37:13 +01:00
997c275139 bump version manually 2016-04-14 10:32:37 +01:00
ba33f2ecd8 add npmignore and bump version manually 2016-04-14 10:19:54 +01:00
c74e2594f8 bump version manually 2016-04-14 03:08:35 +01:00
61757793ed update npm scripts 2016-04-14 03:04:46 +01:00
01bd659ee8 vendor node-forge, update websockets dep 2016-04-14 03:03:54 +01:00
f8cbc89d1a chore: release version v0.9.3 2016-04-14 02:34:07 +01:00
7906f059f7 Merge pull request #34 from dignifiedquire/dignfied
Use dignified.js
2016-04-14 02:26:25 +01:00
cea42f54cd Use dignified.js 1.0.0 2016-04-07 21:21:42 +02:00
71c6242a10 Use dignified.js 2016-03-23 16:10:12 +01:00
d7a0246d54 Release v0.9.2. 2016-03-23 08:32:07 +00:00
1344caa4d2 Merge pull request #33 from diasdavid/tests/add-multiplex-to-the-mix
add multiplex to the mix
2016-03-23 08:28:43 +00:00
52519cd4e9 add multiplex tests 2016-03-23 08:17:16 +00:00
5bfbd8d972 restructure test files 2016-03-23 08:14:37 +00:00
28bd4ab187 Release v0.9.1. 2016-03-23 07:01:54 +00:00
35b5ac6573 Merge pull request #32 from diasdavid/tests/websockets-mania
fix dirty identify bug
2016-03-22 17:36:50 +00:00
2bd536e861 fix dirty identify bug 2016-03-22 17:31:58 +00:00
a2084f01e3 Merge pull request #31 from diasdavid/clean/browser-tests
WIP: clean browser tests, add badgers
2016-03-22 12:07:13 +00:00
8c6ef52504 clean browser tests, add badgers 2016-03-22 12:01:46 +00:00
72f205e2b9 Merge pull request #29 from xicombd/browser-tests
Browser tests
2016-03-22 10:00:28 +00:00
e41694d308 Add more tests 2016-03-20 18:50:30 +00:00
caf3a0180a Add browser tests 2016-03-20 18:22:54 +00:00
879d736686 Merge pull request #30 from xicombd/dial-fixes
Dial fixes
2016-03-20 18:22:00 +00:00
c726c252df Return conn on swarm.dial 2016-03-20 18:11:16 +00:00
f2df5586d5 Update libp2p-websockets and add test for callback's conn 2016-03-20 17:57:14 +00:00
9d149caf15 Release v0.9.0. 2016-03-15 12:57:14 +00:00
689bd4b190 Merge pull request #28 from diasdavid/tests/ws+tcp
All together now 🎵
2016-03-15 12:24:39 +00:00
9a29b01ad3 it wooorks™ 2016-03-15 12:20:42 +00:00
63569849c0 Release v0.8.1. 2016-03-15 11:21:54 +00:00
c4f87f0a33 Merge pull request #27 from diasdavid/tests/websockets
add websockets to the battery of tests, everything checks out
2016-03-15 11:18:07 +00:00
eda78d7a76 add websockets to the battery of tests, everything checks out 2016-03-15 11:14:55 +00:00
6bcf48ff39 Release v0.8.0. 2016-03-15 10:25:27 +00:00
8615a50bc9 Merge pull request #26 from diasdavid/feature/filter-addrs
filter the multiaddrs that are passed to avoid collision
2016-03-15 10:08:43 +00:00
b83e5dd8dc complete 2016-03-15 09:57:06 +00:00
4036ea4b1a Release v0.7.0. 2016-03-11 14:56:16 +00:00
d65a0901b9 Merge pull request #25 from diasdavid/fix/silly-passthrough-bug
silly passthrough bug
2016-03-11 14:55:52 +00:00
412bda731b fixed 2016-03-11 14:47:39 +00:00
69bd386afc Release v0.6.0. 2016-03-10 21:00:28 +00:00
849d38e8e0 update readme badges 2016-03-10 21:00:15 +00:00
bb7f7399b2 Merge pull request #20 from diasdavid/update/simplify
simplify libp2p-swarm
2016-03-10 20:41:23 +00:00
990111980b woot 2016-03-10 20:36:07 +00:00
366b6ef382 design notes 2016-03-10 15:17:07 +00:00
e8de55bc28 update the docs 2016-03-10 14:38:22 +00:00
f8e14e4ddf stream multiplexing done, starting on identify refactor 2016-03-07 15:22:36 +00:00
9d8ee67c61 high level API working + tests 2016-03-06 08:40:49 +00:00
c8f2fdd077 internal transport interface + libp2p-tcp tests 2016-03-05 11:27:57 +00:00
1fd6a3885d remove coverage folder and solve new linting issue 2016-03-03 12:21:01 +00:00
c651dd2aec remove coverage folder and solve new linting issue 2016-03-03 12:18:00 +00:00
d688893268 Merge pull request #19 from diasdavid/update/mocha-istanbul-standard
update swarm
2016-03-03 12:09:06 +00:00
0e636597ee update swarm 2016-03-03 12:08:46 +00:00
b54b7edeeb Merge pull request #18 from RichardLitt/patch-1
Freejs => Freenode
2015-12-29 00:29:30 +01:00
aea0940b2d Freejs => Freenode
See https://github.com/ipfs/community/issues/93
2015-12-28 17:18:08 -05:00
60028daf14 Merge pull request #17 from masylum/feature/remove-v4-to-v6-hack
Removed ipv6/ipv4 hack
2015-11-02 04:32:31 +00:00
c39eb4a830 Removed ipv6 to ipv4 hack 2015-11-01 19:57:20 +01:00
3b9465de92 Release v0.5.5. 2015-10-29 00:27:59 +00:00
c827bd8470 package.json 2015-10-29 00:27:49 +00:00
555f2199df Release v0.5.4. 2015-10-29 00:27:18 +00:00
a9942b014b Merge pull request #16 from diasdavid/rn
update readme and package.json
2015-10-29 00:26:53 +00:00
348615b5aa update readme and package.json 2015-10-29 00:26:18 +00:00
f309d4f7b7 Release v0.5.3. 2015-09-28 16:12:01 +01:00
1c8fbb2c5b Merge branch 'masylum-patch-1' 2015-09-28 16:11:45 +01:00
789fdcfdc3 merge #11 2015-09-28 16:11:16 +01:00
f53124393c Release v0.5.2. 2015-09-28 04:01:45 +01:00
81c6ab013d Merge pull request #14 from masylum/implement-close
Implemented `close` and improved the tests with it
2015-09-28 04:00:12 +01:00
adb5ce19b1 Release v0.5.1. 2015-09-26 21:12:46 +01:00
4feaa8b187 Merge pull request #13 from masylum/patch-3
Do not allow undefined `peerInfo`
2015-09-26 20:59:14 +01:00
5c53540e92 Implemented close and improved the tests with it 2015-09-26 20:12:13 +02:00
8dc46da80f Protect from peers without supported transports
# What

Trying to run compliance tests from the kad router module. I've tried to port the new swarm API but forgot to add a transport. The tests ended up blowing up instead of failing gracefully.

# How to test

```js
peerOne = new Peer(Id.create(), [multiaddr('/ip4/127.0.0.1/tcp/8090')])
peerTwo = new Peer(Id.create(), [multiaddr('/ip4/127.0.0.1/tcp/8091')])
swarm = new Swarm(peerZero)
swarm.dial(peerTwo, {}, function (err) {
  console.log(err);
});
```

This just work and display the error.
2015-09-26 16:55:34 +02:00
0514b0034b Do not allow undefined peerInfo
# What

The code assumes that `peerInfo` exists, the API doesn't.

# How to test

```js
swarm = new Swarm()
swarm.addTransport('tcp', tcp, { multiaddr: mh }, {}, {port: 8095})
```

This shouldn't explode because of `self.peerInfo.multiaddrs`.
2015-09-26 16:24:46 +02:00
cd53344441 Release v0.5.0. 2015-09-23 23:12:50 +01:00
490022cf02 ready to publish new version 2015-09-23 23:12:35 +01:00
4d9d8c94c7 Merge pull request #10 from diasdavid/revisit
Revisit Swarm - multitransport + upgrades - https://github.com/diasdavid/node-ipfs-swarm/issues/8
2015-09-23 23:09:27 +01:00
1ba8e80d4d rm laf 2015-09-23 20:34:31 +01:00
5b7a6051ad comment undone tests 2015-09-23 20:07:55 +01:00
5fe94446d8 rm old test file 2015-09-23 20:07:05 +01:00
92b499df82 fix readme typos and missing links 2015-09-23 20:06:10 +01:00
e6bcde41fb change cov 2015-09-23 19:58:14 +01:00
fb37b4dec9 clear unused console logs 2015-09-23 19:57:37 +01:00
2000827273 add identify 2015-09-23 19:14:29 +01:00
0bcbe63005 rm old code 2015-09-23 17:26:26 +01:00
168d01befd stream muxer for connection reuse test 2015-09-23 17:25:21 +01:00
0040be765d add spdy + test 2015-09-23 17:11:32 +01:00
416e107d64 quick fix for travis 2015-09-22 17:50:41 +01:00
59b00f6886 use warmed up connection + test 2015-09-22 17:27:37 +01:00
8e8d8e9093 dial on a protocol + test 2015-09-22 16:50:42 +01:00
5e4cca52c0 dial a conn + test 2015-09-22 16:16:21 +01:00
e1df0b9ecd add transport and close listener test 2015-09-22 14:31:23 +01:00
73a6a4fd45 adding transports works 2015-09-21 19:56:42 +01:00
1833ded0f7 making progress 2015-09-21 16:46:04 +01:00
544e4a4165 update README with new candidate interface 2015-09-20 21:08:28 +01:00
7aae02581c Merge pull request #7 from Dignifiedquire/identify-tests
identify: Fix some issues with updateSelf.
2015-09-14 19:23:24 +01:00
17f40911db identify: Fix some issues with updateSelf. 2015-08-04 12:10:17 +02:00
41 changed files with 31920 additions and 855 deletions

19
.aegir.js Normal file
View File

@ -0,0 +1,19 @@
'use strict'
const path = require('path')
module.exports = {
webpack: {
resolve: {
alias: {
'node-forge': path.resolve(
path.dirname(require.resolve('libp2p-crypto')),
'../vendor/forge.bundle.js'
)
}
},
externals: {
'simple-websocket-server': '{}'
}
}
}

6
.gitignore vendored
View File

@ -1,3 +1,4 @@
# Logs
logs
*.log
@ -27,6 +28,7 @@ build/Release
node_modules
coverage
.jshintrc
.jshintignore
dist
lib

35
.npmignore Normal file
View File

@ -0,0 +1,35 @@
test
# Logs
logs
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
node_modules
# Optional npm cache directory
.npm
# Optional REPL history
.node_repl_history

View File

@ -1,7 +1,8 @@
sudo: false
language: node_js
node_js:
- "4.0"
- 4
- 5
# Make sure we have new NPM.
before_install:
@ -10,3 +11,14 @@ before_install:
script:
- npm run lint
- npm test
- npm run coverage
addons:
firefox: 'latest'
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
after_success:
- npm run coverage-publish

217
README.md
View File

@ -1,82 +1,203 @@
ipfs-swarm Node.js implementation
=================================
libp2p-swarm JavaScript implementation
======================================
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) [![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) [![Build Status](https://img.shields.io/travis/diasdavid/node-ipfs-swarm/master.svg?style=flat-square)](https://travis-ci.org/diasdavid/node-ipfs-swarm)
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
[![Build Status](https://img.shields.io/travis/libp2p/js-libp2p-swarm/master.svg?style=flat-square)](https://travis-ci.org/libp2p/js-libp2p-swarm)
[![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-swarm/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-swarm?branch=master)
[![Dependency Status](https://david-dm.org/libp2p/js-libp2p-swarm.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-swarm)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
> IPFS swarm implementation in Node.js
> libp2p swarm implementation in JavaScript.
# Description
libp2p-swarm is a connection abstraction that is able to leverage several transports and connection upgrades, such as congestion control, channel encryption, the multiplexing of several streams in one connection, and more. It does this by bringing protocol multiplexing to the application level (instead of the traditional Port level) using multicodec and multistream.
ipfs-swarm is an abstraction for the network layer on IPFS. It offers an API to open streams between peers on a specific protocol.
libp2p-swarm is used by [libp2p](https://github.com/libp2p/js-libp2p) but it can be also used as a standalone module.
Ref spec (WIP) - https://github.com/diasdavid/specs/blob/protocol-spec/protocol/layers.md#network-layer
## Table of Contents
# Usage
- [Install](#install)
- [Usage](#usage)
- [Create a libp2p Swarm](#create-a-libp2p-swarm)
- [API](#api)
- [Transports](#transports)
- [Connection](#connection)
- [`swarm.dial(pi, protocol, callback)`](#swarmdialpi-protocol-callback)
- [`swarm.hangUp(pi, callback)`](#swarmhanguppi-callback)
- [`swarm.listen(callback)`](#swarmlistencallback)
- [`swarm.handle(protocol, handler)`](#swarmhandleprotocol-handler)
- [`swarm.unhandle(protocol)`](#swarmunhandleprotocol)
- [`swarm.close(callback)`](#swarmclosecallback)
- [Design](#design)
- [Multitransport](#multitransport)
- [Connection upgrades](#connection-upgrades)
- [Identify](#identify)
- [Notes](#notes)
- [Contribute](#contribute)
- [License](#license)
### Create a new Swarm
## Install
```javascript
var Swarm = require('ipfs-swarm')
libp2p-swarm is available on npm and so, like any other npm module, just:
var s = new Swarm([port]) // `port` defalts to 4001
```bash
> npm install libp2p-swarm --save
```
### Set the swarm to listen for incoming streams
## Usage
```javascript
s.listen([port], [callback]) // `port` defaults to 4001, `callback` gets called when the socket starts listening
### Create a libp2p Swarm
And use it in your Node.js code as:
```JavaScript
const Swarm = require('libp2p-swarm')
const sw = new Swarm(peerInfo)
```
### Close the listener/socket and every open stream that was multiplexed on it
## API
```javascript
s.closeListener()
```
peerInfo is a [PeerInfo](https://github.com/diasdavid/js-peer-info) object that represents the peer creating this swarm instance.
### Register a protocol to be handled by an incoming stream
### Transports
```javascript
s.registerHandler('/name/protocol/you/want/version', function (stream) {})
```
##### `swarm.transport.add(key, transport, options, callback)`
### Open a new connection
libp2p-swarm expects transports that implement [interface-transport](https://github.com/diasdavid/abstract-transport). For example [libp2p-tcp](https://github.com/diasdavid/js-libp2p-tcp).
Used when we want to make sure we can connect to a given peer, but do not intend to establish a stream with any of the services offered right away.
- `key` - the transport identifier.
- `transport` -
- `options` -
- `callback` -
```
s.openConnection(peerConnection, function (err) {})
```
##### `swarm.transport.dial(key, multiaddrs, callback)`
Dial to a peer on a specific transport.
### Dial a new stream
- `key`
- `multiaddrs`
- `callback`
```
s.openStream(peerInfo, protocol, function (err, stream) {})
```
##### `swarm.transport.listen(key, options, handler, callback)`
peerInfo must be a [`ipfs-peer`](https://www.npmjs.com/package/ipfs-peer) object, contaning both peer-id and multiaddrs.
Set a transport to start listening mode.
## Events emitted
- `key`
- `options`
- `handler`
- `callback`
```
.on('error')
##### `swarm.transport.close(key, callback)`
.on('connection')
.on('connection-unknown') // used by Identify to start the Identify protocol from listener to dialer
```
Close the listeners of a given transport.
## Identify protocol
- `key`
- `callback`
The Identify protocol is an integral part to Swarm. It enables peers to share observedAddrs, identities and other possible address available. This enables us to do better NAT traversal.
### Connection
To instantiate Identify:
##### `swarm.connection.addUpgrade()`
```
var Identify = require('ipfs-swarm/identify')
A connection upgrade must be able to receive and return something that implements the [interface-connection](https://github.com/diasdavid/interface-connection) specification.
var i = new Identify(swarmInstance, peerSelf)
```
> **WIP**
`swarmInstance` must be an Instance of swarm and `peerSelf` must be a instance of `ipfs-peer` that represents the peer that instantiated this Identify
##### `swarm.connection.addStreamMuxer(muxer)`
Identify emits a `peer-update` event each time it receives information from another peer.
Upgrading a connection to use a stream muxer is still considered an upgrade, but a special case since once this connection is applied, the returned obj will implement the [interface-stream-muxer](https://github.com/diasdavid/interface-stream-muxer) spec.
- `muxer`
##### `swarm.connection.reuse()`
Enable the identify protocol.
### `swarm.dial(pi, protocol, callback)`
dial uses the best transport (whatever works first, in the future we can have some criteria), and jump starts the connection until the point where we have to negotiate the protocol. If a muxer is available, then drop the muxer onto that connection. Good to warm up connections or to check for connectivity. If we have already a muxer for that peerInfo, then do nothing.
- `pi` - peer info project
- `protocol`
- `callback`
### `swarm.hangUp(pi, callback)`
Hang up the muxed connection we have with the peer.
- `pi` - peer info project
- `callback`
### `swarm.listen(callback)`
Start listening on all added transports that are available on the current `peerInfo`.
### `swarm.handle(protocol, handler)`
Handle a new protocol.
- `protocol`
- `handler` - function called when we receive a dial on `protocol. Signature must be `function (conn) {}`
### `swarm.unhandle(protocol)`
Unhandle a protocol.
- `protocol`
### `swarm.close(callback)`
Close all the listeners and muxers.
- `callback`
## Design
### Multitransport
libp2p is designed to support multiple transports at the same time. While peers are identified by their ID (which are generated from their public keys), the addresses of each pair may vary, depending the device where they are being run or the network in which they are accessible through.
In order for a transport to be supported, it has to follow the [interface-transport](https://github.com/diasdavid/interface-transport) spec.
### Connection upgrades
Each connection in libp2p follows the [interface-connection](https://github.com/diasdavid/interface-connection) spec. This design decision enables libp2p to have upgradable transports.
We think of `upgrade` as a very important notion when we are talking about connections, we can see mechanisms like: stream multiplexing, congestion control, encrypted channels, multipath, simulcast, etc, as `upgrades` to a connection. A connection can be a simple and with no guarantees, drop a packet on the network with a destination thing, a transport in the other hand can be a connection and or a set of different upgrades that are mounted on top of each other, giving extra functionality to that connection and therefore `upgrading` it.
Types of upgrades to a connection:
- encrypted channel (with TLS for e.g)
- congestion flow (some transports don't have it by default)
- multipath (open several connections and abstract it as a single connection)
- simulcast (still really thinking this one through, it might be interesting to send a packet through different connections under some hard network circumstances)
- stream-muxer - this a special case, because once we upgrade a connection to a stream-muxer, we can open more streams (multiplex them) on a single stream, also enabling us to reuse the underlying dialed transport
We also want to enable flexibility when it comes to upgrading a connection, for example, we might that all dialed transports pass through the encrypted channel upgrade, but not the congestion flow, specially when a transport might have already some underlying properties (UDP vs TCP vs WebRTC vs every other transport protocol)
### Identify
Identify is a protocol that Swarms mounts on top of itself, to identify the connections between any two peers. E.g:
- a) peer A dials a conn to peer B
- b) that conn gets upgraded to a stream multiplexer that both peers agree
- c) peer B executes de identify protocol
- d) peer B now can open streams to peer A, knowing which is the identity of peer A
In addition to this, we also share the 'observed addresses' by the other peer, which is extremely useful information for different kinds of network topologies.
### Notes
To avoid the confusion between connection, stream, transport, and other names that represent an abstraction of data flow between two points, we use terms as:
- connection - something that implements the transversal expectations of a stream between two peers, including the benefits of using a stream plus having a way to do half duplex, full duplex
- transport - something that as a dial/listen interface and return objs that implement a connection interface
## Contribute
This module is actively under development. Please check out the issues and submit PRs!
## License
MIT © Protocol Labs

12
circle.yml Normal file
View File

@ -0,0 +1,12 @@
machine:
node:
version: stable
dependencies:
pre:
- google-chrome --version
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
- sudo apt-get update
- sudo apt-get --only-upgrade install google-chrome-stable
- google-chrome --version

View File

@ -1,25 +0,0 @@
// var Identify = require('./../src/identify')
var Swarm = require('./../src')
var Peer = require('ipfs-peer')
var Id = require('ipfs-peer-id')
var multiaddr = require('multiaddr')
var a = new Swarm()
a.port = 4000
// a.listen()
// var peerA = new Peer(Id.create(), [multiaddr('/ip4/127.0.0.1/tcp/' + a.port)])
// attention, peerB Id isn't going to match, but whateves
var peerB = new Peer(Id.create(), [multiaddr('/ip4/127.0.0.1/tcp/4001')])
// var i = new Identify(a, peerA)
// i.on('thenews', function (news) {
// console.log('such news')
// })
a.openStream(peerB, '/ipfs/sparkles/1.2.3', function (err, stream) {
if (err) {
return console.log(err)
}
console.log('WoHoo, dialed a stream')
})

View File

@ -1,28 +0,0 @@
// var Identify = require('./../src/identify')
var Swarm = require('./../src')
// var Peer = require('ipfs-peer')
// var Id = require('ipfs-peer-id')
// var multiaddr = require('multiaddr')
var b = new Swarm()
b.port = 4001
// var peerB = new Peer(Id.create(), [multiaddr('/ip4/127.0.0.1/tcp/' + b.port)])
// var i = new Identify(b, peerB)
// i.on('thenews', function (news) {
// console.log('such news')
// })
b.on('error', function (err) {
console.log(err)
})
b.listen()
b.registerHandler('/ipfs/sparkles/1.2.3', function (stream) {
// if (err) {
// return console.log(err)
// }
console.log('woop got a stream')
})

76
gulpfile.js Normal file
View File

@ -0,0 +1,76 @@
'use strict'
const gulp = require('gulp')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const WebSockets = require('libp2p-websockets')
const Swarm = require('./src')
const spdy = require('libp2p-spdy')
const multiaddr = require('multiaddr')
const fs = require('fs')
const path = require('path')
const sigServer = require('libp2p-webrtc-star/src/signalling-server')
let swarmA
let swarmB
let sigS
gulp.task('test:browser:before', (done) => {
function createListenerA (cb) {
const id = PeerId.createFromJSON(
JSON.parse(
fs.readFileSync(
path.join(__dirname, './test/test-data/id-1.json'))))
const peerA = new PeerInfo(id)
const maA = multiaddr('/ip4/127.0.0.1/tcp/9100/ws')
peerA.multiaddr.add(maA)
swarmA = new Swarm(peerA)
swarmA.transport.add('ws', new WebSockets())
swarmA.transport.listen('ws', {}, echo, cb)
}
function createListenerB (cb) {
const id = PeerId.createFromJSON(
JSON.parse(
fs.readFileSync(
path.join(__dirname, './test/test-data/id-2.json'))))
const peerB = new PeerInfo(id)
const maB = multiaddr('/ip4/127.0.0.1/tcp/9200/ws')
peerB.multiaddr.add(maB)
swarmB = new Swarm(peerB)
swarmB.transport.add('ws', new WebSockets())
swarmB.connection.addStreamMuxer(spdy)
swarmB.connection.reuse()
swarmB.listen(cb)
swarmB.handle('/echo/1.0.0', echo)
}
let count = 0
const ready = () => ++count === 3 ? done() : null
createListenerA(ready)
createListenerB(ready)
sigS = sigServer.start(15555, ready)
function echo (conn) {
conn.pipe(conn)
}
})
gulp.task('test:browser:after', (done) => {
let count = 0
const ready = () => ++count === 3 ? done() : null
swarmA.transport.close('ws', ready)
swarmB.close(ready)
sigS.stop(ready)
})
require('aegir/gulp')(gulp)

View File

@ -1,18 +1,24 @@
{
"name": "ipfs-swarm",
"version": "0.4.1",
"description": "IPFS swarm implementation in Node.js",
"main": "src/index.js",
"name": "libp2p-swarm",
"version": "0.22.1",
"description": "libp2p swarm implementation in JavaScript",
"main": "lib/index.js",
"jsnext:main": "src/index.js",
"scripts": {
"test": "./node_modules/.bin/lab tests/*-test.js",
"coverage": "./node_modules/.bin/lab -t 100 tests/*-test.js",
"codestyle": "./node_modules/.bin/standard --format",
"lint": "./node_modules/.bin/standard",
"validate": "npm ls"
"lint": "gulp lint",
"build": "gulp build",
"test": "gulp test",
"test:node": "gulp test:node",
"test:browser": "gulp test:browser",
"release": "gulp release",
"release-minor": "gulp release --type minor",
"release-major": "gulp release --type major",
"coverage": "gulp coverage",
"coverage-publish": "aegir-coverage publish"
},
"repository": {
"type": "git",
"url": "https://github.com/diasdavid/node-ipfs-swarm.git"
"url": "https://github.com/libp2p/js-libp2p-swarm.git"
},
"keywords": [
"IPFS"
@ -20,34 +26,54 @@
"author": "David Dias <daviddias@ipfs.io>",
"license": "MIT",
"bugs": {
"url": "https://github.com/diasdavid/node-ipfs-swarm/issues"
"url": "https://github.com/libp2p/js-libp2p-swarm/issues"
},
"homepage": "https://github.com/diasdavid/node-ipfs-swarm",
"homepage": "https://github.com/libp2p/js-libp2p-swarm",
"pre-commit": [
"codestyle",
"lint",
"test"
],
"engines": {
"node": "^4.0.0"
"node": "^4.3.0"
},
"devDependencies": {
"code": "^1.4.1",
"lab": "^5.13.0",
"precommit-hook": "^3.0.0",
"sinon": "^1.15.4",
"standard": "^4.5.2",
"stream-pair": "^1.0.3"
"aegir": "^3.2.0",
"buffer-loader": "0.0.1",
"chai": "^3.5.0",
"gulp": "^3.9.1",
"istanbul": "^0.4.3",
"libp2p-multiplex": "^0.2.1",
"libp2p-spdy": "^0.7.0",
"libp2p-tcp": "^0.7.1",
"libp2p-webrtc-star": "^0.3.1",
"libp2p-websockets": "^0.7.0",
"pre-commit": "^1.1.2",
"stream-pair": "^1.0.3",
"webrtcsupport": "^2.2.0"
},
"dependencies": {
"async": "^1.3.0",
"ip-address": "^4.0.0",
"ipfs-logger": "^0.1.0",
"ipfs-peer": "^0.3.0",
"ipfs-peer-id": "^0.3.0",
"multiaddr": "^1.0.0",
"multiplex-stream-muxer": "^0.2.0",
"multistream-select": "^0.6.1",
"protocol-buffers-stream": "^1.2.0",
"spdy-stream-muxer": "^0.6.0"
}
}
"babel-runtime": "^6.6.1",
"bl": "^1.1.2",
"browserify-zlib": "github:ipfs/browserify-zlib",
"duplexify": "^3.4.3",
"interface-connection": "^0.1.7",
"ip-address": "^5.8.0",
"length-prefixed-stream": "^1.5.0",
"libp2p-identify": "^0.1.2",
"lodash.contains": "^2.4.3",
"multiaddr": "^2.0.0",
"multistream-select": "^0.9.0",
"peer-id": "^0.7.0",
"peer-info": "^0.7.0",
"protocol-buffers": "^3.1.6",
"run-parallel": "^1.1.6"
},
"contributors": [
"David Dias <daviddias.p@gmail.com>",
"David Dias <mail@daviddias.me>",
"Francisco Baio Dias <xicombd@gmail.com>",
"Pau Ramon Revilla <masylum@gmail.com>",
"Richard Littauer <richard.littauer@gmail.com>",
"dignifiedquire <dignifiedquire@gmail.com>"
]
}

74
src/connection.js Normal file
View File

@ -0,0 +1,74 @@
'use strict'
const protocolMuxer = require('./protocol-muxer')
const identify = require('libp2p-identify')
const multistream = require('multistream-select')
module.exports = function connection (swarm) {
return {
addUpgrade () {},
addStreamMuxer (muxer) {
// for dialing
swarm.muxers[muxer.multicodec] = muxer
// for listening
swarm.handle(muxer.multicodec, (conn) => {
const muxedConn = muxer(conn, true)
muxedConn.on('stream', (conn) => {
protocolMuxer(swarm.protocols, conn)
})
// If identify is enabled
// 1. overload getPeerInfo
// 2. call getPeerInfo
// 3. add this conn to the pool
if (swarm.identify) {
// overload peerInfo to use Identify instead
conn.getPeerInfo = (cb) => {
const conn = muxedConn.newStream()
const ms = new multistream.Dialer()
ms.handle(conn, (err) => {
if (err) { return cb(err) }
ms.select(identify.multicodec, (err, conn) => {
if (err) { return cb(err) }
identify.exec(conn, (err, peerInfo, observedAddrs) => {
if (err) { return cb(err) }
observedAddrs.forEach((oa) => {
swarm._peerInfo.multiaddr.addSafe(oa)
})
cb(null, peerInfo)
})
})
})
}
conn.getPeerInfo((err, peerInfo) => {
if (err) {
return console.log('Identify not successful')
}
swarm.muxedConns[peerInfo.id.toB58String()] = {
muxer: muxedConn
}
swarm.emit('peer-mux-established', peerInfo)
muxedConn.on('close', () => {
delete swarm.muxedConns[peerInfo.id.toB58String()]
swarm.emit('peer-mux-closed', peerInfo)
})
})
}
})
},
reuse () {
swarm.identify = true
swarm.handle(identify.multicodec, identify.handler(swarm._peerInfo))
}
}
}

185
src/dial.js Normal file
View File

@ -0,0 +1,185 @@
'use strict'
const multistream = require('multistream-select')
const Connection = require('interface-connection').Connection
const protocolMuxer = require('./protocol-muxer')
module.exports = function dial (swarm) {
return (pi, protocol, callback) => {
if (typeof protocol === 'function') {
callback = protocol
protocol = null
}
if (!callback) {
callback = function noop () {}
}
const proxyConn = new Connection()
const b58Id = pi.id.toB58String()
if (!swarm.muxedConns[b58Id]) {
if (!swarm.conns[b58Id]) {
attemptDial(pi, (err, conn) => {
if (err) {
return callback(err)
}
gotWarmedUpConn(conn)
})
} else {
const conn = swarm.conns[b58Id]
swarm.conns[b58Id] = undefined
gotWarmedUpConn(conn)
}
} else {
if (!protocol) {
return callback()
}
gotMuxer(swarm.muxedConns[b58Id].muxer)
}
return proxyConn
function gotWarmedUpConn (conn) {
conn.setPeerInfo(pi)
attemptMuxerUpgrade(conn, (err, muxer) => {
if (!protocol) {
if (err) {
swarm.conns[b58Id] = conn
}
return callback()
}
if (err) {
// couldn't upgrade to Muxer, it is ok
protocolHandshake(conn, protocol, callback)
} else {
gotMuxer(muxer)
}
})
}
function gotMuxer (muxer) {
if (swarm.identify) {
// TODO: Consider:
// 1. overload getPeerInfo
// 2. exec identify (through getPeerInfo)
// 3. update the peerInfo that is already stored in the conn
}
openConnInMuxedConn(muxer, (conn) => {
protocolHandshake(conn, protocol, callback)
})
}
function attemptDial (pi, cb) {
const tKeys = swarm.availableTransports(pi)
if (tKeys.length === 0) {
return cb(new Error('No available transport to dial to'))
}
nextTransport(tKeys.shift())
function nextTransport (key) {
const multiaddrs = pi.multiaddrs.slice()
swarm.transport.dial(key, multiaddrs, (err, conn) => {
if (err) {
if (tKeys.length === 0) {
return cb(new Error('Could not dial in any of the transports'))
}
return nextTransport(tKeys.shift())
}
cryptoDial()
function cryptoDial () {
// currently, no crypto channel is implemented
const ms = new multistream.Dialer()
ms.handle(conn, (err) => {
if (err) {
return cb(err)
}
ms.select('/plaintext/1.0.0', cb)
})
}
})
}
}
function attemptMuxerUpgrade (conn, cb) {
const muxers = Object.keys(swarm.muxers)
if (muxers.length === 0) {
return cb(new Error('no muxers available'))
}
// 1. try to handshake in one of the muxers available
// 2. if succeeds
// - add the muxedConn to the list of muxedConns
// - add incomming new streams to connHandler
nextMuxer(muxers.shift())
function nextMuxer (key) {
const ms = new multistream.Dialer()
ms.handle(conn, (err) => {
if (err) {
return callback(new Error('multistream not supported'))
}
ms.select(key, (err, conn) => {
if (err) {
if (muxers.length === 0) {
cb(new Error('could not upgrade to stream muxing'))
} else {
nextMuxer(muxers.shift())
}
return
}
const muxedConn = swarm.muxers[key](conn, false)
swarm.muxedConns[b58Id] = {}
swarm.muxedConns[b58Id].muxer = muxedConn
// should not be needed anymore - swarm.muxedConns[b58Id].conn = conn
swarm.emit('peer-mux-established', pi)
muxedConn.once('close', () => {
delete swarm.muxedConns[pi.id.toB58String()]
swarm.emit('peer-mux-closed', pi)
})
// For incoming streams, in case identify is on
muxedConn.on('stream', (conn) => {
protocolMuxer(swarm.protocols, conn)
})
cb(null, muxedConn)
})
})
}
}
function openConnInMuxedConn (muxer, cb) {
cb(muxer.newStream())
}
function protocolHandshake (conn, protocol, cb) {
const ms = new multistream.Dialer()
ms.handle(conn, (err) => {
if (err) {
return callback(err)
}
ms.select(protocol, (err, conn) => {
if (err) {
return callback(err)
}
proxyConn.setInnerConn(conn)
callback(null, proxyConn)
})
})
}
}
}

View File

@ -1,25 +0,0 @@
message Identify {
// protocolVersion determines compatibility between peers
optional string protocolVersion = 5; // e.g. ipfs/1.0.0
// agentVersion is like a UserAgent string in browsers, or client version in bittorrent
// includes the client name and client.
optional string agentVersion = 6; // e.g. go-ipfs/0.1.0
// publicKey is this node's public key (which also gives its node.ID)
// - may not need to be sent, as secure channel implies it has been sent.
// - then again, if we change / disable secure channel, may still want it.
optional bytes publicKey = 1;
// listenAddrs are the multiaddrs the sender node listens for open connections on
repeated bytes listenAddrs = 2;
// oservedAddr is the multiaddr of the remote endpoint that the sender node perceives
// this is useful information to convey to the other side, as it helps the remote endpoint
// determine whether its connection to the local peer goes through NAT.
optional bytes observedAddr = 4;
// (DEPRECATED) protocols are the services this node is running
// repeated string protocols = 3;
}

View File

@ -1,141 +0,0 @@
/*
* Identify is one of the protocols swarms speaks in order to broadcast and learn
* about the ip:port pairs a specific peer is available through
*/
var Interactive = require('multistream-select').Interactive
var EventEmmiter = require('events').EventEmitter
var util = require('util')
var protobufs = require('protocol-buffers-stream')
var fs = require('fs')
var schema = fs.readFileSync(__dirname + '/identify.proto')
var v6 = require('ip-address').v6
var Id = require('ipfs-peer-id')
var multiaddr = require('multiaddr')
exports = module.exports = Identify
util.inherits(Identify, EventEmmiter)
function Identify (swarm, peerSelf) {
var self = this
self.createProtoStream = protobufs(schema)
swarm.registerHandler('/ipfs/identify/1.0.0', function (stream) {
var ps = self.createProtoStream()
ps.on('identify', function (msg) {
updateSelf(peerSelf, msg.observedAddr)
var peerId = Id.createFromPubKey(msg.publicKey)
var socket = swarm.connections[peerId.toB58String()].socket
var mh = getMultiaddr(socket)
ps.identify({
protocolVersion: 'na',
agentVersion: 'na',
publicKey: peerSelf.id.pubKey,
listenAddrs: peerSelf.multiaddrs.map(function (mh) {return mh.buffer}),
observedAddr: mh.buffer
})
self.emit('peer-update', {
peerId: peerId,
listenAddrs: msg.listenAddrs.map(function (mhb) {return multiaddr(mhb)})
})
ps.finalize()
})
ps.pipe(stream).pipe(ps)
})
swarm.on('connection-unknown', function (conn, socket) {
conn.dialStream(function (err, stream) {
if (err) { return console.log(err) }
var msi = new Interactive()
msi.handle(stream, function () {
msi.select('/ipfs/identify/1.0.0', function (err, ds) {
if (err) { return console.log(err) }
var ps = self.createProtoStream()
ps.on('identify', function (msg) {
var peerId = Id.createFromPubKey(msg.publicKey)
updateSelf(peerSelf, msg.observedAddr)
swarm.connections[peerId.toB58String()] = {
conn: conn,
socket: socket
}
self.emit('peer-update', {
peerId: peerId,
listenAddrs: msg.listenAddrs.map(function (mhb) {return multiaddr(mhb)})
})
})
var mh = getMultiaddr(socket)
ps.identify({
protocolVersion: 'na',
agentVersion: 'na',
publicKey: peerSelf.id.pubKey,
listenAddrs: peerSelf.multiaddrs.map(function (mh) {return mh.buffer}),
observedAddr: mh.buffer
})
ps.pipe(ds).pipe(ps)
ps.finalize()
})
})
})
})
}
function getMultiaddr (socket) {
var mh
if (~socket.remoteAddress.indexOf(':')) {
var addr = new v6.Address(socket.remoteAddress)
if (addr.v4) {
var ip4 = socket.remoteAddress.split(':')[3]
mh = multiaddr('/ip4/' + ip4 + '/tcp/' + socket.remotePort)
} else {
mh = multiaddr('/ip6/' + socket.remoteAddress + '/tcp/' + socket.remotePort)
}
} else {
mh = multiaddr('/ip4/' + socket.remoteAddress + '/tcp/' + socket.remotePort)
}
return mh
}
function updateSelf (peerSelf, observedAddr) {
var omh = multiaddr(observedAddr)
if (!peerSelf.previousObservedAddrs) {
peerSelf.previousObservedAddrs = []
}
for (var i = 0; i < peerSelf.previousObservedAddrs.length; i++) {
if (peerSelf.previousObservedAddrs[i].toString() === omh.toString()) {
peerSelf.previousObservedAddrs.splice(i, 1)
addToSelf()
return
}
}
peerSelf.previousObservedAddrs.push(omh)
function addToSelf () {
var isIn = false
peerSelf.multiaddrs.forEach(function (mh) {
if (mh.toString() === omh.toString()) {
isIn = true
}
})
if (!isIn) {
peerSelf.multiaddrs.push(omh)
}
}
}

View File

@ -1,4 +1,135 @@
var Swarm = require('./swarm')
'use strict'
const util = require('util')
const EE = require('events').EventEmitter
const parallel = require('run-parallel')
const contains = require('lodash.contains')
const transport = require('./transport')
const connection = require('./connection')
const dial = require('./dial')
const protocolMuxer = require('./protocol-muxer')
exports = module.exports = Swarm
exports.singleton = new Swarm()
util.inherits(Swarm, EE)
function Swarm (peerInfo) {
if (!(this instanceof Swarm)) {
return new Swarm(peerInfo)
}
if (!peerInfo) {
throw new Error('You must provide a value for `peerInfo`')
}
this._peerInfo = peerInfo
// transports --
// { key: transport }; e.g { tcp: <tcp> }
this.transports = {}
// connections --
// { peerIdB58: { conn: <conn> }}
this.conns = {}
// {
// peerIdB58: {
// muxer: <muxer>
// conn: <transport socket> // to extract info required for the Identify Protocol
// }
// }
this.muxedConns = {}
// { protocol: handler }
this.protocols = {}
// { muxerCodec: <muxer> } e.g { '/spdy/0.3.1': spdy }
this.muxers = {}
// is the Identify protocol enabled?
this.identify = false
this.transport = transport(this)
this.connection = connection(this)
this.availableTransports = (pi) => {
const addrs = pi.multiaddrs
// Only listen on transports we actually have addresses for
return Object.keys(this.transports).filter((ts) => {
// ipfs multiaddrs are not dialable so we drop them here
let dialable = addrs.map((addr) => {
// webrtc-star needs the /ipfs/QmHash
if (addr.toString().indexOf('webrtc-star') > 0) {
return addr
}
if (contains(addr.protoNames(), 'ipfs')) {
return addr.decapsulate('ipfs')
}
return addr
})
return this.transports[ts].filter(dialable).length > 0
})
}
// higher level (public) API
this.dial = dial(this)
// Start listening on all available transports
this.listen = (callback) => {
parallel(this.availableTransports(peerInfo).map((ts) => (cb) => {
// Listen on the given transport
this.transport.listen(ts, {}, null, cb)
}), callback)
}
this.handle = (protocol, handler) => {
this.protocols[protocol] = handler
}
// our crypto handshake :)
this.handle('/plaintext/1.0.0', (conn) => {
protocolMuxer(this.protocols, conn)
})
this.unhandle = (protocol, handler) => {
if (this.protocols[protocol]) {
delete this.protocols[protocol]
}
}
this.hangUp = (peerInfo, callback) => {
const key = peerInfo.id.toB58String()
if (this.muxedConns[key]) {
const muxer = this.muxedConns[key].muxer
muxer.end()
muxer.once('close', () => {
delete this.muxedConns[key]
callback()
})
} else {
callback()
}
}
this.close = (callback) => {
Object.keys(this.muxedConns).forEach((key) => {
this.muxedConns[key].muxer.end()
})
const transports = this.transports
parallel(Object.keys(transports).map((key) => {
return (cb) => {
parallel(transports[key].listeners.map((listener) => {
return (cb) => {
listener.close(cb)
}
}), cb)
}
}), callback)
}
}

21
src/protocol-muxer.js Normal file
View File

@ -0,0 +1,21 @@
'use strict'
const multistream = require('multistream-select')
module.exports = function protocolMuxer (protocols, conn) {
const ms = new multistream.Listener()
Object.keys(protocols).forEach((protocol) => {
if (!protocol) {
return
}
ms.addHandler(protocol, protocols[protocol])
})
ms.handle(conn, (err) => {
if (err) {
return // the multistream handshake failed
}
})
}

View File

@ -1,2 +0,0 @@
exports = module.exports = require('spdy-stream-muxer')
// exports = module.exports = require('multiplex-stream-muxer')

View File

@ -1,189 +0,0 @@
var tcp = require('net')
var Select = require('multistream-select').Select
var Interactive = require('multistream-select').Interactive
var Muxer = require('./stream-muxer')
var log = require('ipfs-logger').group('swarm')
var async = require('async')
var EventEmitter = require('events').EventEmitter
var util = require('util')
exports = module.exports = Swarm
util.inherits(Swarm, EventEmitter)
function Swarm () {
var self = this
if (!(self instanceof Swarm)) {
throw new Error('Swarm must be called with new')
}
self.port = parseInt(process.env.IPFS_SWARM_PORT, 10) || 4001
self.connections = {} // {peerIdB58: {conn: <>, socket: <>}
self.handles = {}
// set the listener
self.listen = function (port, ready) {
if (!ready) {
ready = function noop () {}
}
if (typeof port === 'function') {
ready = port
} else if (port) { self.port = port }
//
self.listener = tcp.createServer(function (socket) {
errorUp(self, socket)
var ms = new Select()
ms.handle(socket)
ms.addHandler('/spdy/3.1.0', function (ds) {
log.info('Negotiated spdy with incoming socket')
var conn = new Muxer().attach(ds, true)
// attach multistream handlers to incoming streams
conn.on('stream', registerHandles)
errorUp(self, conn)
// FOR IDENTIFY
self.emit('connection-unknown', conn, socket)
// IDENTIFY DOES THIS FOR US
// conn.on('close', function () { delete self.connections[conn.peerId] })
})
}).listen(self.port, ready)
errorUp(self, self.listener)
}
// interface
// open stream account for connection reuse
self.openConnection = function (peer, cb) {
// If no connection open yet, open it
if (!self.connections[peer.id.toB58String()]) {
// Establish a socket with one of the addresses
var socket
async.eachSeries(peer.multiaddrs, function (multiaddr, next) {
if (socket) { return next() }
var tmp = tcp.connect(multiaddr.toOptions(), function () {
socket = tmp
errorUp(self, socket)
next()
})
tmp.once('error', function (err) {
log.warn(multiaddr.toString(), 'on', peer.id.toB58String(), 'not available', err)
next()
})
}, function done () {
if (!socket) {
return cb(new Error('Not able to open a scoket with peer - ',
peer.id.toB58String()))
}
gotSocket(socket)
})
} else {
cb()
}
// do the spdy people dance (multistream-select into spdy)
function gotSocket (socket) {
var msi = new Interactive()
msi.handle(socket, function () {
msi.select('/spdy/3.1.0', function (err, ds) {
if (err) { cb(err) }
var conn = new Muxer().attach(ds, false)
conn.on('stream', registerHandles)
self.connections[peer.id.toB58String()] = {
conn: conn,
socket: socket
}
conn.on('close', function () { delete self.connections[peer.id.toB58String()]})
errorUp(self, conn)
cb()
})
})
}
}
self.openStream = function (peer, protocol, cb) {
self.openConnection(peer, function (err) {
if (err) {
return cb(err)
}
// spawn new muxed stream
var conn = self.connections[peer.id.toB58String()].conn
conn.dialStream(function (err, stream) {
if (err) { return cb(err) }
errorUp(self, stream)
// negotiate desired protocol
var msi = new Interactive()
msi.handle(stream, function () {
msi.select(protocol, function (err, ds) {
if (err) { return cb(err) }
peer.lastSeen = new Date()
cb(null, ds) // return the stream
})
})
})
})
}
self.registerHandler = function (protocol, handlerFunc) {
if (self.handles[protocol]) {
return handlerFunc(new Error('Handle for protocol already exists', protocol))
}
self.handles[protocol] = handlerFunc
log.info('Registered handler for protocol:', protocol)
}
self.closeConns = function (cb) {
var keys = Object.keys(self.connections)
var number = keys.length
if (number === 0) { cb() }
var c = new Counter(number, cb)
keys.forEach(function (key) {
self.connections[key].conn.end()
c.hit()
})
}
self.closeListener = function (cb) {
self.listener.close(cb)
}
function registerHandles (stream) {
log.info('Registering protocol handlers on new stream')
errorUp(self, stream)
var msH = new Select()
msH.handle(stream)
Object.keys(self.handles).forEach(function (protocol) {
msH.addHandler(protocol, self.handles[protocol])
})
}
}
function errorUp (self, emitter) {
emitter.on('error', function (err) {
self.emit('error', err)
})
}
function Counter (target, callback) {
var c = 0
this.hit = count
function count () {
c += 1
if (c === target) { callback() }
}
}

154
src/transport.js Normal file
View File

@ -0,0 +1,154 @@
'use strict'
const Connection = require('interface-connection').Connection
const parallel = require('run-parallel')
const debug = require('debug')
const log = debug('libp2p:swarm')
const protocolMuxer = require('./protocol-muxer')
module.exports = function (swarm) {
return {
add (key, transport, options, callback) {
if (typeof options === 'function') {
callback = options
options = {}
}
if (!callback) { callback = noop }
if (swarm.transports[key]) {
throw new Error('There is already a transport with this key')
}
swarm.transports[key] = transport
if (!swarm.transports[key].listeners) {
swarm.transports[key].listeners = []
}
callback()
},
dial (key, multiaddrs, callback) {
const t = swarm.transports[key]
if (!Array.isArray(multiaddrs)) {
multiaddrs = [multiaddrs]
}
// a) filter the multiaddrs that are actually valid for this transport (use a func from the transport itself) (maybe even make the transport do that)
multiaddrs = dialables(t, multiaddrs)
// b) if multiaddrs.length = 1, return the conn from the
// transport, otherwise, create a passthrough
if (multiaddrs.length === 1) {
const conn = t.dial(multiaddrs.shift())
conn.once('error', connectError)
conn.once('connect', () => {
conn.removeListener('error', connectError)
callback(null, conn)
})
return conn
}
function connectError () {
callback(new Error('failed to connect to every multiaddr'))
}
// c) multiaddrs should already be a filtered list
// specific for the transport we are using
const proxyConn = new Connection()
next(multiaddrs.shift())
return proxyConn
// TODO improve in the future to make all the dials in paralell
function next (multiaddr) {
const conn = t.dial(multiaddr)
conn.once('error', connectError)
function connectError () {
if (multiaddrs.length === 0) {
return callback(new Error('failed to connect to every multiaddr'))
}
next(multiaddrs.shift())
}
conn.once('connect', () => {
conn.removeListener('error', connectError)
proxyConn.setInnerConn(conn)
callback(null, proxyConn)
})
}
},
listen (key, options, handler, callback) {
// if no handler is passed, we pass conns to protocolMuxer
if (!handler) {
handler = protocolMuxer.bind(null, swarm.protocols)
}
const multiaddrs = dialables(swarm.transports[key], swarm._peerInfo.multiaddrs)
const transport = swarm.transports[key]
if (!transport.listeners) {
transport.listeners = []
}
let freshMultiaddrs = []
const createListeners = multiaddrs.map((ma) => {
return (cb) => {
const listener = transport.createListener(handler)
listener.listen(ma, () => {
log('Listener started on:', ma.toString())
listener.getAddrs((err, addrs) => {
if (err) {
return cb(err)
}
freshMultiaddrs = freshMultiaddrs.concat(addrs)
transport.listeners.push(listener)
cb()
})
})
}
})
parallel(createListeners, () => {
// cause we can listen on port 0 or 0.0.0.0
swarm._peerInfo.multiaddr.replace(multiaddrs, freshMultiaddrs)
callback()
})
},
close (key, callback) {
const transport = swarm.transports[key]
if (!transport) {
return callback(new Error(`Trying to close non existing transport: ${key}`))
}
parallel(transport.listeners.map((listener) => {
return (cb) => {
listener.close(cb)
}
}), callback)
}
}
}
function dialables (tp, multiaddrs) {
return tp.filter(multiaddrs.map((addr) => {
// webrtc-star needs the /ipfs/QmHash
if (addr.toString().indexOf('webrtc-star') > 0) {
return addr
}
return addr
}))
}
function noop () {}

12
test/00-instance.node.js Normal file
View File

@ -0,0 +1,12 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const Swarm = require('../src')
describe('create Swarm instance', () => {
it('throws on missing peerInfo', () => {
expect(() => Swarm()).to.throw(Error)
})
})

View File

@ -0,0 +1,175 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const parallel = require('run-parallel')
const multiaddr = require('multiaddr')
const Peer = require('peer-info')
const Swarm = require('../src')
const TCP = require('libp2p-tcp')
const bl = require('bl')
describe('transport - tcp', function () {
this.timeout(10000)
var swarmA
var swarmB
var peerA = new Peer()
var peerB = new Peer()
before((done) => {
peerA.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9888'))
peerB.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9999'))
swarmA = new Swarm(peerA)
swarmB = new Swarm(peerB)
done()
})
it('add', (done) => {
swarmA.transport.add('tcp', new TCP())
expect(Object.keys(swarmA.transports).length).to.equal(1)
swarmB.transport.add('tcp', new TCP(), () => {
expect(Object.keys(swarmB.transports).length).to.equal(1)
done()
})
})
it('listen', (done) => {
var count = 0
swarmA.transport.listen('tcp', {}, (conn) => {
conn.pipe(conn)
}, ready)
swarmB.transport.listen('tcp', {}, (conn) => {
conn.pipe(conn)
}, ready)
function ready () {
if (++count === 2) {
expect(peerA.multiaddrs.length).to.equal(1)
expect(
peerA.multiaddrs[0].equals(multiaddr('/ip4/127.0.0.1/tcp/9888'))
).to.be.equal(
true
)
expect(peerB.multiaddrs.length).to.equal(1)
expect(
peerB.multiaddrs[0].equals(multiaddr('/ip4/127.0.0.1/tcp/9999'))
).to.be.equal(
true
)
done()
}
}
})
it('dial to a multiaddr', (done) => {
const conn = swarmA.transport.dial('tcp', multiaddr('/ip4/127.0.0.1/tcp/9999'), (err, conn) => {
expect(err).to.not.exist
})
conn.pipe(bl((err, data) => {
expect(err).to.not.exist
done()
}))
conn.write('hey')
conn.end()
})
it('dial to set of multiaddr, only one is available', (done) => {
const conn = swarmA.transport.dial('tcp', [
multiaddr('/ip4/127.0.0.1/tcp/9910/ws'), // not valid on purpose
multiaddr('/ip4/127.0.0.1/tcp/9910'),
multiaddr('/ip4/127.0.0.1/tcp/9999'),
multiaddr('/ip4/127.0.0.1/tcp/9309')
], (err, conn) => {
expect(err).to.not.exist
})
conn.pipe(bl((err, data) => {
expect(err).to.not.exist
done()
}))
conn.write('hey')
conn.end()
})
it('close', (done) => {
parallel([
(cb) => swarmA.transport.close('tcp', cb),
(cb) => swarmB.transport.close('tcp', cb)
], done)
})
it('support port 0', (done) => {
var swarm
var peer = new Peer()
peer.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/0'))
swarm = new Swarm(peer)
swarm.transport.add('tcp', new TCP())
swarm.transport.listen('tcp', {}, (conn) => {
conn.pipe(conn)
}, ready)
function ready () {
expect(peer.multiaddrs.length).to.equal(1)
expect(peer.multiaddrs[0]).to.not.deep.equal(multiaddr('/ip4/127.0.0.1/tcp/0'))
swarm.close(done)
}
})
it('support addr /ip4/0.0.0.0/tcp/9050', (done) => {
var swarm
var peer = new Peer()
peer.multiaddr.add(multiaddr('/ip4/0.0.0.0/tcp/9050'))
swarm = new Swarm(peer)
swarm.transport.add('tcp', new TCP())
swarm.transport.listen('tcp', {}, (conn) => {
conn.pipe(conn)
}, ready)
function ready () {
expect(peer.multiaddrs.length >= 1).to.equal(true)
expect(
peer.multiaddrs[0].equals(multiaddr('/ip4/127.0.0.1/tcp/9050'))
).to.be.equal(
true
)
swarm.close(done)
}
})
it('support addr /ip4/0.0.0.0/tcp/0', (done) => {
var swarm
var peer = new Peer()
peer.multiaddr.add(multiaddr('/ip4/0.0.0.0/tcp/0'))
swarm = new Swarm(peer)
swarm.transport.add('tcp', new TCP())
swarm.transport.listen('tcp', {}, (conn) => {
conn.pipe(conn)
}, ready)
function ready () {
expect(peer.multiaddrs.length >= 1).to.equal(true)
expect(peer.multiaddrs[0]).to.not.deep.equal(multiaddr('/ip4/0.0.0.0/tcp/0'))
swarm.close(done)
}
})
it('listen in several addrs', (done) => {
var swarm
var peer = new Peer()
peer.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9001'))
peer.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9002'))
peer.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9003'))
swarm = new Swarm(peer)
swarm.transport.add('tcp', new TCP())
swarm.transport.listen('tcp', {}, (conn) => {
conn.pipe(conn)
}, ready)
function ready () {
expect(peer.multiaddrs.length).to.equal(3)
swarm.close(done)
}
})
})

View File

@ -0,0 +1,13 @@
/* eslint-env mocha */
'use strict'
describe('transport - utp', function () {
this.timeout(10000)
before((done) => { done() })
it.skip('add', (done) => {})
it.skip('listen', (done) => {})
it.skip('dial', (done) => {})
it.skip('close', (done) => {})
})

View File

@ -0,0 +1,93 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const parallel = require('run-parallel')
const multiaddr = require('multiaddr')
const Peer = require('peer-info')
const Swarm = require('../src')
const WebSockets = require('libp2p-websockets')
const bl = require('bl')
describe('transport - websockets', function () {
this.timeout(10000)
var swarmA
var swarmB
var peerA = new Peer()
var peerB = new Peer()
before(() => {
peerA.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9888/ws'))
peerB.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9999/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC'))
swarmA = new Swarm(peerA)
swarmB = new Swarm(peerB)
})
it('add', (done) => {
swarmA.transport.add('ws', new WebSockets())
expect(Object.keys(swarmA.transports).length).to.equal(1)
swarmB.transport.add('ws', new WebSockets(), () => {
expect(Object.keys(swarmB.transports).length).to.equal(1)
done()
})
})
it('listen', (done) => {
parallel([
(cb) => swarmA.transport.listen('ws', {}, (conn) => {
conn.pipe(conn)
}, cb),
(cb) => swarmB.transport.listen('ws', {}, (conn) => {
conn.pipe(conn)
}, cb)
], () => {
expect(peerA.multiaddrs.length).to.equal(1)
expect(
peerA.multiaddrs[0].equals(multiaddr('/ip4/127.0.0.1/tcp/9888/ws'))
).to.be.equal(
true
)
expect(peerB.multiaddrs.length).to.equal(1)
expect(
peerB.multiaddrs[0].equals(multiaddr('/ip4/127.0.0.1/tcp/9999/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC'))
).to.equal(
true
)
done()
})
})
it('dial', (done) => {
const conn = swarmA.transport.dial('ws', multiaddr('/ip4/127.0.0.1/tcp/9999/ws'), (err, conn) => {
expect(err).to.not.exist
})
conn.pipe(bl((err, data) => {
expect(err).to.not.exist
done()
}))
conn.write('hey')
conn.end()
})
it('dial (conn from callback)', (done) => {
swarmA.transport.dial('ws', multiaddr('/ip4/127.0.0.1/tcp/9999/ws'), (err, conn) => {
expect(err).to.not.exist
conn.pipe(bl((err, data) => {
expect(err).to.not.exist
done()
}))
conn.write('hey')
conn.end()
})
})
it('close', (done) => {
parallel([
(cb) => swarmA.transport.close('ws', cb),
(cb) => swarmB.transport.close('ws', cb)
], done)
})
})

View File

@ -0,0 +1,120 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const parallel = require('run-parallel')
const multiaddr = require('multiaddr')
const Peer = require('peer-info')
const Swarm = require('../src')
const TCP = require('libp2p-tcp')
const multiplex = require('libp2p-spdy')
// TODO multiplex needs to be upgraded, like spdy, to work again
describe.skip('stream muxing with multiplex (on TCP)', function () {
this.timeout(60 * 1000)
var swarmA
var peerA
var swarmB
var peerB
var swarmC
var peerC
before((done) => {
peerA = new Peer()
peerB = new Peer()
peerC = new Peer()
// console.log('peer A', peerA.id.toB58String())
// console.log('peer B', peerB.id.toB58String())
// console.log('peer C', peerC.id.toB58String())
peerA.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9001'))
peerB.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9002'))
peerC.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9003'))
swarmA = new Swarm(peerA)
swarmB = new Swarm(peerB)
swarmC = new Swarm(peerC)
swarmA.transport.add('tcp', new TCP())
swarmB.transport.add('tcp', new TCP())
swarmC.transport.add('tcp', new TCP())
parallel([
(cb) => swarmA.transport.listen('tcp', {}, null, cb),
(cb) => swarmB.transport.listen('tcp', {}, null, cb),
(cb) => swarmC.transport.listen('tcp', {}, null, cb)
], done)
})
after((done) => {
parallel([
(cb) => swarmA.close(cb),
(cb) => swarmB.close(cb),
(cb) => swarmC.close(cb)
], done)
})
it('add', (done) => {
swarmA.connection.addStreamMuxer(multiplex)
swarmB.connection.addStreamMuxer(multiplex)
swarmC.connection.addStreamMuxer(multiplex)
done()
})
it('handle + dial on protocol', (done) => {
swarmB.handle('/abacaxi/1.0.0', (conn) => {
conn.pipe(conn)
})
swarmA.dial(peerB, '/abacaxi/1.0.0', (err, conn) => {
expect(err).to.not.exist
expect(Object.keys(swarmA.muxedConns).length).to.equal(1)
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
})
it('dial to warm conn', (done) => {
swarmB.dial(peerA, (err) => {
expect(err).to.not.exist
expect(Object.keys(swarmB.conns).length).to.equal(0)
expect(Object.keys(swarmB.muxedConns).length).to.equal(1)
done()
})
})
it('dial on protocol, reuse warmed conn', (done) => {
swarmA.handle('/papaia/1.0.0', (conn) => {
conn.pipe(conn)
})
swarmB.dial(peerA, '/papaia/1.0.0', (err, conn) => {
expect(err).to.not.exist
expect(Object.keys(swarmB.conns).length).to.equal(0)
expect(Object.keys(swarmB.muxedConns).length).to.equal(1)
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
})
it('enable identify to reuse incomming muxed conn', (done) => {
swarmA.connection.reuse()
swarmC.connection.reuse()
swarmC.dial(peerA, (err) => {
expect(err).to.not.exist
setTimeout(() => {
expect(Object.keys(swarmC.muxedConns).length).to.equal(1)
expect(Object.keys(swarmA.muxedConns).length).to.equal(2)
done()
}, 500)
})
})
})

244
test/05-muxing-spdy.node.js Normal file
View File

@ -0,0 +1,244 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const parallel = require('run-parallel')
const multiaddr = require('multiaddr')
const Peer = require('peer-info')
const Swarm = require('../src')
const TCP = require('libp2p-tcp')
const WebSockets = require('libp2p-websockets')
const spdy = require('libp2p-spdy')
describe('stream muxing with spdy (on TCP)', function () {
this.timeout(60 * 1000)
var swarmA
var peerA
var swarmB
var peerB
var swarmC
var peerC
var swarmD
var peerD
before((done) => {
peerA = new Peer()
peerB = new Peer()
peerC = new Peer()
peerD = new Peer()
// console.log('peer A', peerA.id.toB58String())
// console.log('peer B', peerB.id.toB58String())
// console.log('peer C', peerC.id.toB58String())
peerA.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9001'))
peerB.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9002'))
peerC.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9003'))
peerD.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9004'))
swarmA = new Swarm(peerA)
swarmB = new Swarm(peerB)
swarmC = new Swarm(peerC)
swarmD = new Swarm(peerD)
swarmA.transport.add('tcp', new TCP())
swarmB.transport.add('tcp', new TCP())
swarmC.transport.add('tcp', new TCP())
swarmD.transport.add('tcp', new TCP())
parallel([
(cb) => swarmA.transport.listen('tcp', {}, null, cb),
(cb) => swarmB.transport.listen('tcp', {}, null, cb),
(cb) => swarmC.transport.listen('tcp', {}, null, cb),
(cb) => swarmD.transport.listen('tcp', {}, null, cb)
], done)
})
after((done) => {
parallel([
(cb) => swarmA.close(cb),
(cb) => swarmB.close(cb),
// (cb) => swarmC.close(cb)
(cb) => swarmD.close(cb)
], done)
})
it('add', () => {
swarmA.connection.addStreamMuxer(spdy)
swarmB.connection.addStreamMuxer(spdy)
swarmC.connection.addStreamMuxer(spdy)
swarmD.connection.addStreamMuxer(spdy)
})
it('handle + dial on protocol', (done) => {
swarmB.handle('/abacaxi/1.0.0', (conn) => {
conn.pipe(conn)
})
swarmA.dial(peerB, '/abacaxi/1.0.0', (err, conn) => {
expect(err).to.not.exist
expect(Object.keys(swarmA.muxedConns).length).to.equal(1)
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
})
it('dial to warm conn', (done) => {
swarmB.dial(peerA, (err) => {
expect(err).to.not.exist
expect(Object.keys(swarmB.conns).length).to.equal(0)
expect(Object.keys(swarmB.muxedConns).length).to.equal(1)
done()
})
})
it('dial on protocol, reuse warmed conn', (done) => {
swarmA.handle('/papaia/1.0.0', (conn) => {
conn.pipe(conn)
})
swarmB.dial(peerA, '/papaia/1.0.0', (err, conn) => {
expect(err).to.not.exist
expect(Object.keys(swarmB.conns).length).to.equal(0)
expect(Object.keys(swarmB.muxedConns).length).to.equal(1)
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
})
it('enable identify to reuse incomming muxed conn', (done) => {
swarmA.connection.reuse()
swarmC.connection.reuse()
swarmC.dial(peerA, (err) => {
expect(err).to.not.exist
setTimeout(() => {
expect(Object.keys(swarmC.muxedConns).length).to.equal(1)
expect(Object.keys(swarmA.muxedConns).length).to.equal(2)
done()
}, 500)
})
})
it('with Identify, do getPeerInfo', (done) => {
swarmA.handle('/banana/1.0.0', (conn) => {
conn.getPeerInfo((err, peerInfoC) => {
expect(err).to.not.exist
expect(peerInfoC.id.toB58String()).to.equal(peerC.id.toB58String())
})
conn.pipe(conn)
})
swarmC.dial(peerA, '/banana/1.0.0', (err, conn) => {
expect(err).to.not.exist
setTimeout(() => {
expect(Object.keys(swarmC.muxedConns).length).to.equal(1)
expect(Object.keys(swarmA.muxedConns).length).to.equal(2)
conn.getPeerInfo((err, peerInfoA) => {
expect(err).to.not.exist
expect(peerInfoA.id.toB58String()).to.equal(peerA.id.toB58String())
conn.on('end', done)
conn.resume()
conn.end()
})
}, 500)
})
})
// This test is not possible as the raw conn is not exposed anymore
// TODO: create a similar version, but that spawns a swarm in a
// different proc
it.skip('make sure it does not blow up when the socket is closed', (done) => {
swarmD.connection.reuse()
let count = 0
const destroyed = () => ++count === 2 ? done() : null
swarmD.handle('/banana/1.0.0', (conn) => {
conn.on('error', () => {})
conn.on('close', destroyed)
})
swarmA.dial(peerD, '/banana/1.0.0', (err, conn) => {
expect(err).to.not.exist
conn.on('error', () => {})
conn.on('close', destroyed)
swarmD.muxedConns[peerA.id.toB58String()].conn.destroy()
})
})
// This test is not possible as the raw conn is not exposed anymore
// TODO: create a similar version, but that spawns a swarm in a
// different proc
it.skip('blow up a socket, with WebSockets', (done) => {
var swarmE
var peerE
var swarmF
var peerF
peerE = new Peer()
peerF = new Peer()
peerE.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9110/ws'))
peerF.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9120/ws'))
swarmE = new Swarm(peerE)
swarmF = new Swarm(peerF)
swarmE.transport.add('ws', new WebSockets())
swarmF.transport.add('ws', new WebSockets())
swarmE.connection.addStreamMuxer(spdy)
swarmF.connection.addStreamMuxer(spdy)
swarmE.connection.reuse()
swarmF.connection.reuse()
parallel([
(cb) => swarmE.transport.listen('ws', {}, null, cb),
(cb) => swarmF.transport.listen('ws', {}, null, cb)
], next)
function next () {
let count = 0
const destroyed = () => ++count === 2 ? close() : null
swarmE.handle('/avocado/1.0.0', (conn) => {
conn.on('error', () => {})
conn.on('close', destroyed)
})
swarmF.dial(peerE, '/avocado/1.0.0', (err, conn) => {
expect(err).to.not.exist
conn.on('error', () => {})
conn.on('close', destroyed)
swarmF.muxedConns[peerE.id.toB58String()].conn.destroy()
})
}
function close () {
parallel([
(cb) => swarmE.close(cb),
(cb) => swarmF.close(cb)
], done)
}
})
it('close one end, make sure the other does not blow', (done) => {
swarmC.close((err) => {
if (err) throw err
// to make sure it has time to propagate
setTimeout(done, 1000)
})
})
})

View File

@ -0,0 +1,10 @@
/* eslint-env mocha */
'use strict'
describe('secio conn upgrade (on TCP)', function () {
this.timeout(20000)
it.skip('add', (done) => {})
it.skip('dial', (done) => {})
it.skip('tls on a muxed stream (not the full conn)', (done) => {})
})

View File

@ -0,0 +1,8 @@
/* eslint-env mocha */
'use strict'
describe('tls conn upgrade (on TCP)', function () {
it.skip('add', (done) => {})
it.skip('dial', (done) => {})
it.skip('tls on a muxed stream (not the full conn)', (done) => {})
})

View File

@ -0,0 +1,102 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const parallel = require('run-parallel')
const multiaddr = require('multiaddr')
const Peer = require('peer-info')
const Swarm = require('../src')
const TCP = require('libp2p-tcp')
describe('high level API - 1st without stream multiplexing (on TCP)', function () {
this.timeout(20000)
var swarmA
var peerA
var swarmB
var peerB
before((done) => {
peerA = new Peer()
peerB = new Peer()
peerA.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9001'))
peerB.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9002/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC'))
swarmA = new Swarm(peerA)
swarmB = new Swarm(peerB)
swarmA.transport.add('tcp', new TCP())
swarmB.transport.add('tcp', new TCP())
parallel([
(cb) => swarmA.transport.listen('tcp', {}, null, cb),
(cb) => swarmB.transport.listen('tcp', {}, null, cb)
], done)
})
after((done) => {
parallel([
(cb) => swarmA.close(cb),
(cb) => swarmB.close(cb)
], done)
})
it('handle a protocol', (done) => {
swarmB.handle('/bananas/1.0.0', (conn) => {
conn.pipe(conn)
})
expect(Object.keys(swarmB.protocols).length).to.equal(2)
done()
})
it('dial on protocol', (done) => {
swarmB.handle('/pineapple/1.0.0', (conn) => {
conn.pipe(conn)
})
swarmA.dial(peerB, '/pineapple/1.0.0', (err, conn) => {
expect(err).to.not.exist
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
})
it('dial on protocol (returned conn)', (done) => {
swarmB.handle('/apples/1.0.0', (conn) => {
conn.pipe(conn)
})
const conn = swarmA.dial(peerB, '/apples/1.0.0', (err) => {
expect(err).to.not.exist
})
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
it('dial to warm a conn', (done) => {
swarmA.dial(peerB, (err) => {
expect(err).to.not.exist
done()
})
})
it('dial on protocol, reuse warmed conn', (done) => {
swarmA.dial(peerB, '/bananas/1.0.0', (err, conn) => {
expect(err).to.not.exist
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
})
it('unhandle', (done) => {
const proto = '/bananas/1.0.0'
swarmA.unhandle(proto)
expect(swarmA.protocols[proto]).to.not.exist
done()
})
})

View File

@ -0,0 +1,248 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const parallel = require('run-parallel')
const multiaddr = require('multiaddr')
const Peer = require('peer-info')
const Swarm = require('../src')
const TCP = require('libp2p-tcp')
const WebSockets = require('libp2p-websockets')
const spdy = require('libp2p-spdy')
describe('high level API - with everything mixed all together!', function () {
this.timeout(100000)
var swarmA // tcp
var peerA
var swarmB // tcp+ws
var peerB
var swarmC // tcp+ws
var peerC
var swarmD // ws
var peerD
var swarmE // ws
var peerE
before((done) => {
peerA = new Peer()
peerB = new Peer()
peerC = new Peer()
peerD = new Peer()
peerE = new Peer()
// console.log('peer A', peerA.id.toB58String())
// console.log('peer B', peerB.id.toB58String())
// console.log('peer C', peerC.id.toB58String())
swarmA = new Swarm(peerA)
swarmB = new Swarm(peerB)
swarmC = new Swarm(peerC)
swarmD = new Swarm(peerD)
swarmE = new Swarm(peerE)
done()
})
after((done) => {
parallel([
(cb) => swarmA.close(cb),
(cb) => swarmB.close(cb),
// (cb) => swarmC.close(cb),
(cb) => swarmD.close(cb),
(cb) => swarmE.close(cb)
], done)
})
it('add tcp', (done) => {
peerA.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/0'))
peerB.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/0'))
peerC.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/0'))
swarmA.transport.add('tcp', new TCP())
swarmB.transport.add('tcp', new TCP())
swarmC.transport.add('tcp', new TCP())
parallel([
(cb) => swarmA.transport.listen('tcp', {}, null, cb),
(cb) => swarmB.transport.listen('tcp', {}, null, cb)
// (cb) => swarmC.transport.listen('tcp', {}, null, cb)
], done)
})
it.skip('add utp', (done) => {})
it('add websockets', (done) => {
peerB.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9012/ws'))
peerC.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9022/ws'))
peerD.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9032/ws'))
peerE.multiaddr.add(multiaddr('/ip4/127.0.0.1/tcp/9042/ws'))
swarmB.transport.add('ws', new WebSockets())
swarmC.transport.add('ws', new WebSockets())
swarmD.transport.add('ws', new WebSockets())
swarmE.transport.add('ws', new WebSockets())
parallel([
(cb) => swarmB.transport.listen('ws', {}, null, cb),
// (cb) => swarmC.transport.listen('ws', {}, null, cb),
(cb) => swarmD.transport.listen('ws', {}, null, cb),
(cb) => swarmE.transport.listen('ws', {}, null, cb)
], done)
})
it('listen automatically', (done) => {
swarmC.listen(done)
})
it('add spdy', () => {
swarmA.connection.addStreamMuxer(spdy)
swarmB.connection.addStreamMuxer(spdy)
swarmC.connection.addStreamMuxer(spdy)
swarmD.connection.addStreamMuxer(spdy)
swarmE.connection.addStreamMuxer(spdy)
swarmA.connection.reuse()
swarmB.connection.reuse()
swarmC.connection.reuse()
swarmD.connection.reuse()
swarmE.connection.reuse()
})
it.skip('add multiplex', () => {})
it('warm up from A to B on tcp to tcp+ws', (done) => {
parallel([
(cb) => swarmB.once('peer-mux-established', (peerInfo) => {
expect(peerInfo.id.toB58String()).to.equal(peerA.id.toB58String())
cb()
}),
(cb) => swarmA.once('peer-mux-established', (peerInfo) => {
expect(peerInfo.id.toB58String()).to.equal(peerB.id.toB58String())
cb()
}),
(cb) => swarmA.dial(peerB, (err) => {
expect(err).to.not.exist
expect(Object.keys(swarmA.muxedConns).length).to.equal(1)
cb()
})
], done)
})
it('warm up a warmed up, from B to A', (done) => {
swarmB.dial(peerA, (err) => {
expect(err).to.not.exist
expect(Object.keys(swarmA.muxedConns).length).to.equal(1)
done()
})
})
it('dial from tcp to tcp+ws, on protocol', (done) => {
swarmB.handle('/anona/1.0.0', (conn) => {
conn.pipe(conn)
})
swarmA.dial(peerB, '/anona/1.0.0', (err, conn) => {
expect(err).to.not.exist
expect(Object.keys(swarmA.muxedConns).length).to.equal(1)
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
})
it('dial from ws to ws no proto', (done) => {
swarmD.dial(peerE, (err) => {
expect(err).to.not.exist
expect(Object.keys(swarmD.muxedConns).length).to.equal(1)
done()
})
})
it('dial from ws to ws', (done) => {
swarmE.handle('/abacaxi/1.0.0', (conn) => {
conn.pipe(conn)
})
swarmD.dial(peerE, '/abacaxi/1.0.0', (err, conn) => {
expect(err).to.not.exist
expect(Object.keys(swarmD.muxedConns).length).to.equal(1)
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', () => {
setTimeout(() => {
expect(Object.keys(swarmE.muxedConns).length).to.equal(1)
done()
}, 1000)
})
})
})
it('dial from tcp to tcp+ws (returned conn)', (done) => {
swarmB.handle('/grapes/1.0.0', (conn) => {
conn.pipe(conn)
})
const conn = swarmA.dial(peerB, '/grapes/1.0.0', (err, conn) => {
expect(err).to.not.exist
expect(Object.keys(swarmA.muxedConns).length).to.equal(1)
})
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
it('dial from tcp+ws to tcp+ws', (done) => {
swarmC.handle('/mamao/1.0.0', (conn) => {
conn.getPeerInfo((err, peerInfo) => {
expect(err).to.not.exist
expect(peerInfo).to.exist
})
conn.pipe(conn)
})
swarmA.dial(peerC, '/mamao/1.0.0', (err, conn) => {
expect(err).to.not.exist
conn.getPeerInfo((err, peerInfo) => {
expect(err).to.not.exist
expect(peerInfo).to.exist
})
expect(Object.keys(swarmA.muxedConns).length).to.equal(2)
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
})
it('hangUp', (done) => {
let count = 0
const ready = () => ++count === 3 ? done() : null
swarmB.once('peer-mux-closed', (peerInfo) => {
expect(Object.keys(swarmB.muxedConns).length).to.equal(0)
ready()
})
swarmA.once('peer-mux-closed', (peerInfo) => {
expect(Object.keys(swarmA.muxedConns).length).to.equal(1)
ready()
})
swarmA.hangUp(peerB, (err) => {
expect(err).to.not.exist
ready()
})
})
it('close a muxer emits event', (done) => {
parallel([
(cb) => swarmC.close(cb),
(cb) => swarmA.once('peer-mux-closed', (peerInfo) => cb())
], done)
})
})

View File

@ -0,0 +1,48 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const multiaddr = require('multiaddr')
const Id = require('peer-id')
const Peer = require('peer-info')
const WebSockets = require('libp2p-websockets')
const bl = require('bl')
const Swarm = require('../src')
describe('transport - websockets', function () {
this.timeout(10000)
var swarm
before(() => {
const b58IdSrc = 'QmYzgdesgjdvD3okTPGZT9NPmh1BuH5FfTVNKjsvaAprhb'
// use a pre generated Id to save time
const idSrc = Id.createFromB58String(b58IdSrc)
const peerSrc = new Peer(idSrc)
swarm = new Swarm(peerSrc)
})
it('add', (done) => {
swarm.transport.add('ws', new WebSockets(), () => {
expect(Object.keys(swarm.transports).length).to.equal(1)
done()
})
})
it('dial', (done) => {
const ma = multiaddr('/ip4/127.0.0.1/tcp/9100/ws')
const conn = swarm.transport.dial('ws', ma, (err, conn) => {
expect(err).to.not.exist
})
conn.pipe(bl((err, data) => {
expect(err).to.not.exist
expect(data.toString()).to.equal('hey')
done()
}))
conn.write('hey')
conn.end()
})
})

View File

@ -0,0 +1,90 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const multiaddr = require('multiaddr')
const peerId = require('peer-id')
const PeerInfo = require('peer-info')
const WebRTCStar = require('libp2p-webrtc-star')
const bl = require('bl')
const parallel = require('run-parallel')
const Swarm = require('../src')
describe('transport - webrtc-star', function () {
this.timeout(10000)
let swarm1
let peer1
let swarm2
let peer2
before(() => {
const id1 = peerId.createFromB58String('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooooA')
peer1 = new PeerInfo(id1)
const mh1 = multiaddr('/libp2p-webrtc-star/ip4/127.0.0.1/tcp/15555/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooooA')
peer1.multiaddr.add(mh1)
const id2 = peerId.createFromB58String('QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooooB')
peer2 = new PeerInfo(id2)
const mh2 = multiaddr('/libp2p-webrtc-star/ip4/127.0.0.1/tcp/15555/ws/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSooooB')
peer2.multiaddr.add(mh2)
swarm1 = new Swarm(peer1)
swarm2 = new Swarm(peer2)
})
it('add WebRTCStar transport to swarm 1', (done) => {
swarm1.transport.add('wstar', new WebRTCStar(), () => {
expect(Object.keys(swarm1.transports).length).to.equal(1)
done()
})
})
it('add WebRTCStar transport to swarm 2', (done) => {
swarm2.transport.add('wstar', new WebRTCStar(), () => {
expect(Object.keys(swarm2.transports).length).to.equal(1)
done()
})
})
it('listen on swarm 1', (done) => {
swarm1.transport.listen('wstar', {}, (conn) => {
conn.pipe(conn)
}, done)
})
it('listen on swarm 2', (done) => {
swarm2.transport.listen('wstar', {}, (conn) => {
conn.pipe(conn)
}, done)
})
it('dial', (done) => {
swarm1.transport.dial('wstar', peer2.multiaddrs[0], (err, conn) => {
expect(err).to.not.exist
const text = 'Hello World'
conn.pipe(bl((err, data) => {
expect(err).to.not.exist
expect(data.toString()).to.equal(text)
done()
}))
conn.write(text)
conn.end()
})
})
it('close', (done) => {
parallel([
(cb) => {
swarm1.transport.close('wstar', cb)
},
(cb) => {
swarm2.transport.close('wstar', cb)
}
], done)
})
})

View File

@ -0,0 +1,74 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const multiaddr = require('multiaddr')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const WebSockets = require('libp2p-websockets')
const spdy = require('libp2p-spdy')
const fs = require('fs')
const path = require('path')
const Swarm = require('../src')
describe('high level API (swarm with spdy + websockets)', function () {
this.timeout(60 * 1000)
var swarm
var peerDst
before(() => {
const peerSrc = new PeerInfo()
swarm = new Swarm(peerSrc)
})
it('add spdy', () => {
swarm.connection.addStreamMuxer(spdy)
swarm.connection.reuse()
})
it('add ws', () => {
swarm.transport.add('ws', new WebSockets())
expect(Object.keys(swarm.transports).length).to.equal(1)
})
it('create Dst peer info', () => {
const id = PeerId.createFromJSON(
JSON.parse(
fs.readFileSync(
path.join(__dirname, './test-data/id-2.json'))))
peerDst = new PeerInfo(id)
const ma = multiaddr('/ip4/127.0.0.1/tcp/9200/ws')
peerDst.multiaddr.add(ma)
})
it('dial to warm a conn', (done) => {
swarm.dial(peerDst, (err) => {
expect(err).to.not.exist
done()
})
})
it('dial on protocol, use warmed conn', (done) => {
swarm.dial(peerDst, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist
conn.end()
conn.on('data', () => {}) // let it flow.. let it flooooow
conn.on('end', done)
})
})
it('close', (done) => {
// cause CI is slow
setTimeout(() => {
swarm.close(done)
}, 1000)
})
// TODO - test that the listener (node.js peer) can dial back
// do that by dialing on a protocol to activate that behaviour
// like libp2p-spdy tests
})

View File

@ -0,0 +1,129 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const multiaddr = require('multiaddr')
const peerId = require('peer-id')
const PeerInfo = require('peer-info')
const WebRTCStar = require('libp2p-webrtc-star')
const spdy = require('libp2p-spdy')
const bl = require('bl')
const parallel = require('run-parallel')
const Swarm = require('../src')
describe('high level API (swarm with spdy + webrtc-star)', function () {
this.timeout(60 * 1000)
let swarm1
let peer1
let wstar1
let swarm2
let peer2
let wstar2
before(() => {
const id1 = peerId.create()
peer1 = new PeerInfo(id1)
const mh1 = multiaddr('/libp2p-webrtc-star/ip4/127.0.0.1/tcp/15555/ws/ipfs/' + id1.toB58String())
peer1.multiaddr.add(mh1)
const id2 = peerId.create()
peer2 = new PeerInfo(id2)
const mh2 = multiaddr('/libp2p-webrtc-star/ip4/127.0.0.1/tcp/15555/ws/ipfs/' + id2.toB58String())
peer2.multiaddr.add(mh2)
swarm1 = new Swarm(peer1)
swarm2 = new Swarm(peer2)
})
it('add WebRTCStar transport to swarm 1', () => {
wstar1 = new WebRTCStar()
swarm1.transport.add('wstar', wstar1)
expect(Object.keys(swarm1.transports).length).to.equal(1)
})
it('add WebRTCStar transport to swarm 2', () => {
wstar2 = new WebRTCStar()
swarm2.transport.add('wstar', wstar2)
expect(Object.keys(swarm2.transports).length).to.equal(1)
})
it('listen on swarm 1', (done) => {
swarm1.listen(done)
})
it('listen on swarm 2', (done) => {
swarm2.listen(done)
})
it('add spdy', () => {
swarm1.connection.addStreamMuxer(spdy)
swarm1.connection.reuse()
swarm2.connection.addStreamMuxer(spdy)
swarm2.connection.reuse()
})
it('handle proto', () => {
swarm2.handle('/echo/1.0.0', (conn) => {
conn.pipe(conn)
})
})
it('dial on proto', (done) => {
swarm1.dial(peer2, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist
expect(Object.keys(swarm1.muxedConns).length).to.equal(1)
const text = 'Hello World'
conn.pipe(bl((err, data) => {
expect(err).to.not.exist
expect(data.toString()).to.equal(text)
expect(Object.keys(swarm2.muxedConns).length).to.equal(1)
done()
}))
conn.write(text)
conn.end()
})
})
it('create a third node and check that discovery works', (done) => {
wstar1.discovery.on('peer', (peerInfo) => {
expect(Object.keys(swarm1.muxedConns).length).to.equal(1)
swarm1.dial(peerInfo, () => {
expect(Object.keys(swarm1.muxedConns).length).to.equal(2)
})
})
wstar2.discovery.on('peer', (peerInfo) => {
swarm2.dial(peerInfo)
})
const id3 = peerId.create()
const peer3 = new PeerInfo(id3)
const mh3 = multiaddr('/libp2p-webrtc-star/ip4/127.0.0.1/tcp/15555/ws/ipfs/' + id3.toB58String())
peer3.multiaddr.add(mh3)
const swarm3 = new Swarm(peer3)
const wstar3 = new WebRTCStar()
swarm3.transport.add('wstar', wstar3)
swarm3.connection.addStreamMuxer(spdy)
swarm3.connection.reuse()
swarm3.listen(() => {
setTimeout(() => {
expect(Object.keys(swarm1.muxedConns).length).to.equal(2)
expect(Object.keys(swarm2.muxedConns).length).to.equal(2)
expect(Object.keys(swarm3.muxedConns).length).to.equal(2)
swarm3.close(done)
}, 8000)
})
})
it('close', (done) => {
parallel([
swarm1.close,
swarm2.close
], done)
})
})

27
test/browser.js Normal file
View File

@ -0,0 +1,27 @@
/* eslint-env mocha */
'use strict'
const expect = require('chai').expect
const w = require('webrtcsupport')
const Swarm = require('../src')
describe('basics', () => {
it('throws on missing peerInfo', (done) => {
expect(Swarm).to.throw(Error)
done()
})
})
require('./browser-00-transport-websockets.js')
if (w.support) {
require('./browser-01-transport-webrtc-star.js')
}
require('./browser-02-swarm-with-muxing-plus-websockets.js')
if (w.support) {
require('./browser-03-swarm-with-muxing-plus-webrtc-star.js')
require('./browser-04-swarm-with-muxing-plus-websockets-and-webrtc-star.js')
}

12
test/node.js Normal file
View File

@ -0,0 +1,12 @@
/* eslint-env mocha */
'use strict'
const fs = require('fs')
describe('libp2p-swarm', () => {
fs.readdirSync(__dirname)
.filter((file) => file.match(/\.node\.js$/))
.forEach((file) => {
require(`./${file}`)
})
})

5
test/test-data/id-1.json Normal file
View File

@ -0,0 +1,5 @@
{
"id": "QmYmfUS4A3E64BzU8DsCmCWpPhcXWU2KTKNRGtdtN4oCgU",
"privKey": "CAASqAkwggSkAgEAAoIBAQCYtGLh+ow9WEJMn50voPGa6MsqSgJx8pNXGtk5kMSktWxfYHrejLZJjN0+br2CwpFMtf9JW6dAIpxb3qViBCFXjzEK8JuYaXM2sHC6sapyCxeZUbZJtGAXNWQW3qV7m8s8cJTOu2s1euT/G6uf/mIVFIzCkQDx+Ejh5Aie+BTAEf1WbLmcoDDxVESe22gpTxtMG8WTocMV34BxKn8d8vhcZZsi8LLkjg172QwQr3Q68jKgdja3K1YYm6fnso6H3+H06IHgPFAvVhycBbmlyR3bL/hFBl6+ElwBxeIrlM/oAY93KCs622SLYWFHb+J2q7WofSbUSscp3gWj7c8KJqHvAgMBAAECggEBAJZi4BcpBj/L0c9gSg8D86zZomvNY0cQ3GYmPNPibKbBPS9Y9uiBr2wT3DeGHADQ2QOxIO7/4mDZNR+Mz1cONj/i9yuM9c9N2nd7oClcmz2hCualgF5p01BH9oBHWLW5IpgtT3+hN939X9SVTZpNjg6wpEdhQosKN8yvJIZaTyUvh/ZMRIJvbnbLg13gIF7Lpyn1rtFovQg0dET0C8zhTCDPacJIOLp8BIBMknPfOl0SrvOMZjufzVZLvbt0YraXhLK8EWe87ffTMoBlIktWpEKdPBOCuFf4E4WRXJ78tcbvNtx3f5zGi+ZVbKcLA1axu+OqbjHCG6yrlywcVBoTuxECgYEA56yDBaM0VFD1CqsqwYIWmAyYBjV7dkM+ogMb+mfQn+ja6QSt+U/APXB3dP+EDvysh5AZR0wpUrmz14xC1yB1/XAKIfMLQZB8DdUkuj5UcsKjkzLJkIFYGOXIutU7IHTma7s/0fLxwp8SvkEL+6nHuZskf77yjDAvWLZeSD/CYWsCgYEAqL0mKeyyhBBFvNJyE3CyyhDfzgf+NrvrNJcx73nAzLDE44BPc/3lHYn2AJJhasNnjJfRiFzW90PNgCjZLLXqeHkX4xixoibvRtb31WHR2UyxXe/KQZwBy11mPzStnI4Y83C2A8OXsx4xAPq69nX9foSFD6cuLkWUGeb8f7Jxbo0CgYB25mfcJdW+jEom7pAj/kLgSF5hmWNC3+IuPhBG5K8C0vw+6ULsmEyee7EjX9wD4RQfAwqmN+VhaqNtNbQ8OpGzv6PDprwZKzEv3DtcRo8K0vAmpMMkIe334T6y/Kq6zqRPmCt58gi4DPIOqM2gnJM/o+sIkRRkdHpoOjiLNgXp/wKBgQCNrGpLjwl/am4zEHppKhljIPHX+cwORo8/06ZAi/g9pDlbThLnr4fb2kaqyjxyuGfLmnh5xoFSkCINdb6KFJ8t0XYl3UjffVMvJjRle0EG8qaE2Vz24zZ6egvsC52ssX3vf3XDCUjoQfQg/2NUpVJWFIvnzZUvkom7ib38tWUZzQKBgDe0+OqdJEIdajkwCMEYbmZDYqkbw4pgmwSqCwK7HeCi8dvACW5OCCutnN0L57eEltyWy0XP2XmRlfsD0atkKBq3KgNfSawx6/t/K3OtZa8VAtg2M0PbCZljW/8Bz6xlxiyPXFTRgr9zr4yM1homMmPA39hURmXNNedXUh3IMkH7",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYtGLh+ow9WEJMn50voPGa6MsqSgJx8pNXGtk5kMSktWxfYHrejLZJjN0+br2CwpFMtf9JW6dAIpxb3qViBCFXjzEK8JuYaXM2sHC6sapyCxeZUbZJtGAXNWQW3qV7m8s8cJTOu2s1euT/G6uf/mIVFIzCkQDx+Ejh5Aie+BTAEf1WbLmcoDDxVESe22gpTxtMG8WTocMV34BxKn8d8vhcZZsi8LLkjg172QwQr3Q68jKgdja3K1YYm6fnso6H3+H06IHgPFAvVhycBbmlyR3bL/hFBl6+ElwBxeIrlM/oAY93KCs622SLYWFHb+J2q7WofSbUSscp3gWj7c8KJqHvAgMBAAE="
}

5
test/test-data/id-2.json Normal file
View File

@ -0,0 +1,5 @@
{
"id": "QmQAbW9j3wQ8JDFmg8JRid82EpZabuCngVDmhqzCmJwqt6",
"privKey": "CAASpgkwggSiAgEAAoIBAQCAQjiCzMF+PQaDUuNa7avUsj2xnNTQcUrs4yHz/L+JI/AY2ij0iXsBSE0chK1KtBu24gZzWs3/BDyNl28E0Sd41QpK6oTVMHjUfLovO+h7G78bqpI83vk5CEOKt29VihQs282fivbQb5ALYwzBIW2lsIoWwrQq1btsNA5NXJ43OAcPZ9SybBUg49f5gWf/kmh/J6e1rvwyVjQc7cmmpzcQUc+XNL7db6T3ArokXZMyBK6oQCOaJc1bqwgHwYSI3parjds9k8Z6fXA2ub3Va//1EgjQ50lRZH03PGYS42HR1QSSz1eLjMmdrbJrZZj7IbXgqAO6gT6wlGLr5xMQudabAgMBAAECggEAQ9NBESJ4fGqHJDFUG8St5pevelqGTAhtZ+IhFWamXz6K/Il5uP9u9dmnNZqQDX47XbYfVSdC4kX6Q6I+SlzUs9htTfrA7gBpFW00BEB5C4k7wcSs+tWrE9bj6NpiXOjdDG/cSC9zn/wvP2ZM22DzG/jEvY6POku2hlzs50pAPNB7bBaKysA/e52J0Tu/Wf/+sZyp2MiYQJmIkfbYeDF2rqm5y04S6Z31O3SMQIETNcBK8T+L2jwx+Q0msB8toam7hRf1KjxD0yZe+Vff9tPfwjgEoWF+O27g3+rjDq/QqUfzOPMgvAFgELBMpv6CCM8/3l9gUu+7itBxDq65sDCoCQKBgQC6FTLTQA3ux3WV0/7MKXJIHgYZ4b8lIbiiWuO/6t2ZnwvLfTbiU5br/8bcRPL5ygFuIdzkx8VHcbkOmld/VE7qaRZoJb94JVvC6N+5MQxr+pzbWQSNcE+cKJgy1RADea8nad698ifls/39kZGCc6Srt2TqxTBuoZ3c9jEMs3N2pwKBgQCwcxNSw7Wkq302lKc/7QdtfegrwlLjRClLYaW9ESQeErayRY8pxLgl/XKap1HPyc0aQ+78W6w+DAxvcToGBsLak0ujJjzP7b8G6fo+cexuIr8NiGL4LVzpZfQjkfQU4DDwsOdedeKzGelIdstMMtAZDFG9eNPe99XeJBnYfIDS7QKBgH8xFjiHQ/6+n4T2DueGPPNGcm0mfPzoe8ed0KbR5v6mU+2XfPheon5VqpvNFTff9/JLey11z0byWMe+f6gs/HQFuKcfhiydfIdRnfp7qD32Y1kbE52J8yCOLtowAG4fsrWCDBpRdyvvR+EWqxs76IbnKDfA6UX1em4aaZSA5J9pAoGAE8aB5ue6Rt9VZDWa3QZCq9nNmIHp6kCsZB9ohN0T8C7mvOog1myOuutB2eVgvOoAC66LbUsU7ctJ5X+KIjzFv9t8Qae6bw9VNoAopLD974YDZY/gj7H91Maxav8jnOdXdNJOy/5oTuxbgdyWgk67leMUkiiljjq2hHQFVYb2pS0CgYBam0ZJ5Trds1LijE2eoYPyiJdhWEsHYFDzoV17cyjhbSrmlWJBNKQfw6q6UtnxSNFMvsPOZv53d3B8iIDnZ/UHFvw1et+yQk/QrxTfXurqn8lJcMCfKzm3ORKibgJPMmtcPbLoxuEKXMXx18iwoCsMnapijJ0Qj5HofluiupSfxg==",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCAQjiCzMF+PQaDUuNa7avUsj2xnNTQcUrs4yHz/L+JI/AY2ij0iXsBSE0chK1KtBu24gZzWs3/BDyNl28E0Sd41QpK6oTVMHjUfLovO+h7G78bqpI83vk5CEOKt29VihQs282fivbQb5ALYwzBIW2lsIoWwrQq1btsNA5NXJ43OAcPZ9SybBUg49f5gWf/kmh/J6e1rvwyVjQc7cmmpzcQUc+XNL7db6T3ArokXZMyBK6oQCOaJc1bqwgHwYSI3parjds9k8Z6fXA2ub3Va//1EgjQ50lRZH03PGYS42HR1QSSz1eLjMmdrbJrZZj7IbXgqAO6gT6wlGLr5xMQudabAgMBAAE="
}

View File

@ -1,139 +0,0 @@
var Lab = require('lab')
var Code = require('code')
var lab = exports.lab = Lab.script()
var experiment = lab.experiment
var test = lab.test
var beforeEach = lab.beforeEach
var afterEach = lab.afterEach
var expect = Code.expect
var Muxer = require('./../src/stream-muxer.js')
var multistream = require('multistream-select')
var Interactive = multistream.Interactive
var Select = multistream.Select
var streamPair = require('stream-pair')
beforeEach(function (done) {
done()
})
afterEach(function (done) {
done()
})
experiment('MULTISTREAM AND STREAM MUXER', function () {
test('Open a socket and multistream-select it into spdy', function (done) {
var pair = streamPair.create()
var msI = new Interactive()
var msS = new Select()
var dialerMuxer = new Muxer()
var listenerMuxer = new Muxer()
msS.handle(pair.other)
msS.addHandler('/spdy/0.3.1', function (stream) {
var listenerConn = listenerMuxer.attach(stream, true)
expect(typeof listenerConn).to.be.equal('object')
done()
})
msI.handle(pair, function () {
msI.select('/spdy/0.3.1', function (err, stream) {
expect(err).to.not.be.instanceof(Error)
var dialerConn = dialerMuxer.attach(stream, false)
expect(typeof dialerConn).to.be.equal('object')
})
})
})
test('socket->ms-select into spdy->stream from dialer->ms-select into other protocol', function (done) {
var pair = streamPair.create()
var msI = new Interactive()
var msS = new Select()
var dialerMuxer = new Muxer()
var listenerMuxer = new Muxer()
msS.handle(pair.other)
msS.addHandler('/spdy/0.3.1', function (stream) {
var listenerConn = listenerMuxer.attach(stream, true)
listenerConn.on('stream', function (stream) {
stream.on('data', function (chunk) {
expect(chunk.toString()).to.equal('mux all the streams')
done()
})
})
})
msI.handle(pair, function () {
msI.select('/spdy/0.3.1', function (err, stream) {
expect(err).to.not.be.instanceof(Error)
var dialerConn = dialerMuxer.attach(stream, false)
dialerConn.dialStream(function (err, stream) {
expect(err).to.not.be.instanceof(Error)
stream.write('mux all the streams')
})
})
})
})
test('socket->ms-select into spdy->stream from listener->ms-select into another protocol', function (done) {
var pair = streamPair.create()
var msI = new Interactive()
var msS = new Select()
var dialerMuxer = new Muxer()
var listenerMuxer = new Muxer()
msS.handle(pair.other)
msS.addHandler('/spdy/0.3.1', function (stream) {
var listenerConn = listenerMuxer.attach(stream, true)
listenerConn.on('stream', function (stream) {
stream.on('data', function (chunk) {
expect(chunk.toString()).to.equal('mux all the streams')
listenerConn.dialStream(function (err, stream) {
expect(err).to.not.be.instanceof(Error)
var msI2 = new Interactive()
msI2.handle(stream, function () {
msI2.select('/other/protocol', function (err, stream) {
expect(err).to.not.be.instanceof(Error)
stream.write('the other protocol')
})
})
})
})
})
})
msI.handle(pair, function () {
msI.select('/spdy/0.3.1', function (err, stream) {
expect(err).to.not.be.instanceof(Error)
var dialerConn = dialerMuxer.attach(stream, false)
dialerConn.dialStream(function (err, stream) {
expect(err).to.not.be.instanceof(Error)
stream.write('mux all the streams')
})
dialerConn.on('stream', function (stream) {
var msS2 = new Select()
msS2.handle(stream)
msS2.addHandler('/other/protocol', function (stream) {
stream.on('data', function (chunk) {
expect(chunk.toString()).to.equal('the other protocol')
done()
})
})
})
})
})
})
})

View File

@ -1,221 +0,0 @@
var Lab = require('lab')
var Code = require('code')
var sinon = require('sinon')
var lab = exports.lab = Lab.script()
var experiment = lab.experiment
var test = lab.test
var beforeEach = lab.beforeEach
var afterEach = lab.afterEach
var expect = Code.expect
var multiaddr = require('multiaddr')
var Id = require('ipfs-peer-id')
var Peer = require('ipfs-peer')
var Swarm = require('../src/')
var Identify = require('../src/identify')
var swarmA
var swarmB
var peerA
var peerB
beforeEach(function (done) {
swarmA = new Swarm()
swarmB = new Swarm()
var c = new Counter(2, done)
swarmA.listen(8100, function () {
peerA = new Peer(Id.create(), [multiaddr('/ip4/127.0.0.1/tcp/' + swarmA.port)])
c.hit()
})
swarmB.listen(8101, function () {
peerB = new Peer(Id.create(), [multiaddr('/ip4/127.0.0.1/tcp/' + swarmB.port)])
c.hit()
})
})
afterEach(function (done) {
swarmA.closeListener()
swarmB.closeListener()
done()
})
experiment('BASICS', function () {
experiment('Swarm', function () {
test('enforces instantiation with new', function (done) {
expect(function () {
Swarm()
}).to.throw('Swarm must be called with new')
done()
})
test('parses $IPFS_SWARM_PORT', function (done) {
process.env.IPFS_SWARM_PORT = 1111
var swarm = new Swarm()
expect(swarm.port).to.be.equal(1111)
process.env.IPFS_SWARM_PORT = undefined
done()
})
})
experiment('Swarm.listen', function (done) {
test('handles missing port', function (done) {
var swarm = new Swarm()
swarm.listen(done)
})
test('handles passed in port', function (done) {
var swarm = new Swarm()
swarm.listen(1234)
expect(swarm.port).to.be.equal(1234)
done()
})
})
experiment('Swarm.registerHandler', function () {
test('throws when registering a protcol handler twice', function (done) {
var swarm = new Swarm()
swarm.registerHandler('/sparkles/1.1.1', function () {})
swarm.registerHandler('/sparkles/1.1.1', function (err) {
expect(err).to.be.an.instanceOf(Error)
expect(err.message).to.be.equal('Handle for protocol already exists')
done()
})
})
})
experiment('Swarm.closeConns', function () {
test('calls end on all connections', function (done) {
swarmA.openConnection(peerB, function () {
var key = Object.keys(swarmA.connections)[0]
sinon.spy(swarmA.connections[key].conn, 'end')
swarmA.closeConns(function () {
expect(swarmA.connections[key].conn.end.called).to.be.equal(true)
done()
})
})
})
})
})
experiment('BASE', function () {
test('Open a stream', function (done) {
var protocol = '/sparkles/3.3.3'
var c = new Counter(2, done)
swarmB.registerHandler(protocol, function (stream) {
c.hit()
})
swarmA.openStream(peerB, protocol, function (err, stream) {
expect(err).to.not.be.instanceof(Error)
c.hit()
})
})
test('Reuse connection (from dialer)', function (done) {
var protocol = '/sparkles/3.3.3'
swarmB.registerHandler(protocol, function (stream) {})
swarmA.openStream(peerB, protocol, function (err, stream) {
expect(err).to.not.be.instanceof(Error)
swarmA.openStream(peerB, protocol, function (err, stream) {
expect(err).to.not.be.instanceof(Error)
expect(swarmA.connections.length === 1)
done()
})
})
})
test('Check for lastSeen', function (done) {
var protocol = '/sparkles/3.3.3'
swarmB.registerHandler(protocol, function (stream) {})
swarmA.openStream(peerB, protocol, function (err, stream) {
expect(err).to.not.be.instanceof(Error)
expect(peerB.lastSeen).to.be.instanceof(Date)
done()
})
})
})
experiment('IDENTIFY', function () {
test('Attach Identify, open a stream, see a peer update', function (done) {
swarmA.on('error', function (err) {
console.log('A - ', err)
})
swarmB.on('error', function (err) {
console.log('B - ', err)
})
var protocol = '/sparkles/3.3.3'
var identifyA = new Identify(swarmA, peerA)
var identifyB = new Identify(swarmB, peerB)
setTimeout(function () {
swarmB.registerHandler(protocol, function (stream) {})
swarmA.openStream(peerB, protocol, function (err, stream) {
expect(err).to.not.be.instanceof(Error)
})
identifyB.on('peer-update', function (answer) {
done()
})
identifyA.on('peer-update', function (answer) {})
}, 500)
})
test('Attach Identify, open a stream, reuse stream', function (done) {
console.log('\n\n\n')
var protocol = '/sparkles/3.3.3'
var identifyA = new Identify(swarmA, peerA)
var identifyB = new Identify(swarmB, peerB)
swarmA.registerHandler(protocol, function (stream) {})
swarmB.registerHandler(protocol, function (stream) {})
swarmA.openStream(peerB, protocol, function (err, stream) {
expect(err).to.not.be.instanceof(Error)
})
identifyB.on('peer-update', function (answer) {
expect(Object.keys(swarmB.connections).length).to.equal(1)
swarmB.openStream(peerA, protocol, function (err, stream) {
expect(err).to.not.be.instanceof(Error)
expect(Object.keys(swarmB.connections).length).to.equal(1)
done()
})
})
identifyA.on('peer-update', function (answer) {})
})
})
experiment('HARDNESS', function () {})
function Counter (target, callback) {
var c = 0
this.hit = count
function count () {
c += 1
if (c === target) {
callback()
}
}
}
// function checkErr (err) {
// console.log('err')
// expect(err).to.be.instanceof(Error)
// }

29552
vendor/forge.bundle.js vendored Normal file

File diff suppressed because it is too large Load Diff