Files: 89fcc0043e8f853739d0a8a922763779d2007b6d / server.js
6569 bytesRaw
1 | |
2 | |
3 | const fs = require('fs') |
4 | const path = require('path') |
5 | const ssbKeys = require('ssb-keys') |
6 | const minimist = require('minimist') |
7 | const notifier = require('node-notifier') |
8 | const SysTray = require('forked-systray').default |
9 | |
10 | // uninitialized |
11 | let tray = null |
12 | let ssbConfig = null |
13 | |
14 | function noop () {} |
15 | |
16 | function start (customConfig, donecb) { |
17 | donecb = donecb || noop |
18 | // TODO: try { allthethings } catch(e) { donecb(e) } |
19 | customConfig = customConfig || {} |
20 | let appname = customConfig.appname || false |
21 | let customPluginPaths = customConfig.plugins || false |
22 | let argv = process.argv.slice(2) |
23 | let i = argv.indexOf('--') |
24 | let conf = argv.slice(i + 1) |
25 | argv = ~i ? argv.slice(0, i) : argv |
26 | let ssbAppName = appname || process.env.ssb_appname |
27 | |
28 | const config = require('ssb-config/inject')(ssbAppName, minimist(conf)) |
29 | |
30 | const keys = ssbKeys.loadOrCreateSync(path.join(config.path, 'secret')) |
31 | if (keys.curve === 'k256') { |
32 | // i think this is _really_ old and could be removed |
33 | throw new Error('k256 curves are no longer supported,' + |
34 | 'please delete' + path.join(config.path, 'secret')) |
35 | } |
36 | config.keys = keys |
37 | ssbConfig = config |
38 | |
39 | const manifestFile = path.join(config.path, 'manifest.json') |
40 | |
41 | const createSbot = require('scuttlebot') |
42 | .use(require('scuttlebot/plugins/master')) |
43 | .use(require('scuttlebot/plugins/gossip')) |
44 | .use(require('scuttlebot/plugins/replicate')) |
45 | .use(require('scuttlebot/plugins/invite')) |
46 | .use(require('scuttlebot/plugins/local')) |
47 | .use(require('scuttlebot/plugins/logging')) |
48 | .use(require('ssb-about')) |
49 | .use(require('ssb-backlinks')) |
50 | .use(require('ssb-blobs')) |
51 | .use(require('ssb-chess-db')) |
52 | .use(require('ssb-ebt')) |
53 | .use(require('ssb-friends')) |
54 | .use(require('ssb-links')) // needed by patchfoo |
55 | .use(require('ssb-names')) |
56 | .use(require('ssb-meme')) |
57 | .use(require('ssb-ooo')) |
58 | .use(require('ssb-private')) |
59 | .use(require('ssb-query')) |
60 | .use(require('ssb-search')) |
61 | .use(require('ssb-talequery')) // only tale:net |
62 | .use(require('ssb-unread')) |
63 | .use(require('ssb-ws')) |
64 | |
65 | // load user plugins (from $HOME/.ssb/node_modules using $HOME/.ssb/config plugins {name:true}) |
66 | require('scuttlebot/plugins/plugins').loadUserPlugins(createSbot, config) |
67 | |
68 | // Custom plugins from json |
69 | let appManifestFile = path.resolve('scuttleshell.json') |
70 | if (fs.existsSync(appManifestFile)) { |
71 | let manifest = JSON.parse(fs.readFileSync(appManifestFile)) |
72 | if (manifest.hasOwnProperty('plugins') && Array.isArray(manifest.plugins)) { |
73 | console.log('loading custom plugins: ', manifest.plugins.join(', ')) |
74 | manifest.plugins.forEach(plugin => createSbot.use(require(plugin))) |
75 | } |
76 | } |
77 | |
78 | // from customConfig.plugins |
79 | if (Array.isArray(customPluginPaths)) { |
80 | console.log('loading custom plugins: ', customPluginPaths.join(', ')) |
81 | customPluginPaths.forEach(plugin => createSbot.use(require(plugin))) |
82 | } |
83 | |
84 | // --extra-plugin |
85 | const args = minimist(process.argv.slice(1)) |
86 | const extraPlugin = args['extra-plugin'] |
87 | if (typeof extraPlugin === 'string') { // one |
88 | createSbot.use(require(extraPlugin)) |
89 | } else if (extraPlugin instanceof Array) { // multiple |
90 | extraPlugin.forEach((plugPath) => createSbot.use(require(plugPath))) |
91 | } |
92 | |
93 | // start server |
94 | const server = createSbot(config) |
95 | |
96 | // write RPC manifest to ~/.ssb/manifest.json |
97 | fs.writeFileSync(manifestFile, JSON.stringify(server.getManifest(), null, 2)) |
98 | |
99 | const icon = fs.readFileSync(path.join(__dirname, `icon.${process.platform === 'win32' ? 'ico' : 'png'}`)) |
100 | tray = new SysTray({ |
101 | menu: { |
102 | icon: icon.toString('base64'), |
103 | title: 'Scuttle-Shell', |
104 | tooltip: 'Secure Scuttlebutt', |
105 | items: [ |
106 | { |
107 | title: 'starting...', |
108 | checked: false, |
109 | enabled: true |
110 | }, |
111 | { |
112 | title: 'version: unset', |
113 | checked: false, |
114 | enabled: false |
115 | }, |
116 | { |
117 | title: 'Quit', |
118 | tooltip: 'Stop sbot and quit tray application', |
119 | checked: false, |
120 | enabled: true |
121 | } |
122 | ] |
123 | }, |
124 | debug: false, |
125 | copyDir: true |
126 | }) |
127 | |
128 | tray.on('click', (action) => { |
129 | console.log('scuttle-shell got action:', action) |
130 | switch (action.item.title) { |
131 | case 'Quit': |
132 | console.log('### EXITING IN TWO SECONDS ###') |
133 | |
134 | notifier.notify({ |
135 | title: 'Secure Scuttlebutt', |
136 | message: `Secure Scuttlebutt will exit in two seconds...`, |
137 | icon: path.join(__dirname, 'icon.png'), |
138 | wait: true, |
139 | id: 0 |
140 | }) |
141 | |
142 | tray.kill() |
143 | } |
144 | }) |
145 | |
146 | tray.on('exit', (code, signal) => { |
147 | console.log('scuttle-shell got exit:', code) |
148 | setTimeout(() => |
149 | process.exit(0), 2000) |
150 | }) |
151 | |
152 | const sbotVersion = server.version() |
153 | console.log(`started sbot server v${sbotVersion}`) |
154 | tray.emit('action', { |
155 | type: 'update-item', |
156 | seq_id: 1, |
157 | item: { |
158 | title: `sbot version: ${sbotVersion}`, |
159 | checked: false, |
160 | enabled: false |
161 | } |
162 | }) |
163 | |
164 | server.about.get((err, curr) => { |
165 | if (err) { |
166 | console.warn('got err from about idx:', err) |
167 | return |
168 | } |
169 | // new key maybe? might not have set a name yet |
170 | if (typeof curr === 'undefined') { |
171 | return |
172 | } |
173 | const myAbouts = curr[ssbConfig.keys.id] |
174 | if (typeof myAbouts === 'undefined') { |
175 | return |
176 | } |
177 | const myNames = myAbouts['name'] |
178 | if (typeof myNames === 'undefined') { |
179 | return |
180 | } |
181 | const fromMe = myNames[ssbConfig.keys.id] |
182 | if (fromMe instanceof Array && fromMe.length === 2) { // format is [ 'name', ts ] |
183 | tray.emit('action', { |
184 | type: 'update-item', |
185 | seq_id: 0, |
186 | item: { |
187 | title: `@${fromMe[0]}`, |
188 | tooltip: ssbConfig.keys.id, |
189 | checked: false, |
190 | enabled: false |
191 | } |
192 | }) |
193 | } |
194 | }) |
195 | donecb(null) |
196 | } |
197 | |
198 | function stop () { |
199 | // todo: sbot shutdown handler? |
200 | tray.kill() |
201 | } |
202 | |
203 | const getConfig = () => { |
204 | if (ssbConfig === null) { |
205 | return { type: 'error', msg: 'uninitialized config - call start() first' } |
206 | } |
207 | try { |
208 | const k = ssbConfig.keys |
209 | const manifest = JSON.parse(fs.readFileSync(path.join(ssbConfig.path, 'manifest.json'))) |
210 | const remote = 'ws://localhost:8989~shs:' + k.id.substring(1, k.id.indexOf('.')) |
211 | return { |
212 | type: 'config', |
213 | keys: k, |
214 | manifest: manifest, |
215 | remote: remote |
216 | } |
217 | } catch (n) { |
218 | return { type: 'error', msg: n.message } |
219 | } |
220 | } |
221 | |
222 | module.exports = { start, stop, getConfig } |
223 | |
224 | if (require.main === module) { |
225 | start({}, (err) => { |
226 | if (err) console.error(err) |
227 | }) |
228 | } |
229 |
Built with git-ssb-web