Name: ssb-cli-dashboard
Owner: Secure Scuttlebutt Consortium
Description: A cli dashboard for scuttlebot
Created: 2015-09-18 23:59:11.0
Updated: 2018-03-27 03:13:57.0
Pushed: 2016-03-17 02:25:21.0
Homepage: null
Size: 3602
Language: JavaScript
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
clone https://github.com/ssbc/ssb-cli-dashboard.git
sb-cli-dashboard
install
Then:
st all feeds
feeds.js
ew the given feed
feed.js {feedid}
ew blobs linked-to by the given feed
blobs.js {feedid}
ew feeds related to the given feed
graph.js [follows|followers|flags|flaggers] {feedid}
twork status
gossip.js
The feeds.js
view pulls some metadata from Scuttlebot, and uses that to produce a master list of known feeds.
oad data from sbot
done = multicb({ pluck: 1, spread: true })
(
ot.latest(), // get the sequence number of the latest message of each known feed
ilter) ? pull.filter(filter) : null, // apply a filter, if given
ll.collect(done()) // collect into an array
.friends.all('follow', done()) // fetch the computed follow-graph
.friends.all('flag', done()) // fetch the computed flag-graph
(function (err, feeds, follows, flags) {
...
Each entry shows:
id [seq: N follows: N/N flags: N/N]
Where, in the case of follows and flags, it's showing the outbound then inbound. It computes this info by counting directed-edges:
elper to count how many nodes in the graph have edges pointing to the given ID
graphs are given in the shape of { sourceIds: { destIds: true } }
eg. if bob follows alice, the follow graph would include { bobsId: { alicesId: true } }
if alice also followed bob, the follow graph would be { bobsId: { alicesId: true }, alicesId: { bobsId: true } }
tion countInbounds (graph, id) {
r n = 0
r (var id2 in graph)
if (graph[id2][id])
n++
turn n
elper to count how many nodes in the graph the given ID points to
see `countInbounds` comment for more info
tion countOutbounds(graph, id) {
turn Object.keys(graph[id] || {}).length
ake the feeds and graphs, produce textual list items
tion feedsToListItems (feeds, follows, flags) {
sort by highest sequence to lowest sequence
eds.sort(function (a, b) {
return b.sequence - a.sequence
produce a list of labels
turn feeds.map(function (f) {
var info = [
'seq: ' + f.sequence,
'follows: ' + countOutbounds(follows, f.id) + '/' + countInbounds(follows, f.id),
'flags: ' + countOutbounds(flags, f.id) + '/' + countInbounds(flags, f.id)
]
return f.id + '[' + info.join(' ') + ']'
In feed.js
, the list is a simple stream-fetch:
(sbot.createUserStream({ id: userId }), pull.collect(function (err, log) {
...
graph.js
uses the same code in feeds.js
, but it applies a filter.
It generates the filter using this function:
tion filteredFeeds (graph, inbound, label) {
r included = {}
ot.friends.all(graph, function (err, g) {
if (inbound) {
// collect feeds with an edge to `userId`
for (var id2 in g)
if (g[id2][userId])
included[id2] = true
} else {
// use the already-computed `userId` edges
included = g[userId] || {}
}
nction filter (entry) {
return included[entry.id]
...
Here's how it's applied to create the four graph-filters:
graphs = {
ollows': filteredFeeds('follow', false, 'Follows'),
ollowers': filteredFeeds('follow', true, 'Followers'),
lags': filteredFeeds('flag', false, 'Flags'),
laggers': filteredFeeds('flag', true, 'Flaggers'),
blobs.js
collects every reference to a blob made by the given userId
, and lists them in the form:
id (N references)
It does this by first searching for any messages by userId
that link to a blob.
Then, it groups the messages by blob, producing the final list.
blobs, blobMessageMap = {}
(
fetch messages by `userId` which link to a blob
ot.links({ source: userId, dest: '&', values: true }),
group together messages that publish a blob
ll.filter(function (index) {
var blobId = index.dest
if (!blobMessageMap[blobId]) {
blobMessageMap[blobId] = [index]
return true
}
blobMessageMap[blobId].push(index)
return false
,
collect into an array
ll.collect(function (err, _blobs) {
if (err) throw err
blobs = _blobs
// sort by the number of references to the blob
blobs.sort(function (a, b) {
return blobMessageMap[b.dest].length - blobMessageMap[a.dest].length
})
// render in the list widget
var listItems = blobs.map(function (index) {
return index.dest + ' ('+blobMessageMap[index.dest].length+' references)'
})
listWidget.setItems(listItems)
listWidget.select(0)
screen.render()
Finally, gossip.js
simply polls the status of the gossip-network and renders it periodically.
tion poll () {
ot.gossip.peers(function (err, peers) {
if (err) throw err
table.setData(peersToTableData(peers))
screen.render()
()
nterval(poll, 1000)
tion status (peer) {
(peer.connected)
return 'Connected'
(peer.time && peer.time.connect > peer.time.attempt)
return 'Connecting'
(peer.failure)
return peer.failure + ' Failures'
turn 'Disconnected'
tion peersToTableData (peers) {
ers.sort(function (a, b) {
var an = (a.announcers) ? a.announcers.length : 0
var bn = (b.announcers) ? b.announcers.length : 0
return bn - an
turn {
headers: ['Announcers', 'Address', 'Status'],
data: peers.map(function (p) {
return [
(p.announcers) ? p.announcers.length : 0,
p.host + ':' + p.port + ':' + p.key,
status(p)
]
})