git ssb

2+

mixmix / ticktack



Tree: af7a4df07ba10c8db16edf9a61244f671fe0fbf1

Files: af7a4df07ba10c8db16edf9a61244f671fe0fbf1 / ftu / app.js

6929 bytesRaw
1const { h, Value, when, resolve, computed, Struct, watch } = require('mutant')
2const nest = require('depnest')
3const path = require('path')
4const fs = require('fs')
5const { remote } = require('electron')
6const insertCss = require('insert-css')
7const values = require('lodash/values')
8const electron = require('electron')
9const { dialog } = require('electron').remote
10const os = require('os')
11const appName = process.env.SSB_APPNAME || 'ssb'
12const configFolder = path.join(os.homedir(), `.${appName}`)
13
14var isBusy = Value(false)
15var isPresentingOptions = Value(true)
16
17// these initial values are overwritten by the identity file.
18var state = Struct({
19 latestSequence: 0,
20 currentSequence: -1
21})
22
23exports.gives = nest('ftu.app')
24
25exports.needs = nest({
26 'styles.css': 'reduce',
27 'translations.sync.strings': 'first',
28})
29
30exports.create = (api) => {
31 return nest({
32 'ftu.app': function app() {
33
34 const strings = api.translations.sync.strings()
35
36 const css = values(api.styles.css()).join('\n')
37 insertCss(css)
38
39 var actionButtons = h('section', [
40 h('div.left', h('Button', { 'ev-click': () => actionImportIdentity(strings) }, strings.backup.ftu.importAction)),
41 h('div.right', h('Button', { 'ev-click': () => actionCreateNewOne() }, strings.backup.ftu.createAction))
42 ])
43
44 var busyMessage = h('p', strings.backup.ftu.busyMessage)
45
46 var initialOptions = h('Page -ftu', [
47 h('div.content', [
48 h('h1', strings.backup.ftu.welcomeHeader),
49 h('p', strings.backup.ftu.welcomeMessage),
50 when(isBusy, busyMessage, actionButtons)
51 ])
52 ])
53
54 var importProcess = h('Page -ftu', [
55 h('div.content', [
56 h('h1', strings.backup.import.header),
57 h('p', [strings.backup.import.synchronizeMessage, state.currentSequence, '/', state.latestSequence]),
58 ])
59 ])
60
61 // This watcher is responsible for switching from FTU to Ticktack main app
62 watch(state, s => {
63 if (s.currentSequence >= s.latestSequence) {
64 console.log('all imported')
65 electron.ipcRenderer.send('import-completed')
66 }
67 })
68
69 if (fs.existsSync(path.join(configFolder, "secret"))) {
70 // somehow the FTU started but the identity is already in place.
71 // treat it as a failed import and start importing...
72 console.log('resuming import')
73 let previousData = getImportData()
74 state.latestSequence.set(previousData.latestSequence)
75 state.currentSequence.set(previousData.currentSequence)
76 isPresentingOptions.set(false)
77 observeSequence()
78 }
79
80 var app = h('App', [
81 h('Header', [
82 windowControls()
83 ]),
84 when(isPresentingOptions, initialOptions, importProcess)
85 ])
86
87 return app
88 }
89 })
90}
91
92electron.ipcRenderer.on('import-started', function (ev, c) {
93 console.log('background process is running, begin observing')
94
95 observeSequence()
96})
97
98
99
100function actionCreateNewOne() {
101 isBusy.set(true)
102 const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, "../manifest.json")))
103 const manifestFile = path.join(configFolder, 'manifest.json')
104 if (!fs.existsSync(configFolder)) {
105 fs.mkdirSync(configFolder)
106 }
107 fs.writeFileSync(manifestFile, JSON.stringify(manifest))
108
109
110 electron.ipcRenderer.send('create-new-identity')
111}
112
113function actionImportIdentity(strings) {
114 const peersFile = path.join(configFolder, "gossip.json")
115 const secretFile = path.join(configFolder, "secret")
116 const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, "../manifest.json")))
117 const manifestFile = path.join(configFolder, 'manifest.json')
118
119 // place the other files first
120 dialog.showOpenDialog(
121 {
122 title: strings.backup.import.dialog.title,
123 butttonLabel: strings.backup.import.dialog.label,
124 defaultPath: 'ticktack-identity.backup',
125 properties: ['openFile']
126 },
127 (filenames) => {
128 if (typeof filenames !== "undefined") {
129 let filename = filenames[0]
130 let data = JSON.parse(fs.readFileSync(filename))
131 if (data.hasOwnProperty("secret") && data.hasOwnProperty("peers") && data.hasOwnProperty("latestSequence")) {
132 if (!fs.existsSync(configFolder)) {
133 fs.mkdirSync(configFolder)
134 }
135
136 fs.writeFileSync(manifestFile, JSON.stringify(manifest))
137 fs.writeFileSync(peersFile, JSON.stringify(data.peers), "utf8")
138 fs.writeFileSync(secretFile, data.secret, "utf8")
139 state.latestSequence.set(data.latestSequence)
140 state.currentSequence.set(0)
141 isPresentingOptions.set(false)
142
143 data.importing = true
144 data.currentSequence = 0
145
146 setImportData(data)
147
148 electron.ipcRenderer.send('import-identity')
149 } else {
150 console.log("> bad export file")
151 console.log(data)
152 alert("Bad Export File")
153 }
154 }
155 }
156 )
157}
158
159function windowControls() {
160 if (process.platform === 'darwin') return
161
162 const window = remote.getCurrentWindow()
163 const minimize = () => window.minimize()
164 const maximize = () => {
165 if (!window.isMaximized()) window.maximize()
166 else window.unmaximize()
167 }
168 const close = () => window.close()
169
170 return h('div.window-controls', [
171 h('img.min', {
172 src: assetPath('minimize.png'),
173 'ev-click': minimize
174 }),
175 h('img.max', {
176 src: assetPath('maximize.png'),
177 'ev-click': maximize
178 }),
179 h('img.close', {
180 src: assetPath('close.png'),
181 'ev-click': close
182 })
183 ])
184}
185
186
187function assetPath(name) {
188 return path.join(__dirname, '../assets', name)
189}
190
191
192function getImportData() {
193 var importFile = path.join(configFolder, 'importing.json')
194 if (fs.existsSync(importFile)) {
195 let data = JSON.parse(fs.readFileSync(importFile))
196 return data || false
197 } else {
198 return false
199 }
200}
201
202function setImportData(data) {
203 var importFile = path.join(configFolder, 'importing.json')
204 fs.writeFileSync(importFile, JSON.stringify(data))
205}
206
207function observeSequence() {
208 const pull = require('pull-stream')
209 const Client = require('ssb-client')
210 const config = require('../config').create().config.sync.load()
211 const _ = require('lodash')
212
213 Client(config.keys, config, (err, ssbServer) => {
214 if (err) {
215 console.error('problem starting client', err)
216 } else {
217 console.log('> sbot running!!!!')
218 ssbServer.whoami((err, data) => {
219 console.log("whoami", data.id)
220
221 var feedSource = ssbServer.createUserStream({
222 live: true,
223 id: data.id
224 })
225
226 var valueLogger = pull.drain((msg) => {
227 console.log("msg", msg)
228
229 let seq = _.get(msg, "value.sequence", false)
230 if (seq) {
231 state.currentSequence.set(seq)
232 }
233 })
234
235 pull(
236 feedSource,
237 valueLogger,
238 )
239
240 })
241 }
242 })
243}

Built with git-ssb-web