aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcel <cel@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519>2017-04-02 12:20:20 -0400
committercel <cel@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519>2017-04-04 17:40:09 -0700
commit487a99ede50bdbbd5308b1b446b9fc354d0a8c27 (patch)
tree3c1108d425f788fc83609e3de309714d9cca8f49
parentba3a576d5ae23bed296e9d2329b42e975482fc1a (diff)
downloadpatchfoo-487a99ede50bdbbd5308b1b446b9fc354d0a8c27.tar.gz
patchfoo-487a99ede50bdbbd5308b1b446b9fc354d0a8c27.zip
Add peers page
-rw-r--r--lib/app.js28
-rw-r--r--lib/serve.js62
2 files changed, 90 insertions, 0 deletions
diff --git a/lib/app.js b/lib/app.js
index 230768a..25cb02c 100644
--- a/lib/app.js
+++ b/lib/app.js
@@ -157,3 +157,31 @@ App.prototype.createLogStream = function (opts) {
? this.sbot.createFeedStream(opts)
: this.sbot.createLogStream(opts)
}
+
+var stateVals = {
+ connected: 3,
+ connecting: 2,
+ disconnecting: 1,
+}
+
+function comparePeers(a, b) {
+ var aState = stateVals[a.state] || 0
+ var bState = stateVals[b.state] || 0
+ return bState > aState ? 1 : bState < aState ? -1 :
+ b.stateChange - a.stateChange
+}
+
+App.prototype.streamPeers = function (opts) {
+ var gossip = this.sbot.gossip
+ return u.readNext(function (cb) {
+ gossip.peers(function (err, peers) {
+ if (err) return cb(err)
+ if (opts) peers = peers.filter(function (peer) {
+ for (var k in opts) if (opts[k] !== peer[k]) return false
+ return true
+ })
+ peers.sort(comparePeers)
+ cb(null, pull.values(peers))
+ })
+ })
+}
diff --git a/lib/serve.js b/lib/serve.js
index b24b9ae..7180f7a 100644
--- a/lib/serve.js
+++ b/lib/serve.js
@@ -17,6 +17,7 @@ var pkg = require('../package')
var Busboy = require('busboy')
var mime = require('mime-types')
var ident = require('pull-identify-filetype')
+var htime = require('human-time')
module.exports = Serve
@@ -37,6 +38,7 @@ function isMsgEncrypted(msg) {
function ctype(name) {
switch (name && /[^.\/]*$/.exec(name)[0] || 'html') {
case 'html': return 'text/html'
+ case 'txt': return 'text/plain'
case 'js': return 'text/javascript'
case 'css': return 'text/css'
case 'png': return 'image/png'
@@ -209,6 +211,7 @@ Serve.prototype.path = function (url) {
case '/private': return this.private(m[2])
case '/search': return this.search(m[2])
case '/vote': return this.vote(m[2])
+ case '/peers': return this.peers(m[2])
}
m = /^(\/?[^\/]*)(\/.*)?$/.exec(url)
switch (m[1]) {
@@ -305,6 +308,52 @@ Serve.prototype.search = function (ext) {
)
}
+Serve.prototype.peers = function (ext) {
+ var self = this
+ if (self.data.action === 'connect') {
+ return self.app.sbot.gossip.connect(self.data.address, function (err) {
+ if (err) return pull(
+ pull.once(u.renderError(err, ext).outerHTML),
+ self.wrapPage('peers'),
+ self.respondSink(400, {'Content-Type': ctype(ext)})
+ )
+ self.data = {}
+ return self.peers(ext)
+ })
+ }
+
+ pull(
+ self.app.streamPeers(),
+ paramap(function (peer, cb) {
+ var done = multicb({pluck: 1, spread: true})
+ var connectedTime = Date.now() - peer.stateChange
+ var addr = peer.host + ':' + peer.port + ':' + peer.key
+ done()(null, h('section',
+ h('form', {method: 'post', action: ''},
+ peer.client ? '→' : '←', ' ',
+ h('code', peer.host, ':', peer.port, ':'),
+ self.app.render.idLink(peer.key, done()), ' ',
+ htime(new Date(peer.stateChange)), ' ',
+ peer.state === 'connected' ? 'connected' : [
+ h('input', {name: 'action', type: 'submit', value: 'connect'}),
+ h('input', {name: 'address', type: 'hidden', value: addr})
+ ]
+ )
+ // h('div', 'source: ', peer.source)
+ // JSON.stringify(peer, 0, 2)).outerHTML
+ ))
+ done(cb)
+ }, 8),
+ pull.map(u.toHTML),
+ self.wrapPeers(),
+ self.wrapPage('peers'),
+ self.respondSink(200, {
+ 'Content-Type': ctype(ext)
+ })
+ )
+}
+
+
Serve.prototype.type = function (path) {
var q = this.query
var type = path.substr(1)
@@ -688,6 +737,7 @@ Serve.prototype.wrapPage = function (title, searchQ) {
h('nav.nav-bar', h('form', {action: render.toUrl('/search'), method: 'get'},
h('a', {href: render.toUrl('/public')}, 'public'), ' ',
h('a', {href: render.toUrl('/private')}, 'private') , ' ',
+ h('a', {href: render.toUrl('/peers')}, 'peers') , ' ',
render.idLink(self.app.sbot.id, done()), ' ',
h('input.search-input', {name: 'q', value: searchQ,
placeholder: 'search'})
@@ -834,6 +884,18 @@ Serve.prototype.wrapLinks = function (dest) {
})
}
+Serve.prototype.wrapPeers = function (opts) {
+ var self = this
+ return u.hyperwrap(function (peers, cb) {
+ cb(null, [
+ h('section',
+ h('h3', 'Peers')
+ ),
+ peers
+ ])
+ })
+}
+
function rows(str) {
return String(str).split(/[^\n]{150}|\n/).length
}