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