git ssb

2+

mixmix / ticktack



Commit 5f86bdb837a971c779cc9be81fd7c8e39090a252

mostly working !!!!

mix irving committed on 5/31/2018, 10:59:30 AM
Parent: be227038215cfd41dc8aee4c1ece14657a72abce

Files changed

backup/async/exportIdentity.jschanged
ftu/app.jschanged
ftu/observeSequence.jsdeleted
ftu/manageProgress.jsadded
translations/en.jschanged
backup/async/exportIdentity.jsView
@@ -30,16 +30,16 @@
3030 onceTrue(api.sbot.obs.connection, sbot => {
3131 parallel([
3232 getLatestSequence,
3333 getGossipFollowers,
34- getPeersSequence
34+ getPeersLatestSequence
3535 ], save)
3636
3737 function getLatestSequence (done) {
3838 sbot.latestSequence(sbot.id, (err, seq) => {
3939 if (err) return done(err)
4040
41- backup.latestSequence = seq
41+ backup.mySequence = { latest: seq }
4242 done(null)
4343 })
4444 }
4545
@@ -55,9 +55,9 @@
5555 done(null)
5656 })
5757 }
5858
59- function getPeersSequence (done) {
59+ function getPeersLatestSequence (done) {
6060 sbot.friends.get({ source: sbot.id }, (err, d) => {
6161 if (err) return done(err)
6262
6363 var follows = Object.keys(d).filter(id => d[id] === true)
@@ -67,15 +67,17 @@
6767 if (err && err.message && err.message.indexOf('not found') > 0) {
6868 console.error(err)
6969 return cb(null, null) // don't include this user
7070 }
71+ if (err) return cb(err)
7172
7273 cb(null, [ id, seq ])
7374 }),
7475 (err, peers) => {
7576 if (err) return done(err)
7677
77- backup.peersSequence = peers
78+ // TODO change
79+ backup.peersLatestSequence = peers
7880 .filter(Boolean)
7981 .reduce((soFar, [ id, seq ]) => {
8082 if (seq) soFar[id] = seq
8183 return soFar
ftu/app.jsView
@@ -6,26 +6,49 @@
66 const os = require('os')
77 const progress = require('progress-string')
88 const values = require('lodash/values')
99
10-const observeSequence = require('./observeSequence')
10+const manageProgress = require('./manageProgress')
1111 const windowControls = require('../windowControls')
1212 const ftuCss = require('./styles')
1313
14-const appName = process.env.SSB_APPNAME || 'ssb'
15-const CONFIG_FOLDER = path.join(os.homedir(), `.${appName}`)
16-const IMPORT_FILE = path.join(CONFIG_FOLDER, 'importing.json')
14+// const config = require('../config').create().config.sync.load()
15+const config = {
16+ path: path.join(os.homedir(), `.${process.env.SSB_APPNAME || process.env.ssb_appname || 'ssb'}`)
17+}
18+const SECRET_PATH = path.join(config.path, 'secret')
19+const MANIFEST_PATH = path.join(config.path, 'manifest.json')
20+const GOSSIP_PATH = path.join(config.path, 'gossip.json')
21+const IMPORT_PATH = path.join(config.path, 'importing.json')
1722
18-var isBusy = Value(false)
19-var isPresentingOptions = Value(true)
20-
2123 // these initial values are overwritten by the identity file.
2224 var state = Struct({
23- latestSequence: 0,
24- confirmedRemotely: false,
25- currentSequence: -1
25+ isPresentingOptions: true,
26+ creatingNewIdentity: false,
27+ mySequence: Struct({
28+ current: 0,
29+ latest: 0,
30+ latestConfirmed: false
31+ }),
32+ peerSequences: Struct({
33+ current: 0,
34+ latest: 0
35+ }),
36+ importComplete: false
2637 })
2738
39+state.peerSequences(console.log)
40+
41+watch(throttle(state.peersLatestSequence, 1000), console.log)
42+
43+// Note you can't want state and get updates to mySequence!
44+watch(throttle(state, 500), s => {
45+ const myFeedSynced = s.mySequence.current >= s.mySequence.latest && s.mySequence.latestConfirmed
46+ const enoughFriends = s.peerSequences.current > 0.95 * s.peerSequences.latest
47+
48+ if (myFeedSynced && enoughFriends) state.importComplete.set(true)
49+})
50+
2851 exports.gives = nest('ftu.app')
2952
3053 exports.needs = nest({
3154 'styles.css': 'reduce',
@@ -40,16 +63,13 @@
4063 const css = [...values(api.styles.css()), ftuCss].join('\n')
4164 document.head.appendChild(h('style', { innerHTML: css }))
4265
4366 // This watcher is responsible for switching from FTU to Ticktack main app
44- watch(throttle(state, 500), s => {
45- if (s.currentSequence >= s.latestSequence && s.confirmedRemotely) {
46- console.log('all imported')
47- electron.ipcRenderer.send('import-completed')
48- }
67+ watch(state.importComplete, importComplete => {
68+ if (importComplete) electron.ipcRenderer.send('import-completed')
4969 })
5070
51- if (fs.existsSync(path.join(CONFIG_FOLDER, 'secret'))) {
71+ if (fs.existsSync(SECRET_PATH)) {
5272 // somehow the FTU started but the identity is already in place.
5373 // treat it as a failed import and start importing...
5474 console.log('resuming import')
5575 let previousData = getImportData()
@@ -59,21 +79,21 @@
5979 // it looks like a normal standard installation...
6080 setImportData({ importing: false })
6181 electron.ipcRenderer.send('import-completed')
6282 } else {
63- state.latestSequence.set(previousData.latestSequence)
64- state.currentSequence.set(previousData.currentSequence)
65- isPresentingOptions.set(false)
66- observeSequence({ state })
83+ state.mySequence.latest.set(previousData.mySequence.latest)
84+ // state.peerSequences.latest.set(previousData.peerSequences.latest) // nor made in exportIdentity yet
85+ state.isPresentingOptions.set(false)
86+ manageProgress({ state, config })
6787 }
6888 }
6989
7090 var app = h('App', [
7191 h('Header', [
7292 h('img.logoName', { src: assetPath('logo_and_name.png') }),
7393 windowControls()
7494 ]),
75- when(isPresentingOptions, InitialOptions(), ImportProgress())
95+ when(state.isPresentingOptions, InitialOptions(), ImportProgress())
7696 ])
7797
7898 return app
7999
@@ -85,9 +105,9 @@
85105 h('section.welcome', [
86106 h('h1', welcomeHeader),
87107 h('div', welcomeMessage)
88108 ]),
89- when(isBusy,
109+ when(state.creatingNewIdentity,
90110 h('p', busyMessage),
91111 h('section.actionButtons', [
92112 h('div.left', h('Button', { 'ev-click': () => actionImportIdentity(strings) }, importAction)),
93113 h('div.right', h('Button -strong', { 'ev-click': () => actionCreateNewOne() }, createAction))
@@ -97,25 +117,40 @@
97117 ])
98118 }
99119
100120 function ImportProgress () {
101- const { header, synchronizeMessage, details } = strings.backup.import
121+ const { header, myFeedProgress, myFriendsProgress, details } = strings.backup.import
102122
103123 return h('Page', [
104124 h('div.content', [
105125 h('h1', header),
106- h('p', synchronizeMessage),
107- h('pre', computed(state, s => {
126+ h('h2', myFeedProgress),
127+ h('pre', computed(state.mySequence, s => {
108128 return progress({
109129 width: 42,
110- total: s.latestSequence,
130+ total: s.latest,
131+ complete: '/',
132+ incomplete: '-',
111133 style: function (complete, incomplete) {
112134 // add an arrow at the head of the completed part
113- return `${complete}>${incomplete} (${s.currentSequence}/ ${s.latestSequence})`
135+ return `[${complete}${incomplete}] (${s.current}/ ${s.latest})`
114136 }
115- })(s.currentSequence)
137+ })(s.current)
116138 })),
117- h('p', details)
139+ h('p', details),
140+ h('h2', myFriendsProgress),
141+ h('pre', computed(state.peerSequences, s => {
142+ return progress({
143+ width: 42,
144+ total: s.latest,
145+ complete: '\\',
146+ incomplete: '-',
147+ style: function (complete, incomplete) {
148+ // add an arrow at the head of the completed part
149+ return `[${complete}${incomplete}] (${s.current}/ ${Math.max(s.latest, s.current)})`
150+ }
151+ })(s.current)
152+ }))
118153 ])
119154 ])
120155 }
121156 }
@@ -124,28 +159,29 @@
124159
125160 electron.ipcRenderer.on('import-resumed', function (ev, c) {
126161 console.log('background process is running, begin observing')
127162
128- observeSequence({ state })
163+ manageProgress({ state, config })
129164 })
130165
131166 function actionCreateNewOne () {
132- isBusy.set(true)
167+ state.creatingNewIdentity.set(true)
168+ /// //////////!!!!!!
169+ // WARNING TODO: this needs replacing with manifest exported from actual sbot running!
133170 const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, '../manifest.json')))
134- const manifestFile = path.join(CONFIG_FOLDER, 'manifest.json')
135- if (!fs.existsSync(CONFIG_FOLDER)) {
136- fs.mkdirSync(CONFIG_FOLDER)
171+ /// //////////!!!!!!
172+ if (!fs.existsSync(config.path)) {
173+ fs.mkdirSync(config.path)
137174 }
138- fs.writeFileSync(manifestFile, JSON.stringify(manifest))
175+ fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest))
139176
140177 electron.ipcRenderer.send('create-new-identity')
141178 }
142179
143180 function actionImportIdentity (strings) {
144- const gossipFile = path.join(CONFIG_FOLDER, 'gossip.json')
145- const secretFile = path.join(CONFIG_FOLDER, 'secret')
181+ /// /////////!!!!!!
182+ // WARNING TODO (same as above warning)
146183 const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, '../manifest.json')))
147- const manifestFile = path.join(CONFIG_FOLDER, 'manifest.json')
148184
149185 // place the other files first
150186 electron.remote.dialog.showOpenDialog(
151187 {
@@ -157,22 +193,23 @@
157193 (filenames) => {
158194 if (typeof filenames !== 'undefined') {
159195 let filename = filenames[0]
160196 let data = JSON.parse(fs.readFileSync(filename))
161- if (data.hasOwnProperty('secret') && data.hasOwnProperty('gossip') && data.hasOwnProperty('latestSequence')) {
162- if (!fs.existsSync(CONFIG_FOLDER)) {
163- fs.mkdirSync(CONFIG_FOLDER)
197+ const requiredProps = ['secret', 'gossip', 'mySequence', 'peersLatestSequence']
198+
199+ if (requiredProps.every(prop => data.hasOwnProperty(prop))) {
200+ if (!fs.existsSync(config.path)) {
201+ fs.mkdirSync(config.path)
164202 }
165203
166- fs.writeFileSync(manifestFile, JSON.stringify(manifest))
167- fs.writeFileSync(gossipFile, JSON.stringify(data.gossip), 'utf8')
168- fs.writeFileSync(secretFile, data.secret, 'utf8')
169- state.latestSequence.set(data.latestSequence)
170- state.currentSequence.set(0)
171- isPresentingOptions.set(false)
204+ fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest))
205+ fs.writeFileSync(GOSSIP_PATH, JSON.stringify(data.gossip), 'utf8')
206+ fs.writeFileSync(SECRET_PATH, data.secret, 'utf8')
172207
208+ state.mySequence.latest.set(data.mySequence.latest)
209+ state.isPresentingOptions.set(false)
210+
173211 data.importing = true
174- data.currentSequence = 0
175212
176213 setImportData(data)
177214
178215 electron.ipcRenderer.send('import-identity')
@@ -190,15 +227,15 @@
190227 return path.join(__dirname, '../assets', name)
191228 }
192229
193230 function getImportData () {
194- if (fs.existsSync(IMPORT_FILE)) {
195- let data = JSON.parse(fs.readFileSync(IMPORT_FILE))
231+ if (fs.existsSync(IMPORT_PATH)) {
232+ let data = JSON.parse(fs.readFileSync(IMPORT_PATH))
196233 return data || false
197234 } else {
198235 return false
199236 }
200237 }
201238
202239 function setImportData (data) {
203- fs.writeFileSync(IMPORT_FILE, JSON.stringify(data))
240+ fs.writeFileSync(IMPORT_PATH, JSON.stringify(data))
204241 }
ftu/observeSequence.jsView
@@ -1,87 +1,0 @@
1-const get = require('lodash/get')
2-const pull = require('pull-stream')
3-const Client = require('ssb-client')
4-const { resolve } = require('mutant')
5-
6-function observeSequence ({ state }) {
7- const config = require('../config').create().config.sync.load()
8-
9- Client(config.keys, config, (err, ssbServer) => {
10- if (err) return console.error('problem starting client', err)
11-
12- console.log('> sbot running!!!!')
13-
14- ssbServer.gossip.peers((err, peers) => {
15- if (err) return console.error(err)
16-
17- connectToPeers(peers)
18- checkPeers()
19- })
20-
21- // start listening to the my seq, and update the state
22- pull(
23- ssbServer.createUserStream({ live: true, id: ssbServer.id }),
24- pull.drain((msg) => {
25- let seq = get(msg, 'value.sequence', false)
26- if (seq) {
27- state.currentSequence.set(seq)
28- }
29- })
30- )
31-
32- function connectToPeers (peers) {
33- if (peers.length > 10) {
34- const lessPeers = peers.filter(p => !p.error)
35- if (lessPeers.length > 10) peers = lessPeers
36- console.log('CONNECTING TO PEERS:', peers.length)
37- }
38-
39- peers.forEach(({ host, port, key }) => {
40- if (host && port && key) {
41- ssbServer.gossip.connect({ host, port, key }, (err, v) => {
42- if (err) console.log('error connecting to ', host, err)
43- else console.log('connected to ', host)
44- })
45- }
46- })
47- }
48-
49- function checkPeers () {
50- ssbServer.ebt.peerStatus(ssbServer.id, (err, data) => {
51- if (err) {
52- setTimeout(checkPeers, 5000)
53- return
54- }
55-
56- const latest = resolve(state.latestSequence)
57-
58- const remoteSeqs = Object.keys(data.peers)
59- .map(p => data.peers[p].seq) // get my seq reported by each peer
60- .filter(s => s >= latest) // only keep remote seq that confirm or update backup seq
61- .sort((a, b) => a > b ? -1 : 1) // order them
62-
63- // console.log(remoteSeqs)
64-
65- const newLatest = remoteSeqs[0]
66- if (newLatest) {
67- state.latestSequence.set(newLatest)
68-
69- // if this value is confirmed remotely twice, assume safe
70- if (remoteSeqs.filter(s => s === newLatest).length >= 2) {
71- state.confirmedRemotely.set(true)
72- }
73- }
74-
75- var s = resolve(state)
76- // NOTE - this 'isDone' logic is repeated in ftu/app.js
77- if (s.currentSequence >= s.latestSequence && s.confirmedRemotely) return
78-
79- setTimeout(checkPeers, 5000)
80- })
81-
82- ssbServer.progress(console.log)
83- }
84- })
85-}
86-
87-module.exports = observeSequence
ftu/manageProgress.jsView
@@ -1,0 +1,155 @@
1+const pull = require('pull-stream')
2+const Client = require('ssb-client')
3+const Path = require('path')
4+const get = require('lodash/get')
5+const map = require('lodash/map')
6+const { resolve, watch } = require('mutant')
7+const mapLimit = require('map-limit')
8+
9+function manageProgress ({ state, config }) {
10+ const { peersLatestSequence } = require(Path.join(config.path, 'importing.json'))
11+
12+ Client(config.keys, config, (err, sbot) => {
13+ if (err) return console.error('problem starting client', err)
14+
15+ console.log('> sbot running!!!!')
16+
17+ watchCurrentSequence({ sbot, state })
18+ watchLatestSequence({ sbot, period: 5000, state })
19+ watchPeersLatestSequence({ sbot, peersLatestSequence, period: 10000, state })
20+
21+ // pull(
22+ // sbot.replicate.changes(),
23+ // pull.log()
24+ // )
25+
26+ // watch progress (db size) ??
27+ // sbot.progress(console.log)
28+ //
29+ sbot.gossip.peers((err, peers) => {
30+ if (err) return console.error(err)
31+
32+ connectToPeers({ sbot, peers, state })
33+ })
34+ })
35+}
36+
37+function connectToPeers ({ sbot, peers, state }) {
38+ if (peers.length > 10) {
39+ const lessPeers = peers.filter(p => !p.error)
40+ if (lessPeers.length > 10) peers = lessPeers
41+ console.log('CONNECTING TO PEERS:', peers.length)
42+ }
43+
44+ peers.forEach(({ host, port, key }) => {
45+ if (host && port && key) {
46+ sbot.gossip.connect({ host, port, key }, (err, v) => {
47+ if (err) console.log('error connecting to ', host, err)
48+ else console.log('connected to ', host)
49+ })
50+ }
51+ })
52+}
53+
54+function watchCurrentSequence ({ sbot, state }) {
55+ var sink = pull.drain((msg) => {
56+ let seq = get(msg, 'value.sequence', false)
57+ if (seq) state.mySequence.current.set(seq)
58+ })
59+
60+ pull(
61+ sbot.createUserStream({ live: true, id: sbot.id }),
62+ sink
63+ )
64+
65+ watch(state.importComplete, importComplete => {
66+ if (importComplete) sink.abort(() => console.log('stopping watchCurrentSequence'))
67+ })
68+}
69+
70+function watchLatestSequence ({ sbot, period, state }) {
71+ const feedId = sbot.id
72+ sbot.ebt.peerStatus(feedId, (err, data) => {
73+ if (err) return setTimeout(() => watchLatestSequence({ sbot, period, state }), period)
74+
75+ const currentLatest = resolve(state.mySequence.latest)
76+
77+ const remoteSeqs = map(data.peers, (val) => val.seq)
78+ .filter(s => s >= currentLatest) // only keep remote seq that confirm or update backup seq
79+ .sort((a, b) => a > b ? -1 : 1) // order them
80+
81+ console.log('mySequence.latest', resolve(state.mySequence.latest), remoteSeqs)
82+ const newLatest = remoteSeqs[0]
83+ if (newLatest && newLatest >= resolve(state.mySequence.latest)) {
84+ state.mySequence.latest.set(newLatest)
85+
86+ // if this value is confirmed remotely twice, assume safe
87+ if (remoteSeqs.filter(s => s === newLatest).length >= 2) {
88+ state.mySequence.latestConfirmed.set(true)
89+ }
90+ }
91+
92+ if (resolve(state.importComplete)) return
93+
94+ setTimeout(() => watchLatestSequence({ sbot, period, state }), period)
95+ })
96+}
97+
98+function watchPeersLatestSequence ({ sbot, peersLatestSequence, period, state }) {
99+ mapLimit(Object.keys(peersLatestSequence), 5,
100+ (id, cb) => sbot.latestSequence(id, (err, seq) => {
101+ if (err && err.message && err.message.indexOf('not found') > -1) {
102+ return cb(null, null) // don't include this user
103+ }
104+ if (err) return cb(err)
105+ cb(null, [id, seq])
106+ }),
107+ (err, data) => {
108+ if (err) return setTimeout(() => watchPeersLatestSequence({ sbot, peersLatestSequence, period, state }), period)
109+
110+ const results = data
111+ .filter(Boolean)
112+ .reduce((soFar, d) => {
113+ soFar.current = soFar.current + d[1]
114+ soFar.latest = soFar.latest + peersLatestSequence[d[0]]
115+
116+ return soFar
117+ }, { current: 0, latest: 0 })
118+
119+ state.peerSequences.set(results) // NOT WORKING yet
120+
121+ // const results = data
122+ // .filter(Boolean)
123+ // .reduce((soFar, d) => {
124+ // soFar[d[0]] = {
125+ // progress: d[1],
126+ // total: peersLatestSequence[d[0]]
127+ // }
128+ // return soFar
129+ // }, {})
130+ // console.log('progress', results)
131+
132+ if (resolve(state.importComplete)) return
133+
134+ setTimeout(() => watchPeersLatestSequence({ sbot, peersLatestSequence, period, state }), period)
135+ }
136+ )
137+
138+ // NOTE this would be to do something with remote state of peers
139+ // Object.keys(peersLatestSequence).forEach(peerId => {
140+ // sbot.ebt.peerStatus(peerId, (err, data) => {
141+ // if (err) return
142+ // const currentLatest = peersLatestSequence[peerId]
143+
144+ // const remoteSeq = map(data.peers, (val) => val.seq)
145+ // .filter(s => s >= currentLatest)
146+ // .sort((a, b) => a > b ? -1 : 1)
147+ // .shift()
148+
149+ // console.log(peerId, currentLatest, remoteSeq)
150+ // })
151+ // })
152+
153+}
154+
155+module.exports = manageProgress
translations/en.jsView
@@ -214,9 +214,10 @@
214214 },
215215 import: {
216216 importAction: 'Import Identity',
217217 header: 'Importing identity',
218- synchronizeMessage: 'Progress',
218+ myFeedProgress: 'Progress (your identity)',
219+ myFriendsProgress: 'Progress (your friends)',
219220 dialog: {
220221 label: 'Import Identity',
221222 title: 'Import Identity'
222223 },

Built with git-ssb-web