Files: ec2cfa20da9cb844e2d27ddebc9686389de38874 / server.js
6047 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: 'Quit', |
113 | tooltip: 'Stop sbot and quit tray application', |
114 | checked: false, |
115 | enabled: true |
116 | } |
117 | ] |
118 | }, |
119 | debug: false, |
120 | copyDir: true |
121 | }) |
122 | |
123 | tray.on('click', (action) => { |
124 | console.log('scuttle-shell got action:', action) |
125 | switch (action.item.title) { |
126 | case 'Quit': |
127 | console.log('### EXITING IN TWO SECONDS ###') |
128 | |
129 | notifier.notify({ |
130 | title: 'Secure Scuttlebutt', |
131 | message: `Secure Scuttlebutt will exit in two seconds...`, |
132 | icon: path.join(__dirname, 'icon.png'), |
133 | wait: true, |
134 | id: 0 |
135 | }) |
136 | |
137 | tray.kill() |
138 | } |
139 | }) |
140 | |
141 | tray.on('exit', (code, signal) => { |
142 | console.log('scuttle-shell got exit:', code) |
143 | setTimeout(() => |
144 | process.exit(0), 2000) |
145 | }) |
146 | |
147 | const sbotVersion = server.version() |
148 | console.log(`started sbot server v${sbotVersion}`) |
149 | |
150 | server.about.get((err, curr) => { |
151 | if (err) { |
152 | console.warn('got err from about idx:', err) |
153 | return |
154 | } |
155 | const myName = curr[ssbConfig.keys.id]['name'][ssbConfig.keys.id] |
156 | if (myName instanceof Array && myName.length === 2) { // format is [ 'name', ts ] |
157 | console.log('updating menu with', myName[0]) |
158 | tray.emit('action', { |
159 | type: 'update-item', |
160 | seq_id: 0, |
161 | item: { |
162 | title: `@${myName[0]}`, |
163 | tooltip: ssbConfig.keys.id, |
164 | checked: false, |
165 | enabled: false |
166 | } |
167 | }) |
168 | } |
169 | }) |
170 | donecb(null) |
171 | } |
172 | |
173 | function stop () { |
174 | // todo: sbot shutdown handler? |
175 | tray.kill() |
176 | } |
177 | |
178 | const getConfig = () => { |
179 | if (ssbConfig === null) { |
180 | return { type: 'error', msg: 'uninitialized config - call start() first' } |
181 | } |
182 | try { |
183 | const k = ssbConfig.keys |
184 | const manifest = JSON.parse(fs.readFileSync(path.join(ssbConfig.path, 'manifest.json'))) |
185 | const remote = 'ws://localhost:8989~shs:' + k.id.substring(1, k.id.indexOf('.')) |
186 | return { |
187 | type: 'config', |
188 | keys: k, |
189 | manifest: manifest, |
190 | remote: remote |
191 | } |
192 | } catch (n) { |
193 | return { type: 'error', msg: n.message } |
194 | } |
195 | } |
196 | |
197 | module.exports = { start, stop, getConfig } |
198 | |
199 | if (require.main === module) { |
200 | start({}, (err) => { |
201 | if (err) console.error(err) |
202 | }) |
203 | } |
204 |
Built with git-ssb-web