Commit f8a3919796796fb604a4d98decee02f962ee7cee
fix connecting to local peers - you now stay permanently connected
Matt McKegg committed on 11/3/2016, 3:23:31 PMParent: 4085b6135d2bff24ac3c2b0818dedc49e03a87dd
Files changed
lib/persistent-gossip/index.js | changed |
lib/persistent-gossip/schedule.js | changed |
lib/persistent-gossip/init.js | added |
package.json | changed |
server-process.js | changed |
lib/persistent-gossip/index.js | ||
---|---|---|
@@ -6,11 +6,14 @@ | ||
6 | 6 | var apidoc = require('scuttlebot/lib/apidocs').gossip |
7 | 7 | var u = require('scuttlebot/lib/util') |
8 | 8 | var ref = require('ssb-ref') |
9 | 9 | var ping = require('pull-ping') |
10 | -var Stats = require('statistics') | |
10 | +var stats = require('statistics') | |
11 | 11 | var Schedule = require('./schedule') |
12 | -var Init = require('scuttlebot/plugins/gossip/init') | |
12 | +var Init = require('./init') | |
13 | +var AtomicFile = require('atomic-file') | |
14 | +var path = require('path') | |
15 | +var deepEqual = require('deep-equal') | |
13 | 16 | |
14 | 17 | function isFunction (f) { |
15 | 18 | return 'function' === typeof f |
16 | 19 | } |
@@ -18,8 +21,12 @@ | ||
18 | 21 | function stringify(peer) { |
19 | 22 | return [peer.host, peer.port, peer.key].join(':') |
20 | 23 | } |
21 | 24 | |
25 | +function isFriends (friends, a, b) { | |
26 | + return friends[a] && friends[b] && friends[a][b] && friends[b][a] | |
27 | +} | |
28 | + | |
22 | 29 | /* |
23 | 30 | Peers : [{ |
24 | 31 | key: id, |
25 | 32 | host: ip, |
@@ -42,8 +49,10 @@ | ||
42 | 49 | var notify = Notify() |
43 | 50 | var conf = config.gossip || {} |
44 | 51 | var home = ref.parseAddress(server.getAddress()) |
45 | 52 | |
53 | + var stateFile = AtomicFile(path.join(config.path, 'gossip.json')) | |
54 | + | |
46 | 55 | //Known Peers |
47 | 56 | var peers = [] |
48 | 57 | |
49 | 58 | function getPeer(id) { |
@@ -58,8 +67,18 @@ | ||
58 | 67 | wakeup: 0, |
59 | 68 | peers: function () { |
60 | 69 | return peers |
61 | 70 | }, |
71 | + connectToFriends: function () { | |
72 | + server.friends.all((err, friends) => { | |
73 | + if (err) return | |
74 | + peers.forEach(function(peer) { | |
75 | + if (!Schedule.isConnect(peer) && isFriends(friends, server.id, peer.key)) { | |
76 | + gossip.connect(peer, function() {}) | |
77 | + } | |
78 | + }) | |
79 | + }) | |
80 | + }, | |
62 | 81 | get: function (addr) { |
63 | 82 | addr = ref.parseAddress(addr) |
64 | 83 | return u.find(peers, function (a) { |
65 | 84 | return ( |
@@ -88,9 +107,9 @@ | ||
88 | 107 | p.failure = (p.failure || 0) + 1 |
89 | 108 | p.stateChange = Date.now() |
90 | 109 | notify({ type: 'connect-failure', peer: p }) |
91 | 110 | server.emit('log:info', ['SBOT', p.host+':'+p.port+p.key, 'connection failed', err.message || err]) |
92 | - p.duration.value(0) | |
111 | + p.duration = stats(p.duration, 0) | |
93 | 112 | return (cb && cb(err)) |
94 | 113 | } |
95 | 114 | else { |
96 | 115 | p.state = 'connected' |
@@ -131,12 +150,15 @@ | ||
131 | 150 | if(!f) { |
132 | 151 | // new peer |
133 | 152 | addr.source = source |
134 | 153 | addr.announcers = 1 |
135 | - addr.duration = Stats() | |
154 | + addr.duration = addr.duration || null | |
136 | 155 | peers.push(addr) |
137 | 156 | notify({ type: 'discover', peer: addr, source: source || 'manual' }) |
138 | 157 | return addr |
158 | + } else if (source === 'local') { | |
159 | + // this peer is local to us, override old source | |
160 | + addr.source = 'local' | |
139 | 161 | } |
140 | 162 | //don't count local over and over |
141 | 163 | else if(f.source != 'local') |
142 | 164 | f.announcers ++ |
@@ -196,17 +218,45 @@ | ||
196 | 218 | //track whether we have successfully connected. |
197 | 219 | //or how many failures there have been. |
198 | 220 | var since = peer.stateChange |
199 | 221 | peer.stateChange = Date.now() |
200 | - if(peer.state === 'connected') //may be "disconnecting" | |
201 | - peer.duration.value(peer.stateChange - since) | |
222 | +// if(peer.state === 'connected') //may be "disconnecting" | |
223 | + peer.duration = stats(peer.duration, peer.stateChange - since) | |
224 | +// console.log(peer.duration) | |
202 | 225 | peer.state = undefined |
203 | 226 | notify({ type: 'disconnect', peer: peer }) |
204 | 227 | server.emit('log:info', ['SBOT', rpc.id, 'disconnect']) |
205 | 228 | }) |
206 | 229 | |
207 | 230 | notify({ type: 'connect', peer: peer }) |
208 | 231 | }) |
209 | 232 | |
233 | + var last | |
234 | + stateFile.get(function (err, ary) { | |
235 | + last = ary || [] | |
236 | + if(Array.isArray(ary)) | |
237 | + ary.forEach(function (v) { | |
238 | + delete v.state | |
239 | + // don't add local peers (wait to rediscover) | |
240 | + if(v.source !== 'local') { | |
241 | + gossip.add(v, 'stored') | |
242 | + } | |
243 | + }) | |
244 | + }) | |
245 | + | |
246 | + var int = setInterval(function () { | |
247 | + var copy = JSON.parse(JSON.stringify(peers)) | |
248 | + copy.forEach(function (e) { | |
249 | + delete e.state | |
250 | + }) | |
251 | + if(deepEqual(copy, last)) return | |
252 | + last = copy | |
253 | + stateFile.set(copy, function(err) { | |
254 | + if (err) console.log(err) | |
255 | + }) | |
256 | + }, 10*1000) | |
257 | + | |
258 | + if(int.unref) int.unref() | |
259 | + | |
210 | 260 | return gossip |
211 | 261 | } |
212 | 262 | } |
lib/persistent-gossip/schedule.js | ||
---|---|---|
@@ -1,17 +1,11 @@ | ||
1 | -var nonPrivate = require('non-private-ip') | |
2 | 1 | var ip = require('ip') |
3 | 2 | var onWakeup = require('on-wakeup') |
4 | 3 | var onNetwork = require('on-change-network') |
5 | 4 | var hasNetwork = require('has-network') |
6 | 5 | |
7 | 6 | var pull = require('pull-stream') |
8 | -var u = require('scuttlebot/lib/util') | |
9 | 7 | |
10 | -function rand(array) { | |
11 | - return array[~~(Math.random()*array.length)] | |
12 | -} | |
13 | - | |
14 | 8 | function not (fn) { |
15 | 9 | return function (e) { return !fn(e) } |
16 | 10 | } |
17 | 11 | |
@@ -35,11 +29,8 @@ | ||
35 | 29 | function peerNext(peer, opts) { |
36 | 30 | return (peer.stateChange|0) + delay(peer.failure|0, opts.factor, opts.max) |
37 | 31 | } |
38 | 32 | |
39 | -function isFollowing (e) { | |
40 | - return e.source === 'self' | |
41 | -} | |
42 | 33 | |
43 | 34 | //detect if not connected to wifi or other network |
44 | 35 | //(i.e. if there is only localhost) |
45 | 36 | |
@@ -52,9 +43,9 @@ | ||
52 | 43 | |
53 | 44 | function isLocal (e) { |
54 | 45 | // don't rely on private ip address, because |
55 | 46 | // cjdns creates fake private ip addresses. |
56 | - return ip.isPrivate(e.host) && e.type === 'local' | |
47 | + return ip.isPrivate(e.host) && e.source === 'local' | |
57 | 48 | } |
58 | 49 | |
59 | 50 | function isUnattempted (e) { |
60 | 51 | return !e.stateChange |
@@ -157,14 +148,13 @@ | ||
157 | 148 | quota: 3, factor: 2e3, max: 10*min, groupMin: 1e3, |
158 | 149 | disable: !conf('local', true) |
159 | 150 | }) |
160 | 151 | |
161 | - if(connected < 3) { | |
152 | + if(connected < 3) | |
162 | 153 | connect(peers, ts, 'attempt', exports.isUnattempted, { |
163 | 154 | min: 0, quota: 1, factor: 0, max: 0, groupMin: 0, |
164 | 155 | disable: !conf('global', true) |
165 | 156 | }) |
166 | - } | |
167 | 157 | |
168 | 158 | //quota, groupMin, min, factor, max |
169 | 159 | connect(peers, ts, 'retry', exports.isInactive, { |
170 | 160 | min: 0, |
@@ -179,12 +169,12 @@ | ||
179 | 169 | disable: !conf('global', true) |
180 | 170 | }) |
181 | 171 | |
182 | 172 | peers.filter(isConnect).forEach(function (e) { |
183 | - if((!exports.isLongterm(e) || e.state === 'connecting') && e.stateChange + 10e3 < ts) { | |
173 | + var permanent = exports.isLongterm(e) || exports.isLocal(e) | |
174 | + if((!permanent || e.state === 'connecting') && e.stateChange + 10e3 < ts) { | |
184 | 175 | gossip.disconnect(e) |
185 | 176 | } |
186 | - | |
187 | 177 | }) |
188 | 178 | |
189 | 179 | }, 100*Math.random()) |
190 | 180 | |
@@ -206,9 +196,8 @@ | ||
206 | 196 | } |
207 | 197 | |
208 | 198 | exports.isUnattempted = isUnattempted |
209 | 199 | exports.isInactive = isInactive |
210 | -exports.isFollowing = isFollowing | |
211 | 200 | exports.isLongterm = isLongterm |
212 | 201 | exports.isLegacy = isLegacy |
213 | 202 | exports.isLocal = isLocal |
214 | 203 | exports.isConnectedOrConnecting = isConnect |
lib/persistent-gossip/init.js | ||
---|---|---|
@@ -1,0 +1,34 @@ | ||
1 | +var isArray = Array.isArray | |
2 | +var pull = require('pull-stream') | |
3 | +var ref = require('ssb-ref') | |
4 | + | |
5 | +module.exports = function (gossip, config, server) { | |
6 | + | |
7 | + // populate peertable with configured seeds (mainly used in testing) | |
8 | + var seeds = config.seeds | |
9 | + | |
10 | + ;(isArray(seeds) ? seeds : [seeds]).filter(Boolean) | |
11 | + .forEach(function (addr) { gossip.add(addr, 'seed') }) | |
12 | + | |
13 | + // populate peertable with pub announcements on the feed | |
14 | + pull( | |
15 | + server.messagesByType({ | |
16 | + type: 'pub', live: true, keys: false | |
17 | + }), | |
18 | + pull.drain(function (msg) { | |
19 | + if(msg.sync) return | |
20 | + if(!msg.content.address) return | |
21 | + if(ref.isAddress(msg.content.address)) | |
22 | + gossip.add(msg.content.address, 'pub') | |
23 | + }, gossip.connectToFriends) | |
24 | + ) | |
25 | + | |
26 | + // populate peertable with announcements on the LAN multicast | |
27 | + server.on('local', function (_peer) { | |
28 | + gossip.add(_peer, 'local') | |
29 | + }) | |
30 | + | |
31 | +} | |
32 | + | |
33 | + | |
34 | + |
package.json | ||
---|---|---|
@@ -12,9 +12,11 @@ | ||
12 | 12 | "author": "", |
13 | 13 | "license": "GPL", |
14 | 14 | "dependencies": { |
15 | 15 | "@mmckegg/mutant": "~3.7.1", |
16 | + "atomic-file": "^0.1.0", | |
16 | 17 | "data-uri-to-buffer": "0.0.4", |
18 | + "deep-equal": "^1.0.1", | |
17 | 19 | "electron": "~1.4.4", |
18 | 20 | "electron-default-menu": "~1.0.0", |
19 | 21 | "has-network": "0.0.0", |
20 | 22 | "insert-css": "~1.0.0", |
@@ -27,9 +29,11 @@ | ||
27 | 29 | "pull-abortable": "^4.1.0", |
28 | 30 | "pull-file": "~1.0.0", |
29 | 31 | "pull-identify-filetype": "^1.1.0", |
30 | 32 | "pull-next": "0.0.2", |
33 | + "pull-notify": "^0.1.1", | |
31 | 34 | "pull-pause": "0.0.0", |
35 | + "pull-ping": "^2.0.2", | |
32 | 36 | "pull-pushable": "^2.0.1", |
33 | 37 | "pull-stream": "~3.4.5", |
34 | 38 | "scuttlebot": "~9.2.0", |
35 | 39 | "sorted-array-functions": "~1.0.0", |
@@ -37,7 +41,8 @@ | ||
37 | 41 | "ssb-keys": "~7.0.0", |
38 | 42 | "ssb-links": "~2.0.0", |
39 | 43 | "ssb-query": "~0.1.1", |
40 | 44 | "ssb-ref": "~2.6.2", |
41 | - "ssb-sort": "^1.0.0" | |
45 | + "ssb-sort": "^1.0.0", | |
46 | + "statistics": "^3.3.0" | |
42 | 47 | } |
43 | 48 | } |
server-process.js | ||
---|---|---|
@@ -24,24 +24,6 @@ | ||
24 | 24 | } |
25 | 25 | ssbConfig.manifest = context.sbot.getManifest() |
26 | 26 | serveBlobs(context) |
27 | 27 | fs.writeFileSync(Path.join(ssbConfig.path, 'manifest.json'), JSON.stringify(ssbConfig.manifest)) |
28 | - connectToFriendlyPubs(context.sbot) | |
29 | 28 | electron.ipcRenderer.send('server-started', ssbConfig) |
30 | 29 | } |
31 | - | |
32 | -function connectToFriendlyPubs (sbot) { | |
33 | - sbot.gossip.peers((err, peers) => { | |
34 | - if (err) return console.log(err) | |
35 | - sbot.friends.all((err, friends) => { | |
36 | - if (err) return console.log(err) | |
37 | - console.log('Attempting to connect to friendly pubs...') | |
38 | - peers.filter((p) => p.state !== 'connected' && isFriends(friends, sbot.id, p.key)).forEach((peer) => { | |
39 | - sbot.gossip.connect(peer, () => {}) | |
40 | - }) | |
41 | - }) | |
42 | - }) | |
43 | -} | |
44 | - | |
45 | -function isFriends (friends, a, b) { | |
46 | - return friends[a] && friends[b] && friends[a][b] && friends[b][a] | |
47 | -} |
Built with git-ssb-web