git ssb

1+

mixmix / scuttle-shell



Commit 4933e4b778bdb7bc249725e152a78612fe6fcb5c

Merge pull request #9 from ssbc/enhancement-custom-plugins

Enhancement: custom plugins
Henry authored on 9/20/2018, 3:04:46 PM
GitHub committed on 9/20/2018, 3:04:46 PM
Parent: 69094b14d8a0f96b5da1d4ce1008b7ba2ceb94d3
Parent: 20fb2ab17ea2bdbea42eda88b7d13cf5065dccf4

Files changed

README.mdchanged
examples/launch_sbot_custom_plugin.jsadded
examples/service-discovery/index.jsadded
package-lock.jsonchanged
package.jsonchanged
server.jschanged
.travis.runtest.shadded
.travis.ymladded
README.mdView
@@ -67,4 +67,23 @@
6767
6868 ```
6969 $ npm install
7070 ```
71 +
72 +### Plugins
73 +
74 +scuttle-shell supports mutliple ways to extend the sbot that it runs with pluigns (like [ssb-chess-db](https://github.com/Happy0/ssb-chess-db) or [ssb-query](https://github.com/dominictarr/ssb-query)).
75 +
76 +First of all, it supports and loads the plugins that were installed by running `sbot plugins.install ...`.
77 +These are stored under `$HOME/.ssb/node_modules`.
78 +
79 +Additonally, you can either pass the file paths to the API constructor by adding a `plugins` field to the object you pass to `.start()`. Check out `examples/launch_sbot_custom_plugin.js` to see it in action.
80 +
81 +Alternativly you can use the command-line flag of `scuttleshell`, named `--extra-plugins`. i.e. `scuttleshell --extra-plugin path/to/plugin1 --extra-plugin path/to/plugin2`. Please not that these are not installed or persisted, you need to take care of that.
82 +
83 +If you don't want to store them in the `$HOME/.ssb` folder, there is also the option to create a `scuttleshell.json` file next to your custom scuttle-shell and set a `plugins` array inside it.
84 +
85 +```json
86 +{
87 + 'plugins': ['path/to/plug1','path/to/plug2','path/to/plug3']
88 +}
89 +```
examples/launch_sbot_custom_plugin.jsView
@@ -1,0 +1,7 @@
1 +let scuttleshell = require("../server")
2 +
3 +console.log("Starting sbot, quitting after 30 seconds")
4 +console.log("open http://localhost:8989/get-address")
5 +scuttleshell.start({ plugins: ["./examples/service-discovery"] })
6 +
7 +setTimeout(scuttleshell.stop, 30000)
examples/service-discovery/index.jsView
@@ -1,0 +1,14 @@
1 +module.exports = {
2 + name: 'server-discovery',
3 + version: '1.0.0',
4 + init: function (sbot) {
5 + sbot.ws.use(function (req, res, next) {
6 + res.setHeader('Access-Control-Allow-Origin', '*')
7 + if (req.url === '/get-address') {
8 + res.end(sbot.ws.getAddress())
9 + } else {
10 + next()
11 + }
12 + })
13 + }
14 +}
package-lock.jsonView
The diff is too large to show. Use a local git client to view these changes.
Old file size: 158269 bytes
New file size: 178475 bytes
package.jsonView
@@ -1,8 +1,8 @@
11 {
22 "name": "scuttle-shell",
33 "description": "A system tray app for running Secure Scuttlebutt on your local system",
4- "version": "0.0.3",
4 + "version": "0.0.4-snapshot",
55 "author": {
66 "name": "Andre Alves Garzia",
77 "email": "andre@andregarzia.com",
88 "url": "http://andregarzia.com"
@@ -18,28 +18,31 @@
1818 },
1919 "dependencies": {
2020 "chrome-native-messaging": "^0.2.0",
2121 "ecstatic": "^3.1.0",
22 + "forked-systray": "^3.0.2",
2223 "minimist": "^1.2.0",
2324 "node-notifier": "^5.2.1",
24- "scuttlebot": "^11.3.3",
25 + "scuttlebot": "^12.0.1",
2526 "ssb-about": "^0.1.2",
2627 "ssb-backlinks": "^0.7.1",
2728 "ssb-blobs": "^1.1.4",
2829 "ssb-chess-db": "^1.0.3",
2930 "ssb-config": "^2.2.0",
3031 "ssb-ebt": "^5.2.0",
31- "ssb-friends": "^2.4.0",
32 + "ssb-friends": "^3.1.3",
3233 "ssb-keys": "^7.0.13",
34 + "ssb-links": "^3.0.3",
3335 "ssb-meme": "^1.0.4",
3436 "ssb-names": "^3.1.0",
3537 "ssb-ooo": "^1.0.7",
3638 "ssb-private": "^0.2.1",
3739 "ssb-query": "^2.1.0",
3840 "ssb-search": "^1.1.1",
41 + "ssb-talequery": "^2.0.1",
42 + "ssb-unread": "^1.0.1",
3943 "ssb-web-resolver": "^1.1.2",
40- "ssb-ws": "^2.0.0",
41- "systray": "^1.0.3"
44 + "ssb-ws": "^2.0.0"
4245 },
4346 "scripts": {
4447 "start": "node server.js",
4548 "check-win": "node scripts/check-configuration-win.js",
server.jsView
@@ -4,53 +4,94 @@
44 const path = require('path')
55 const ssbKeys = require('ssb-keys')
66 const minimist = require('minimist')
77 const notifier = require('node-notifier')
8-const SysTray = require('systray').default
9-let tray = {}
8 +const SysTray = require('forked-systray').default
109
11-function start(appname) {
10 +// uninitialized
11 +let tray = null
12 +let ssbConfig = null
1213
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
1322 let argv = process.argv.slice(2)
1423 let i = argv.indexOf('--')
1524 let conf = argv.slice(i + 1)
1625 argv = ~i ? argv.slice(0, i) : argv
17- let ssb_appname = appname ? appname : process.env.ssb_appname
26 + let ssbAppName = appname || process.env.ssb_appname
1827
19- const config = require('ssb-config/inject')(ssb_appname, minimist(conf))
28 + const config = require('ssb-config/inject')(ssbAppName, minimist(conf))
2029
2130 const keys = ssbKeys.loadOrCreateSync(path.join(config.path, 'secret'))
2231 if (keys.curve === 'k256') {
32 + // i think this is _really_ old and could be removed
2333 throw new Error('k256 curves are no longer supported,' +
24- 'please delete' + path.join(config.path, 'secret'))
34 + 'please delete' + path.join(config.path, 'secret'))
2535 }
36 + config.keys = keys
37 + ssbConfig = config
2638
2739 const manifestFile = path.join(config.path, 'manifest.json')
2840
2941 const createSbot = require('scuttlebot')
30- // .use(require('scuttlebot/plugins/plugins'))
3142 .use(require('scuttlebot/plugins/master'))
3243 .use(require('scuttlebot/plugins/gossip'))
3344 .use(require('scuttlebot/plugins/replicate'))
3445 .use(require('scuttlebot/plugins/invite'))
3546 .use(require('scuttlebot/plugins/local'))
47 + .use(require('scuttlebot/plugins/logging'))
3648 .use(require('ssb-about'))
3749 .use(require('ssb-backlinks'))
3850 .use(require('ssb-blobs'))
51 + .use(require('ssb-chess-db'))
3952 .use(require('ssb-ebt'))
40- .use(require('ssb-chess-db'))
4153 .use(require('ssb-friends'))
54 + .use(require('ssb-links')) // needed by patchfoo
55 + .use(require('ssb-names'))
4256 .use(require('ssb-meme'))
43- .use(require('ssb-names'))
4457 .use(require('ssb-ooo'))
4558 .use(require('ssb-private'))
59 + .use(require('ssb-query'))
4660 .use(require('ssb-search'))
47- .use(require('ssb-query'))
61 + .use(require('ssb-talequery')) // only tale:net
62 + .use(require('ssb-unread'))
4863 .use(require('ssb-ws'))
4964
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 +
5093 // start server
51-
52- config.keys = keys
5394 const server = createSbot(config)
5495
5596 // write RPC manifest to ~/.ssb/manifest.json
5697 fs.writeFileSync(manifestFile, JSON.stringify(server.getManifest(), null, 2))
@@ -61,50 +102,127 @@
61102 icon: icon.toString('base64'),
62103 title: 'Scuttle-Shell',
63104 tooltip: 'Secure Scuttlebutt',
64105 items: [
65-
66106 {
107 + title: 'starting...',
108 + checked: false,
109 + enabled: true
110 + },
111 + {
112 + title: 'version: unset',
113 + checked: false,
114 + enabled: false
115 + },
116 + {
67117 title: 'Quit',
68118 tooltip: 'Stop sbot and quit tray application',
69119 checked: false,
70120 enabled: true
71121 }
72122 ]
73123 },
74124 debug: false,
75- copyDir: true,
125 + copyDir: true
76126 })
77127
78- tray.onClick(action => {
79- switch (action.seq_id) {
80- case 0:
81- console.log("### EXITING IN TWO SECONDS ###")
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 ###')
82133
83134 notifier.notify({
84135 title: 'Secure Scuttlebutt',
85136 message: `Secure Scuttlebutt will exit in two seconds...`,
86- icon: path.join(__dirname, "icon.png"),
137 + icon: path.join(__dirname, 'icon.png'),
87138 wait: true,
88- id: 0,
139 + id: 0
89140 })
90141
91142 tray.kill()
92143 }
93144 })
94145
95- tray.onExit((code, signal) => {
146 + tray.on('exit', (code, signal) => {
147 + console.log('scuttle-shell got exit:', code)
96148 setTimeout(() =>
97149 process.exit(0), 2000)
98150 })
99151
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)
100196 }
101197
102-function stop() {
198 +function stop () {
199 + // todo: sbot shutdown handler?
103200 tray.kill()
104201 }
105202
106-module.exports = { start, stop }
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 +}
107221
222 +module.exports = { start, stop, getConfig }
223 +
108224 if (require.main === module) {
109- var errorLevel = start()
110-}
225 + start({}, (err) => {
226 + if (err) console.error(err)
227 + })
228 +}
.travis.runtest.shView
@@ -1,0 +1,14 @@
1 +#!/bin/bash
2 +
3 +if [[ $TRAVIS_OS_NAME == 'linux' ]]; then
4 + export DISPLAY=':99.0'
5 + Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
6 + echo started xvfb
7 +fi
8 +
9 +echo debug: $TRAVIS_OS_NAME $DISPLAY
10 +npm i
11 +node ./server.js
12 +
13 +# npm test
14 +# TODO: could do tests/test.bad on appvayor
.travis.ymlView
@@ -1,0 +1,14 @@
1 +language: node_js
2 +node_js:
3 + - 6
4 + - 8
5 + - 10
6 +
7 +addons:
8 + apt:
9 + packages:
10 + - xvfb
11 +
12 +script: ./.travis.runtest.sh
13 +
14 +# TODO: could do test/tests.bat on appvayor

Built with git-ssb-web