Files: d951d83a8663076e0b94ed3ed7f6cbdd16e4b5bf / lib / private-with-index.js
3964 bytesRaw
1 | var ssbKeys = require('ssb-keys') |
2 | var explain = require('explain-error') |
3 | var valid = require('scuttlebot/lib/validators') |
4 | var Links = require('streamview-links') |
5 | var pull = require('pull-stream') |
6 | var Notify = require('pull-notify') |
7 | var path = require('path') |
8 | var Value = require('mutant/value') |
9 | var watchThrottle = require('mutant/watch-throttle') |
10 | |
11 | var indexes = [ |
12 | { key: 'TSP', value: ['timestamp'] }, |
13 | { key: 'ATY', value: [['value', 'author'], ['value', 'content', 'type'], 'timestamp'] } |
14 | ] |
15 | |
16 | module.exports = { |
17 | name: 'private', |
18 | version: '0.0.0', |
19 | manifest: { |
20 | publish: 'async', unbox: 'sync', read: 'source', progress: 'source' |
21 | }, |
22 | permissions: { |
23 | anonymous: {} |
24 | }, |
25 | init: function (sbot, config) { |
26 | var dir = path.join(config.path, 'private') |
27 | var version = 0 |
28 | |
29 | var index = Links(dir, indexes, (x, emit) => { |
30 | var value = unbox(x) |
31 | if (value) { |
32 | emit(value) |
33 | } |
34 | }, version) |
35 | |
36 | var notify = Notify() |
37 | var pending = Value(0) |
38 | |
39 | watchThrottle(pending, 200, (value) => { |
40 | notify({pending: Math.max(0, value)}) |
41 | }) |
42 | |
43 | index.init(function (_, since) { |
44 | countChanges(since, function (err, changes) { |
45 | if (err) throw err |
46 | pending.set(changes) |
47 | onChange(() => { |
48 | pending.set(pending() + 1) |
49 | }) |
50 | pull( |
51 | sbot.createLogStream({gt: since || 0, live: true, sync: false}), |
52 | pull.through(function () { |
53 | pending.set(pending() - 1) |
54 | }), |
55 | index.write(function (err) { |
56 | if (err) throw err |
57 | }) |
58 | ) |
59 | }) |
60 | }) |
61 | |
62 | return { |
63 | publish: valid.async(function (data, recps, cb) { |
64 | var ciphertext |
65 | try { ciphertext = ssbKeys.box(data, recps) } |
66 | catch (e) { return cb(explain(e, 'failed to encrypt')) } |
67 | sbot.publish(ciphertext, cb) |
68 | }, 'string|object', 'array'), |
69 | unbox: valid.sync(function (ciphertext) { |
70 | var data |
71 | try { data = ssbKeys.unbox(ciphertext, sbot.keys.private) } |
72 | catch (e) { throw explain(e, 'failed to decrypt') } |
73 | return data |
74 | }, 'string'), |
75 | read: function (opts) { |
76 | if (opts && typeof opts === 'string') { |
77 | try { |
78 | opts = {query: JSON.parse(opts)} |
79 | } catch (err) { |
80 | return pull.error(err) |
81 | } |
82 | } |
83 | return index.read(opts, function (ts, cb) { |
84 | sbot.sublevel('log').get(ts, function (err, key) { |
85 | if (err) return cb(explain(err, 'missing timestamp:'+ts)) |
86 | sbot.get(key, function (err, value) { |
87 | if(err) return cb(explain(err, 'missing key:'+key)) |
88 | cb(null, {key: key, value: unboxValue(value), timestamp: ts}) |
89 | }) |
90 | }) |
91 | }) |
92 | }, |
93 | progress: notify.listen |
94 | } |
95 | |
96 | function countChanges (since, cb) { |
97 | var result = 0 |
98 | pull( |
99 | sbot.createLogStream({gt: since || 0, keys: false, values: false}), |
100 | pull.drain(function () { |
101 | result += 1 |
102 | }, function (err) { |
103 | cb(err, result) |
104 | }) |
105 | ) |
106 | } |
107 | |
108 | function onChange (cb) { |
109 | pull( |
110 | sbot.createLogStream({keys: false, values: false, old: false}), |
111 | pull.drain(function () { |
112 | cb() |
113 | }) |
114 | ) |
115 | } |
116 | |
117 | function unbox (msg) { |
118 | if (typeof msg.value.content === 'string') { |
119 | var value = unboxValue(msg.value) |
120 | if (value) { |
121 | return { |
122 | key: msg.key, value: value, timestamp: msg.timestamp |
123 | } |
124 | } |
125 | } |
126 | } |
127 | |
128 | function unboxValue (value) { |
129 | var plaintext = null |
130 | try { |
131 | plaintext = ssbKeys.unbox(value.content, sbot.keys.private) |
132 | } catch (ex) {} |
133 | if (!plaintext) return null |
134 | return { |
135 | previous: value.previous, |
136 | author: value.author, |
137 | sequence: value.sequence, |
138 | timestamp: value.timestamp, |
139 | hash: value.hash, |
140 | content: plaintext, |
141 | private: true |
142 | } |
143 | } |
144 | } |
145 | } |
146 |
Built with git-ssb-web