git ssb

4+

Dominic / scuttlebot



Tree: b3923852a5471785a61c33094414b62fa845b7b5

Files: b3923852a5471785a61c33094414b62fa845b7b5 / index.js

6320 bytesRaw
1var SecretStack = require('secret-stack')
2var create = require('secure-scuttlebutt/create')
3var ssbKeys = require('ssb-keys')
4var path = require('path')
5var osenv = require('osenv')
6var mkdirp = require('mkdirp')
7var rimraf = require('rimraf')
8var mdm = require('mdmanifest')
9var cmdAliases = require('./lib/cli-cmd-aliases')
10var valid = require('./lib/validators')
11var apidocs = require('./lib/apidocs.js')
12
13function isString(s) { return 'string' === typeof s }
14function isObject(o) { return 'object' === typeof o }
15function isFunction (f) { return 'function' === typeof f }
16// create SecretStack definition
17var manifest = mdm.manifest(apidocs._)
18manifest.seq = 'async'
19manifest.usage = 'sync'
20manifest.clock = 'async'
21var SSB = {
22 manifest: manifest,
23 permissions: {
24 master: {allow: null, deny: null},
25 anonymous: {allow: ['createHistoryStream'], deny: null}
26 },
27 init: function (api, opts) {
28
29 // .temp: use a /tmp data directory
30 // (useful for testing)
31 if(opts.temp) {
32 var name = isString(opts.temp) ? opts.temp : ''+Date.now()
33 opts.path = path.join(osenv.tmpdir(), name)
34 rimraf.sync(opts.path)
35 }
36
37 // load/create secure scuttlebutt data directory
38 var dbPath = path.join(opts.path, 'db')
39 mkdirp.sync(dbPath)
40
41 if(!opts.keys)
42 opts.keys = ssbKeys.generate('ed25519', opts.seed && new Buffer(opts.seed, 'base64'))
43
44 if(!opts.path)
45 throw new Error('opts.path *must* be provided, or use opts.temp=name to create a test instance')
46
47 // main interface
48 var ssb = create(path.join(opts.path, 'db'), opts, opts.keys)
49 //treat the main feed as remote, because it's likely handled like that by others.
50 var feed = ssb.createFeed(opts.keys, {remote: true})
51 var _close = api.close
52 var close = function (arg, cb) {
53 if('function' === typeof arg) cb = arg
54 // override to close the SSB database
55 ssb.close(function (err) {
56 if (err) throw err
57 _close()
58 cb && cb() //multiserver doesn't take a callback on close.
59 })
60 }
61
62 function since () {
63 var plugs = {}
64 var sync = true
65 for(var k in ssb) {
66 if(ssb[k] && isObject(ssb[k]) && isFunction(ssb[k].since)) {
67 plugs[k] = ssb[k].since.value
68 sync = sync && (plugs[k] === ssb.since.value)
69 }
70 }
71 return {
72 since: ssb.since.value,
73 plugins: plugs,
74 sync: sync,
75 }
76 }
77
78 //remove this, but we'll need something to make a progress bar
79 //otherwise people will get confused about what is happening.
80 /*
81 var _views, _prev
82
83 var state = since()
84 var int = setInterval(function (){
85 var _state = since()
86 if(_state.since == undefined) return
87 if(state && !state.sync && !_state.sync && state.since == _state.since) {
88 var c = 0, t = 0
89
90 for(var k in _state.plugins) {
91 c += state.plugins[k]
92 t++
93 }
94
95 if(c/t !== _views || c/t != _state.since) {
96 console.log('Rebuilding Indexes:', c/t, _views, (c/t)/_state.since)
97 }
98 }
99 else if(_state.since != _prev)
100 console.log("indexes synchronised:", _state.since)
101
102 state = _state
103 _prev = state.since
104 }, 1000)
105
106 //unref is a node.js only api.
107 if (int.unref) int.unref()
108 */
109
110 return {
111 id : feed.id,
112 keys : opts.keys,
113
114 //temporary!
115 _flumeUse :
116 function (name, flumeview) {
117 ssb.use(name, flumeview)
118 return ssb[name]
119 },
120
121 usage : valid.sync(usage, 'string?|boolean?'),
122 close : valid.async(close),
123
124 publish : valid.async(feed.add, 'string|msgContent'),
125 add : valid.async(ssb.add, 'msg'),
126 get : valid.async(ssb.get, 'msgId|number'),
127
128 post : ssb.post,
129
130 since : since,
131
132 getPublicKey : ssb.getPublicKey,
133 latest : ssb.latest,
134 getLatest : valid.async(ssb.getLatest, 'feedId'),
135 latestSequence : valid.async(ssb.latestSequence, 'feedId'),
136 createFeed : ssb.createFeed,
137 whoami : function () { return { id: feed.id } },
138 relatedMessages : valid.async(ssb.relatedMessages, 'relatedMessagesOpts'),
139 query : ssb.query,
140 createFeedStream : valid.source(ssb.createFeedStream, 'readStreamOpts?'),
141 createHistoryStream : valid.source(ssb.createHistoryStream, ['createHistoryStreamOpts'], ['feedId', 'number?', 'boolean?']),
142 createLogStream : valid.source(ssb.createLogStream, 'readStreamOpts?'),
143 createUserStream : valid.source(ssb.createUserStream, 'createUserStreamOpts'),
144 links : valid.source(ssb.links, 'linksOpts'),
145 sublevel : ssb.sublevel,
146 messagesByType : valid.source(ssb.messagesByType, 'string|messagesByTypeOpts'),
147 createWriteStream : ssb.createWriteStream,
148 getVectorClock : ssb.getVectorClock,
149 getAtSequence : ssb.getAtSequence,
150 }
151 }
152}
153
154// live help RPC method
155function usage (cmd) {
156 var path = (cmd||'').split('.')
157 if ((path[0] && apidocs[path[0]]) || (cmd && apidocs[cmd])) {
158 // return usage for the plugin
159 cmd = path.slice(1).join('.')
160 return mdm.usage(apidocs[path[0]], cmd, { prefix: path[0] })
161 }
162 if (!cmd) {
163 // return usage for all docs
164 return Object.keys(apidocs).map(function (name) {
165 if (name == '_')
166 return mdm.usage(apidocs[name], null, { nameWidth: 20 })
167
168 var text = mdm.usage(apidocs[name], null, { prefix: name, nameWidth: 20 })
169 return text.slice(text.indexOf('Commands:') + 10) // skip past the toplevel summary, straight to the cmd list
170 }).join('\n\n')
171 }
172 // toplevel cmd usage
173 cmd = cmdAliases[cmd] || cmd
174 return mdm.usage(apidocs._, cmd)
175}
176
177module.exports = SecretStack({
178 //this is just the default app key.
179 //it can be overridden by passing a appKey as option
180 //when creating a Sbot instance.
181 appKey: require('./lib/ssb-cap')
182})
183.use(SSB)
184
185
186

Built with git-ssb-web