lib/gossip-with-slow-rollout/schedule.jsView |
---|
1 | 1 | var nonPrivate = require('non-private-ip') |
2 | 2 | var ip = require('ip') |
3 | 3 | var onWakeup = require('on-wakeup') |
4 | 4 | var onNetwork = require('on-change-network') |
| 5 | +var hasNetwork = require('has-network') |
5 | 6 | |
6 | | -var Stats = require('statistics') |
7 | | -var os = require('os') |
8 | 7 | var pull = require('pull-stream') |
9 | 8 | var u = require('scuttlebot/lib/util') |
10 | 9 | |
11 | 10 | function rand(array) { |
36 | 35 | function peerNext(peer, opts) { |
37 | 36 | return (peer.stateChange|0) + delay(peer.failure|0, opts.factor, opts.max) |
38 | 37 | } |
39 | 38 | |
| 39 | +function isFollowing (e) { |
| 40 | + return e.source === 'self' |
| 41 | +} |
40 | 42 | |
41 | 43 | |
42 | 44 | |
43 | 45 | |
44 | 46 | function isOffline (e) { |
45 | 47 | if(ip.isLoopback(e.host)) return false |
46 | | - var lo = Object.keys(os.networkInterfaces()) |
47 | | - return lo.length === 1 && lo[0] === 'lo' |
| 48 | + return !hasNetwork() |
48 | 49 | } |
49 | 50 | |
50 | 51 | var isOnline = not(isOffline) |
51 | 52 | |
54 | 55 | |
55 | 56 | return ip.isPrivate(e.host) && e.type === 'local' |
56 | 57 | } |
57 | 58 | |
58 | | -function isFollowing (e) { |
59 | | - return e.source === 'self' |
60 | | -} |
61 | | - |
62 | 59 | function isUnattempted (e) { |
63 | 60 | return !e.stateChange |
64 | 61 | } |
65 | 62 | |
66 | 63 | |
67 | 64 | |
68 | 65 | function isInactive (e) { |
69 | | - return e.stateChange && e.duration.mean == 0 |
| 66 | + return e.stateChange && (!e.duration || e.duration.mean == 0) |
70 | 67 | } |
71 | 68 | |
72 | 69 | function isLongterm (e) { |
73 | | - return e.ping && e.ping.rtt.mean > 0 |
| 70 | + return e.ping && e.ping.rtt && e.ping.rtt.mean > 0 |
74 | 71 | } |
75 | 72 | |
76 | 73 | |
77 | 74 | |
78 | 75 | |
79 | 76 | function isLegacy (peer) { |
80 | | - return peer.duration.mean > 0 && !exports.isLongterm(peer) |
| 77 | + return peer.duration && peer.duration.mean > 0 && !exports.isLongterm(peer) |
81 | 78 | } |
82 | 79 | |
83 | 80 | function isConnect (e) { |
84 | 81 | return 'connected' === e.state || 'connecting' === e.state |
106 | 103 | } |
107 | 104 | |
108 | 105 | var schedule = exports = module.exports = |
109 | 106 | function (gossip, config, server) { |
110 | | - |
| 107 | + |
111 | 108 | var min = 60e3, hour = 60*60e3 |
112 | 109 | |
113 | 110 | |
114 | 111 | onWakeup(gossip.reconnect) |
121 | 118 | } |
122 | 119 | |
123 | 120 | function connect (peers, ts, name, filter, opts) { |
124 | 121 | var connected = peers.filter(isConnect).filter(filter) |
125 | | - .filter(function (peer) { |
126 | | - |
127 | | - return !isFollowing(peer) && peer.stateChange + 10e3 < ts |
128 | | - }) |
129 | 122 | |
| 123 | + |
130 | 124 | if(connected.length > opts.quota) { |
131 | 125 | return earliest(connected, connected.length - opts.quota) |
132 | 126 | .forEach(function (peer) { |
133 | 127 | gossip.disconnect(peer) |
134 | 128 | }) |
135 | 129 | } |
136 | 130 | |
137 | | - select(peers, ts, and(filter, isOnline), opts) |
| 131 | + |
| 132 | + var selected = select(peers, ts, and(filter, isOnline), opts) |
| 133 | + selected |
138 | 134 | .forEach(function (peer) { |
139 | 135 | gossip.connect(peer) |
140 | 136 | }) |
141 | 137 | } |
145 | 141 | function connections () { |
146 | 142 | if(connecting) return |
147 | 143 | connecting = true |
148 | 144 | setTimeout(function () { |
149 | | - connecting = false |
150 | | - var ts = Date.now() |
151 | | - var peers = gossip.peers() |
| 145 | + connecting = false |
| 146 | + var ts = Date.now() |
| 147 | + var peers = gossip.peers() |
152 | 148 | |
153 | | - |
| 149 | + var connected = peers.filter(isConnect).length |
154 | 150 | |
155 | | - connect(peers, ts, 'following', exports.isFollowing, { |
| 151 | + connect(peers, ts, 'following', exports.isFollowing, { |
156 | 152 | min: 0, quota: 5, factor: 0, max: 0, groupMin: 0, |
157 | 153 | disable: !conf('global', true) |
158 | | - }) |
| 154 | + }) |
159 | 155 | |
160 | | - connect(peers, ts, 'attempt', exports.isUnattempted, { |
161 | | - min: 0, quota: 1, factor: 2e3, max: 0, groupMin: 0, |
| 156 | + connect(peers, ts, 'longterm', exports.isLongterm, { |
| 157 | + quota: 3, factor: 10e3, max: 10*min, groupMin: 5e3, |
162 | 158 | disable: !conf('global', true) |
163 | | - }) |
| 159 | + }) |
164 | 160 | |
165 | | - |
166 | | - connect(peers, ts, 'retry', exports.isInactive, { |
| 161 | + connect(peers, ts, 'local', exports.isLocal, { |
| 162 | + quota: 3, factor: 2e3, max: 10*min, groupMin: 1e3, |
| 163 | + disable: !conf('local', true) |
| 164 | + }) |
| 165 | + |
| 166 | + if(connected === 0) |
| 167 | + connect(peers, ts, 'attempt', exports.isUnattempted, { |
| 168 | + min: 0, quota: 1, factor: 0, max: 0, groupMin: 0, |
| 169 | + disable: !conf('global', true) |
| 170 | + }) |
| 171 | + |
| 172 | + |
| 173 | + connect(peers, ts, 'retry', exports.isInactive, { |
167 | 174 | min: 0, |
168 | 175 | quota: 3, factor: 5*60e3, max: 3*60*60e3, groupMin: 5*50e3 |
169 | 176 | }) |
170 | 177 | |
171 | | - connect(peers, ts, 'legacy', exports.isLegacy, { |
172 | | - quota: 3, factor: 5*min, max: 3*hour, groupMin: 5*min, |
| 178 | + var longterm = peers.filter(isConnect).filter(exports.isLongterm).length |
| 179 | + |
| 180 | + connect(peers, ts, 'legacy', exports.isLegacy, { |
| 181 | + quota: 3 - longterm, |
| 182 | + factor: 5*min, max: 3*hour, groupMin: 5*min, |
173 | 183 | disable: !conf('global', true) |
174 | 184 | }) |
175 | 185 | |
176 | | - connect(peers, ts, 'longterm', exports.isLongterm, { |
177 | | - quota: 3, factor: 10e3, max: 10*min, groupMin: 5e3, |
178 | | - disable: !conf('global', true) |
179 | | - }) |
| 186 | + peers.filter(isConnect).forEach(function (e) { |
| 187 | + if((!exports.isLongterm(e) || e.state === 'connecting') && e.stateChange + 10e3 < ts) { |
| 188 | + console.log('disconnect', exports.isLongterm(e), e.state, e.stateChange - ts) |
| 189 | + gossip.disconnect(e) |
| 190 | + } |
180 | 191 | |
181 | | - connect(peers, ts, 'local', exports.isLocal, { |
182 | | - quota: 3, factor: 2e3, max: 10*min, groupMin: 1e3, |
183 | | - disable: !conf('local', true) |
184 | | - }) |
| 192 | + }) |
185 | 193 | |
186 | 194 | }, 100*Math.random()) |
187 | 195 | |
188 | 196 | } |
203 | 211 | } |
204 | 212 | |
205 | 213 | exports.isUnattempted = isUnattempted |
206 | 214 | exports.isInactive = isInactive |
| 215 | +exports.isFollowing = isFollowing |
207 | 216 | exports.isLongterm = isLongterm |
208 | | -exports.isFollowing = isFollowing |
209 | 217 | exports.isLegacy = isLegacy |
210 | 218 | exports.isLocal = isLocal |
211 | 219 | exports.isConnectedOrConnecting = isConnect |
212 | 220 | exports.select = select |