-
-
Notifications
You must be signed in to change notification settings - Fork 21
/
index.js
133 lines (110 loc) · 3.53 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
var EventEmitter = require('events').EventEmitter
var backoff = require('backoff')
module.exports =
function (createConnection) {
return function (opts, onConnect) {
onConnect = 'function' == typeof opts ? opts : onConnect
opts = 'object' == typeof opts ? opts : {initialDelay: 1e3, maxDelay: 30e3}
if(!onConnect)
onConnect = opts.onConnect
var emitter = new EventEmitter()
emitter.connected = false
emitter.reconnect = true
if(onConnect)
//use "connection" to match core (net) api.
emitter.on('connection', onConnect)
var backoffStrategy = opts.strategy || opts.type
var backoffMethod
if (typeof backoffStrategy == 'string')
backoffMethod = backoff[backoffStrategy](opts)
else
backoffMethod = backoffStrategy || backoff.fibonacci(opts)
if(opts.failAfter)
backoffMethod.failAfter(opts.failAfter);
backoffMethod.on('backoff', function (n, d, e) {
emitter.emit('backoff', n, d, e)
})
backoffMethod.on('fail', function (e) {
emitter.disconnect()
emitter.emit('fail', e)
})
var args
function attempt (n, delay) {
if(emitter.connected) return
if(!emitter.reconnect) return
emitter.emit('reconnect', n, delay)
var con = createConnection.apply(emitter, args)
emitter._connection = con
function onError (err) {
con.removeListener('error', onError)
emitter.emit('error', err)
onDisconnect(err)
}
function onDisconnect (err) {
emitter.connected = false
con.removeListener('close', onDisconnect)
con.removeListener('end' , onDisconnect)
//hack to make http not crash.
//HTTP IS THE WORST PROTOCOL.
if(con.constructor.name == 'Request')
con.on('error', function () {})
//emit disconnect before checking reconnect, so user has a chance to decide not to.
emitter.emit('disconnect', err)
if(!emitter.reconnect) return
try { backoffMethod.backoff() } catch (_) { }
}
con
.on('error', onError)
.on('close', onDisconnect)
.on('end' , onDisconnect)
if(opts.immediate || con.constructor.name == 'Request') {
emitter.connected = true
emitter.emit('connect', con)
emitter.emit('connection', con)
con.once('data', function () {
//this is the only way to know for sure that data is coming...
backoffMethod.reset()
})
} else {
con
.once('connect', function () {
backoffMethod.reset()
emitter.connected = true
if(onConnect)
con.removeListener('connect', onConnect)
emitter.emit('connect', con)
//also support net style 'connection' method.
emitter.emit('connection', con)
})
}
}
emitter.connect =
emitter.listen = function () {
this.reconnect = true
if(emitter.connected) return
backoffMethod.reset()
backoffMethod.on('ready', attempt)
if (!args) {
var len = arguments.length;
args = new Array(len);
for (var i = 0; i < len; i++) {
args[i] = arguments[i];
}
}
attempt(0, 0)
return emitter
}
//force reconnection
emitter.disconnect = function () {
this.reconnect = false
if(emitter._connection)
emitter._connection.end()
return emitter
}
emitter.reset = function () {
backoffMethod.reset()
attempt(0, 0)
}
return emitter
}
}