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