git ssb

2+

mixmix / ticktack



Tree: 0818fbce083be238b301bb475711fa9ee88e69b0

Files: 0818fbce083be238b301bb475711fa9ee88e69b0 / ftu / app.js

6652 bytesRaw
1const { h, Value, when, computed, Struct, watch, throttle } = require('mutant')
2const nest = require('depnest')
3const path = require('path')
4const fs = require('fs')
5const electron = require('electron')
6const os = require('os')
7const progress = require('progress-string')
8const values = require('lodash/values')
9
10const observeSequence = require('./observeSequence')
11const windowControls = require('../windowControls')
12const ftuCss = require('./styles')
13
14const appName = process.env.SSB_APPNAME || 'ssb'
15const CONFIG_FOLDER = path.join(os.homedir(), `.${appName}`)
16const IMPORT_FILE = path.join(CONFIG_FOLDER, 'importing.json')
17
18var isBusy = Value(false)
19var isPresentingOptions = Value(true)
20
21// these initial values are overwritten by the identity file.
22var state = Struct({
23 latestSequence: 0,
24 confirmedRemotely: false,
25 currentSequence: -1
26})
27
28exports.gives = nest('ftu.app')
29
30exports.needs = nest({
31 'styles.css': 'reduce',
32 'translations.sync.strings': 'first'
33})
34
35exports.create = (api) => {
36 return nest({
37 'ftu.app': function app () {
38 const strings = api.translations.sync.strings()
39
40 const css = [...values(api.styles.css()), ftuCss].join('\n')
41 document.head.appendChild(h('style', { innerHTML: css }))
42
43 // 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 }
49 })
50
51 if (fs.existsSync(path.join(CONFIG_FOLDER, 'secret'))) {
52 // somehow the FTU started but the identity is already in place.
53 // treat it as a failed import and start importing...
54 console.log('resuming import')
55 let previousData = getImportData()
56 if (previousData === false) {
57 // there is a secret but there is no previous import data.
58 // so, we proceed as normal because we can't do anything else,
59 // it looks like a normal standard installation...
60 setImportData({ importing: false })
61 electron.ipcRenderer.send('import-completed')
62 } else {
63 state.latestSequence.set(previousData.latestSequence)
64 state.currentSequence.set(previousData.currentSequence)
65 isPresentingOptions.set(false)
66 observeSequence({ state })
67 }
68 }
69
70 var app = h('App', [
71 h('Header', [
72 h('img.logoName', { src: assetPath('logo_and_name.png') }),
73 windowControls()
74 ]),
75 when(isPresentingOptions, InitialOptions(), ImportProgress())
76 ])
77
78 return app
79
80 function InitialOptions () {
81 const { welcomeHeader, welcomeMessage, busyMessage, importAction, createAction } = strings.backup.ftu
82
83 return h('Page', [
84 h('div.content', [
85 h('section.welcome', [
86 h('h1', welcomeHeader),
87 h('div', welcomeMessage)
88 ]),
89 when(isBusy,
90 h('p', busyMessage),
91 h('section.actionButtons', [
92 h('div.left', h('Button', { 'ev-click': () => actionImportIdentity(strings) }, importAction)),
93 h('div.right', h('Button -strong', { 'ev-click': () => actionCreateNewOne() }, createAction))
94 ])
95 )
96 ])
97 ])
98 }
99
100 function ImportProgress () {
101 const { header, synchronizeMessage, details } = strings.backup.import
102
103 return h('Page', [
104 h('div.content', [
105 h('h1', header),
106 h('p', synchronizeMessage),
107 h('pre', computed(state, s => {
108 return progress({
109 width: 42,
110 total: s.latestSequence,
111 style: function (complete, incomplete) {
112 // add an arrow at the head of the completed part
113 return `${complete}>${incomplete} (${s.currentSequence}/ ${s.latestSequence})`
114 }
115 })(s.currentSequence)
116 })),
117 h('p', details)
118 ])
119 ])
120 }
121 }
122 })
123}
124
125electron.ipcRenderer.on('import-resumed', function (ev, c) {
126 console.log('background process is running, begin observing')
127
128 observeSequence({ state })
129})
130
131function actionCreateNewOne () {
132 isBusy.set(true)
133 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)
137 }
138 fs.writeFileSync(manifestFile, JSON.stringify(manifest))
139
140 electron.ipcRenderer.send('create-new-identity')
141}
142
143function actionImportIdentity (strings) {
144 const peersFile = path.join(CONFIG_FOLDER, 'gossip.json')
145 const secretFile = path.join(CONFIG_FOLDER, 'secret')
146 const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, '../manifest.json')))
147 const manifestFile = path.join(CONFIG_FOLDER, 'manifest.json')
148
149 // place the other files first
150 electron.remote.dialog.showOpenDialog(
151 {
152 title: strings.backup.import.dialog.title,
153 butttonLabel: strings.backup.import.dialog.label,
154 defaultPath: 'ticktack-identity.backup',
155 properties: ['openFile']
156 },
157 (filenames) => {
158 if (typeof filenames !== 'undefined') {
159 let filename = filenames[0]
160 let data = JSON.parse(fs.readFileSync(filename))
161 if (data.hasOwnProperty('secret') && data.hasOwnProperty('peers') && data.hasOwnProperty('latestSequence')) {
162 if (!fs.existsSync(CONFIG_FOLDER)) {
163 fs.mkdirSync(CONFIG_FOLDER)
164 }
165
166 fs.writeFileSync(manifestFile, JSON.stringify(manifest))
167 fs.writeFileSync(peersFile, JSON.stringify(data.peers), 'utf8')
168 fs.writeFileSync(secretFile, data.secret, 'utf8')
169 state.latestSequence.set(data.latestSequence)
170 state.currentSequence.set(0)
171 isPresentingOptions.set(false)
172
173 data.importing = true
174 data.currentSequence = 0
175
176 setImportData(data)
177
178 electron.ipcRenderer.send('import-identity')
179 } else {
180 console.log('> bad export file')
181 console.log(data)
182 alert('Bad Export File')
183 }
184 }
185 }
186 )
187}
188
189function assetPath (name) {
190 return path.join(__dirname, '../assets', name)
191}
192
193function getImportData () {
194 if (fs.existsSync(IMPORT_FILE)) {
195 let data = JSON.parse(fs.readFileSync(IMPORT_FILE))
196 return data || false
197 } else {
198 return false
199 }
200}
201
202function setImportData (data) {
203 fs.writeFileSync(IMPORT_FILE, JSON.stringify(data))
204}
205

Built with git-ssb-web