Commit f0668f9a8e9bd4c90739103f1c6582a4a483d2ae
initial release
mix irving committed on 6/18/2018, 2:26:26 AMFiles changed
.gitignore | added |
README.md | added |
index.js | added |
package-lock.json | added |
package.json | added |
README.md | ||
---|---|---|
@@ -1,0 +1,61 @@ | ||
1 … | +# Scuttle-inject | |
2 … | + | |
3 … | +Takes a particular sort of nested tree of methods and returns a version of that tree which has a scuttlebutt server injected into each method. | |
4 … | + | |
5 … | +This pattern means you only need to inject a scuttlebot once, makes it easier to test your methods, and handles being able to inject different sorts of server for you. | |
6 … | + | |
7 … | +## Example usage | |
8 … | + | |
9 … | +```js | |
10 … | +// methods.js | |
11 … | +module.exports = { | |
12 … | + async: { | |
13 … | + publishPoll: function (server) { | |
14 … | + return function (opts, cb) { | |
15 … | + // check the opts before publishing | |
16 … | + const cleanOpts = clean(opts) | |
17 … | + | |
18 … | + server.publish(cleanOpts, cb) | |
19 … | + } | |
20 … | + }, | |
21 … | + // getPoll: (key, cb) => {} | |
22 … | + }, | |
23 … | + pull: { | |
24 … | + myPolls: function (server) { | |
25 … | + return function (opts) { | |
26 … | + const defaultQuery = { ... } | |
27 … | + const query = Object.assign({}, defaultQuery, opts) | |
28 … | + | |
29 … | + return server.query.read(opts) | |
30 … | + } | |
31 … | + } | |
32 … | + // openPolls: (opts) => {}, | |
33 … | + // closedPolls: (opts) => {} | |
34 … | + } | |
35 … | +} | |
36 … | +``` | |
37 … | + | |
38 … | +Injecting server once (somehwhere high-level): | |
39 … | +```js | |
40 … | +const inject = require('scuttle-inject') | |
41 … | +cosnt methods = require('./methods') | |
42 … | + | |
43 … | +const scuttle = inject(methods, server) | |
44 … | +// assume you're in a context where you have a server | |
45 … | +``` | |
46 … | + | |
47 … | +Using the scuttle helper: | |
48 … | +``` | |
49 … | +const opts = { ... } | |
50 … | +scuttle.async.publishPoll(opts, cb) | |
51 … | +``` | |
52 … | + | |
53 … | +## API | |
54 … | + | |
55 … | +`inject(server, methods, pluginDeps)` | |
56 … | + | |
57 … | +- `server` - a `scuttlebot` server, an `ssb-client` connection to a server, or an observeable which will resolve into a server connection (such as Patchcore's `sbot.obs.connection`) | |
58 … | + | |
59 … | +- `methods` - an Object nested at least 2 levels deep, where there must be one layer which specifies the `type` of method. Valid types are : `sync`, `async`, `pull`, `obs` | |
60 … | + | |
61 … | +- `pluginDeps` (optional) - an Array of plugins apis the scuttlebot must have for your methods to work. e.g. `['query']` will check that `sbot.query` has methods which are accessible. |
index.js | |||
---|---|---|---|
@@ -1,0 +1,81 @@ | |||
1 … | +const { each, map } = require('libnested') | ||
2 … | +const onceTrue = require('mutant/once-true') | ||
3 … | +const watch = require('mutant/watch') | ||
4 … | +const Value = require('mutant/value') | ||
5 … | +const assert = require('assert') | ||
6 … | +const Defer = require('pull-defer').source | ||
7 … | + | ||
8 … | +// auto-inject the ssb-server to all methods to reduce repitition | ||
9 … | +module.exports = function inject (server, methods, pluginDeps = []) { | ||
10 … | + checkMethods(methods) | ||
11 … | + | ||
12 … | + switch (typeof server) { | ||
13 … | + case 'object': // just a classic ssb server | ||
14 … | + checkPlugins(server, pluginDeps) | ||
15 … | + return map(methods, (fn, path) => fn(server)) | ||
16 … | + | ||
17 … | + case 'function': // hopefully an observeable which will contain an ssb server | ||
18 … | + return injectObsServer(server, methods) | ||
19 … | + | ||
20 … | + default: | ||
21 … | + throw new Error('scuttle-poll expects an ssb server (or obs that contains one)') | ||
22 … | + } | ||
23 … | +} | ||
24 … | + | ||
25 … | +function injectObsServer (server, methods, pluginDeps = []) { | ||
26 … | + onceTrue(server, server => checkPlugins(server, pluginDeps)) | ||
27 … | + | ||
28 … | + return map(methods, (fn, path) => { | ||
29 … | + if (path.includes('async')) { | ||
30 … | + return function () { | ||
31 … | + onceTrue( | ||
32 … | + server, | ||
33 … | + server => fn(server).apply(null, arguments) | ||
34 … | + ) | ||
35 … | + } | ||
36 … | + } | ||
37 … | + | ||
38 … | + if (path.includes('pull')) { | ||
39 … | + return function () { | ||
40 … | + const source = Defer() | ||
41 … | + onceTrue( | ||
42 … | + server, | ||
43 … | + server => { | ||
44 … | + var _source = fn(server).apply(null, arguments) | ||
45 … | + source.resolve(_source) | ||
46 … | + } | ||
47 … | + ) | ||
48 … | + return source | ||
49 … | + } | ||
50 … | + } | ||
51 … | + | ||
52 … | + // NOTE - both `obs` and `sync` methods will return observeables | ||
53 … | + return function () { | ||
54 … | + var result = Value({}) | ||
55 … | + // var result = Struct({}) // WARNING - this shouldn't be copied for other apps, only works with obs.get method here. Probably breaks sync.isBlog | ||
56 … | + onceTrue( | ||
57 … | + server, | ||
58 … | + server => { | ||
59 … | + var res = fn(server).apply(null, arguments) | ||
60 … | + watch(res, res => result.set(res)) | ||
61 … | + } | ||
62 … | + ) | ||
63 … | + return result | ||
64 … | + } | ||
65 … | + }) | ||
66 … | +} | ||
67 … | + | ||
68 … | +function checkMethods (methods) { | ||
69 … | + const server = { backlinks: 'fake' } | ||
70 … | + each(methods, (fn, path) => { | ||
71 … | + assert(typeof fn === 'function', `${path.join('.')}: expect each method to be a function`) | ||
72 … | + const injectedMethod = fn(server) | ||
73 … | + assert(typeof injectedMethod === 'function', `${path.join('.')}: expect each method to be a closure which accepts a server and returns a function`) | ||
74 … | + }) | ||
75 … | +} | ||
76 … | + | ||
77 … | +function checkPlugins (server, pluginDeps) { | ||
78 … | + pluginDeps.forEach(p => { | ||
79 … | + if (!server[p]) throw new Error(`scuttle-blog needs a scuttlebot server with the ${p} plugin installed`) | ||
80 … | + }) | ||
81 … | +} |
package-lock.json | ||
---|---|---|
@@ -1,0 +1,37 @@ | ||
1 … | +{ | |
2 … | + "name": "scuttle-inject", | |
3 … | + "version": "0.0.1", | |
4 … | + "lockfileVersion": 1, | |
5 … | + "requires": true, | |
6 … | + "dependencies": { | |
7 … | + "browser-split": { | |
8 … | + "version": "0.0.1", | |
9 … | + "resolved": "https://registry.npmjs.org/browser-split/-/browser-split-0.0.1.tgz", | |
10 … | + "integrity": "sha1-ewl1dPjj6tYG+0Zk5krf3aKYGpM=" | |
11 … | + }, | |
12 … | + "libnested": { | |
13 … | + "version": "1.3.2", | |
14 … | + "resolved": "https://registry.npmjs.org/libnested/-/libnested-1.3.2.tgz", | |
15 … | + "integrity": "sha512-YvMQglpk/DyB8vFL5usJe6IZTqOU/fRopoUpoOt9TavYh5CaGdTp6zYqrA7DW8tHmZAr8fj+pDXbHBwlVrcVXQ==" | |
16 … | + }, | |
17 … | + "mutant": { | |
18 … | + "version": "3.22.1", | |
19 … | + "resolved": "https://registry.npmjs.org/mutant/-/mutant-3.22.1.tgz", | |
20 … | + "integrity": "sha1-kEh1RvcAs8KKqApD0c99M48wdYE=", | |
21 … | + "requires": { | |
22 … | + "browser-split": "0.0.1", | |
23 … | + "xtend": "^4.0.1" | |
24 … | + } | |
25 … | + }, | |
26 … | + "pull-defer": { | |
27 … | + "version": "0.2.2", | |
28 … | + "resolved": "https://registry.npmjs.org/pull-defer/-/pull-defer-0.2.2.tgz", | |
29 … | + "integrity": "sha1-CIew/7MK8ypW2+z6csFnInHwexM=" | |
30 … | + }, | |
31 … | + "xtend": { | |
32 … | + "version": "4.0.1", | |
33 … | + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", | |
34 … | + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" | |
35 … | + } | |
36 … | + } | |
37 … | +} |
package.json | ||
---|---|---|
@@ -1,0 +1,29 @@ | ||
1 … | +{ | |
2 … | + "name": "scuttle-inject", | |
3 … | + "version": "0.0.1", | |
4 … | + "description": "an helper for injecting a scuttlebot server into all your scuttle-methods", | |
5 … | + "main": "index.js", | |
6 … | + "scripts": { | |
7 … | + "test": "echo \"Error: no test specified\" && exit 1" | |
8 … | + }, | |
9 … | + "repository": { | |
10 … | + "type": "git", | |
11 … | + "url": "git+https://github.com/ssbc/scuttle-inject.git" | |
12 … | + }, | |
13 … | + "keywords": [ | |
14 … | + "scuttlebutt", | |
15 … | + "scuttle", | |
16 … | + "helper" | |
17 … | + ], | |
18 … | + "author": "mixmix", | |
19 … | + "license": "AGPL-3.0", | |
20 … | + "bugs": { | |
21 … | + "url": "https://github.com/ssbc/scuttle-inject/issues" | |
22 … | + }, | |
23 … | + "homepage": "https://github.com/ssbc/scuttle-inject#readme", | |
24 … | + "dependencies": { | |
25 … | + "libnested": "^1.3.2", | |
26 … | + "mutant": "^3.22.1", | |
27 … | + "pull-defer": "^0.2.2" | |
28 … | + } | |
29 … | +} |
Built with git-ssb-web