git ssb

16+

Dominic / patchbay



Tree: 0831215dc5165e22aefa788b8249903f50b9de23

Files: 0831215dc5165e22aefa788b8249903f50b9de23 / modules_extra / network.js

5380 bytesRaw
1const isVisible = require('is-visible').isVisible
2const h = require('../h')
3const mutantMap = require('@mmckegg/mutant/map')
4const mutantDict = require('@mmckegg/mutant/dict')
5const Struct = require('@mmckegg/mutant/struct')
6const Value = require('@mmckegg/mutant/value')
7const toCollection = require('@mmckegg/mutant/dict-to-collection')
8const when = require('@mmckegg/mutant/when')
9const computed = require('@mmckegg/mutant/computed')
10const human = require('human-time')
11
12//var avatar = plugs.first(exports.avatar = [])
13//var sbot_gossip_peers = plugs.first(exports.sbot_gossip_peers = [])
14//var sbot_gossip_connect = plugs.first(exports.sbot_gossip_connect = [])
15
16exports.needs = {
17 avatar: 'first',
18 sbot_gossip_peers: 'first',
19 sbot_gossip_connect: 'first'
20}
21
22exports.gives = {
23 menu_items: true,
24 builtin_tabs: true,
25 screen_view: true
26}
27
28//sbot_gossip_connect
29//sbot_gossip_add
30
31
32function legacyToMultiServer(addr) {
33 return 'net:'+addr.host + ':'+addr.port + '~shs:'+addr.key.substring(1).replace('.ed25519','')
34}
35
36
37
38//on the same wifi network
39function isLocal (peer) {
40 // don't rely on private ip address, because
41 // cjdns creates fake private ip addresses.
42 return ip.isPrivate(peer.host) && peer.type === 'local'
43}
44
45
46//pub is running scuttlebot >=8
47//have connected successfully.
48function isLongterm (peer) {
49 return peer.ping && peer.ping.rtt && peer.ping.rtt.mean > 0
50}
51
52//pub is running scuttlebot < 8
53//have connected sucessfully
54function isLegacy (peer) {
55 return /connect/.test(peer.state) || (peer.duration && peer.duration.mean) > 0 && !isLongterm(peer)
56}
57
58//tried to connect, but failed.
59function isInactive (peer) {
60 return peer.stateChange && (peer.duration && peer.duration.mean == 0)
61}
62
63//havn't tried to connect peer yet.
64function isUnattempted (peer) {
65 return !peer.stateChange
66}
67
68function getType (peer) {
69 return (
70 isLongterm(peer) ? 'modern'
71 : isLegacy(peer) ? 'legacy'
72 : isInactive(peer) ? 'inactive'
73 : isUnattempted(peer) ? 'unattempted'
74 : 'other' //should never happen
75 )
76}
77
78function origin (peer) {
79 return peer.source === 'local' ? 0 : 1
80}
81
82
83function round(n) {
84 return Math.round(n*100)/100
85}
86
87function duration (s) {
88 if(!s) return s
89 if (Math.abs(s) > 30000)
90 return round(s/60000)+'m'
91 else if (Math.abs(s) > 500)
92 return round(s/1000)+'s'
93 else
94 return round(s)+'ms'
95}
96
97function peerListSort (a, b) {
98 var states = {
99 connected: 3,
100 connecting: 2
101 }
102
103 //types of peers
104 var types = {
105 modern: 4,
106 legacy: 3,
107 inactive: 2,
108 unattempted: 1,
109 other: 0
110 }
111
112 return (
113 (states[b.state] || 0) - (states[a.state] || 0)
114 || origin(b) - origin(a)
115 || types[getType(b)] - types[getType(a)]
116 || b.stateChange - a.stateChange
117 )
118}
119
120function formatDate (time) {
121 return new Date(time).toString()
122}
123
124function humanDate (time) {
125 return human(new Date(time))
126}
127
128exports.create = function (api) {
129
130 return {
131 menu_items: () => h('a', {href: '#/network'}, '/network'),
132 builtin_tabs: () => ['/network'],
133 screen_view
134 }
135
136 function screen_view (path) {
137 if (path !== '/network') return
138
139 var peers = obs_gossip_peers(api)
140
141 return h('div', { style: {'overflow':'auto'}, className: 'column scroller' }, [
142 h('Network', [
143 mutantMap(peers, peer => {
144 var { key, ping, source, state, stateChange } = peer
145
146 console.log('ping', ping())
147
148 return h('NetworkConnection', [
149 api.avatar(key(), 'thumbnail'),
150 h('div', [
151 when(state, state, 'not connected'),
152 ' ',
153 computed(peer, getType),
154 ' ',
155 // //TODO: show nicer details, with labels. etc.
156 computed(ping.rtt.mean, duration),
157 ' ',
158 computed(ping.skew.mean, duration),
159 ' ',
160 h('label',
161 { title: computed(stateChange, formatDate) },
162 [ computed(stateChange, humanDate) ]
163 )
164 ]),
165 'source: ',
166 source,
167 h('pre', computed(peer, legacyToMultiServer)),
168 h('button', {
169 'ev-click': () => {
170 api.sbot_gossip_connect(peer(), (err) => {
171 if(err) console.error(err)
172 else console.log('connected to', peer())
173 })
174 }},
175 'connect'
176 )
177 ])
178 })
179 ])
180 ])
181 }
182}
183
184function obs_gossip_peers (api) {
185 var timer = null
186 var state = mutantDict({}, {
187 onListen: () => {
188 timer = setInterval(refresh, 5e3)
189 },
190 onUnlisten: () => {
191 clearInterval(timer)
192 }
193 })
194
195 refresh()
196
197 return toCollection.values(state)
198
199 function refresh () {
200 api.sbot_gossip_peers((err, peers) => {
201 peers.forEach(data => {
202 var current = state.get(data.key)
203 if (!current) {
204 current = Peer()
205 current.set(data)
206 state.put(data.key, current)
207 } else {
208 current.set(data)
209 }
210 })
211 })
212 }
213}
214
215function Peer () {
216 var peer = Struct({
217 key: Value(),
218 ping: Struct({
219 rtt: Struct({
220 mean: Value()
221 }),
222 skew: Struct({
223 mean: Value()
224 })
225 }),
226 source: Value(),
227 state: Value(),
228 stateChange: Value()
229 })
230
231 return peer
232}
233
234

Built with git-ssb-web