├── README.md ├── test ├── reconnect.js └── index.js ├── package.json ├── LICENSE └── index.js /README.md: -------------------------------------------------------------------------------- 1 | # pull-reconnect 2 | 3 | a reconnect with pull-streams. 4 | useful with muxrpc. 5 | 6 | 7 | ## License 8 | 9 | MIT 10 | -------------------------------------------------------------------------------- /test/reconnect.js: -------------------------------------------------------------------------------- 1 | 2 | var tape = require('tape') 3 | var Reconnect = require('../') 4 | 5 | tape('reconnect after disconnect', function (t) { 6 | var n = 3 7 | var r = Reconnect(function (isConnected) { 8 | 9 | setTimeout(function () { 10 | console.log(n) 11 | isConnected(--n ? new Error() : null) 12 | }) 13 | 14 | }) 15 | 16 | var ready = r.async(function (cb) { 17 | cb() 18 | }) 19 | 20 | ready(t.end) 21 | 22 | }) 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pull-reconnect", 3 | "description": "", 4 | "version": "0.0.3", 5 | "homepage": "https://github.com/dominictarr/pull-reconnect", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/dominictarr/pull-reconnect.git" 9 | }, 10 | "dependencies": { 11 | "pull-defer": "^0.2.2" 12 | }, 13 | "devDependencies": { 14 | "pull-stream": "^3.4.3", 15 | "tape": "^4.5.1" 16 | }, 17 | "scripts": { 18 | "test": "set -e; for t in test/*.js; do node $t; done" 19 | }, 20 | "author": "Dominic Tarr (http://dominictarr.com)", 21 | "license": "MIT" 22 | } 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Dominic Tarr 2 | 3 | Permission is hereby granted, free of charge, 4 | to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to 6 | deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, 8 | merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom 10 | the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | var defer = require('pull-defer') 3 | 4 | module.exports = function (connect, factor, max) { 5 | 6 | factor = factor || 100 7 | max = max || 10e3 8 | 9 | var errors = 0, waiting = [] 10 | 11 | var state, attempt = Date.now() //first attempt started below. 12 | 13 | function tryConnect () { 14 | try { connect(isConnected) } 15 | catch (err) { console.log(err); isConnected(err) } 16 | } 17 | 18 | function isConnected (err) { 19 | //if the connection errored 20 | if(err && err !== true) { 21 | _state = false 22 | errors ++ 23 | setTimeout(tryConnect, Math.min(Math.pow(2, errors)*factor, max)) 24 | } 25 | else { 26 | _state = true 27 | errors = 0 28 | } 29 | if(state === _state) return 30 | state = _state 31 | if(state) 32 | while(waiting.length && state) waiting.shift()() 33 | //we don't handle any notifications for loosing connectivity. 34 | } 35 | 36 | isConnected.async = function async(fn) { 37 | return function () { 38 | var args = [].slice.call(arguments) 39 | if(state) fn.apply(null, args) 40 | else waiting.push(function () { 41 | fn.apply(null, args) 42 | }) 43 | } 44 | } 45 | 46 | isConnected.source = function (fn) { 47 | return function () { 48 | var args = [].slice.call(arguments) 49 | if(state) return fn.apply(null, args) 50 | var source = defer.source() 51 | waiting.push(function () { 52 | source.resolve(fn.apply(null, args)) 53 | }) 54 | return source 55 | } 56 | } 57 | 58 | isConnected.sink = function (fn) { 59 | return function () { 60 | var args = [].slice.call(arguments) 61 | if(state) return fn.apply(null, args) 62 | var sink = defer.sink() 63 | waiting.push(function () { 64 | sink.resolve(fn.apply(null, args)) 65 | }) 66 | return sink 67 | } 68 | } 69 | 70 | tryConnect() 71 | 72 | return isConnected 73 | } 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 2 | var tape = require('tape') 3 | var pull = require('pull-stream') 4 | 5 | var Reconnect = require('../') 6 | 7 | tape('delay async', function (t) { 8 | 9 | var ready = false 10 | var r = Reconnect(function (isConnected) { 11 | setTimeout(function () { 12 | isConnected(ready = true) 13 | }) 14 | }) 15 | 16 | var what = r.async(function (cb) { 17 | t.ok(ready) 18 | setTimeout(function () { 19 | cb(null, ready) 20 | }) 21 | }) 22 | 23 | what(function (err, ready) { 24 | t.ok(ready) 25 | t.end() 26 | }) 27 | 28 | }) 29 | 30 | 31 | tape('delay async, sync', function (t) { 32 | 33 | var ready = false 34 | var r = Reconnect(function (isConnected) { 35 | isConnected(ready = true) 36 | }) 37 | 38 | var what = r.async(function (cb) { 39 | t.ok(ready) 40 | setTimeout(function () { 41 | cb(null, ready) 42 | }) 43 | }) 44 | 45 | what(function (err, ready) { 46 | t.ok(ready) 47 | t.end() 48 | }) 49 | 50 | }) 51 | 52 | 53 | 54 | tape('delay source', function (t) { 55 | var ready = false 56 | var r = Reconnect(function (isConnected) { 57 | setTimeout(function () { 58 | isConnected(ready = true) 59 | }) 60 | }) 61 | 62 | var what = r.source(function () { 63 | return pull.values([1,2,3]) 64 | }) 65 | 66 | pull(what(), pull.collect(function (err, ary) { 67 | if(err) throw err 68 | t.deepEqual(ary, [1,2,3]) 69 | t.end() 70 | })) 71 | 72 | }) 73 | 74 | tape('delay source, sync', function (t) { 75 | var ready = false 76 | var r = Reconnect(function (isConnected) { 77 | isConnected(ready = true) 78 | }) 79 | 80 | var what = r.source(function () { 81 | return pull.values([1,2,3]) 82 | }) 83 | 84 | pull(what(), pull.collect(function (err, ary) { 85 | if(err) throw err 86 | t.deepEqual(ary, [1,2,3]) 87 | t.end() 88 | })) 89 | 90 | }) 91 | 92 | tape('delay sink', function (t) { 93 | var ready = false 94 | var r = Reconnect(function (isConnected) { 95 | setTimeout(function () { 96 | isConnected(ready = true) 97 | }) 98 | }) 99 | 100 | var collect = r.sink(function (cb) { 101 | t.ok(ready) 102 | return pull.collect(cb) 103 | }) 104 | 105 | pull(pull.values([1,2,3]), collect(function (err, ary) { 106 | if(err) throw err 107 | t.deepEqual(ary, [1,2,3]) 108 | t.end() 109 | })) 110 | 111 | }) 112 | 113 | 114 | 115 | --------------------------------------------------------------------------------