Files: 8e8434f441e3e179672053fbde29570a4fcf6981 / create.js
4885 bytesRaw
1 | |
2 | |
3 | var join = require('path').join |
4 | var EventEmitter = require('events') |
5 | //var ViewLevel = require('flumeview-level') |
6 | var ltgt = require('ltgt') |
7 | |
8 | var pull = require('pull-stream') |
9 | var ref = require('ssb-ref') |
10 | var ssbKeys = require('ssb-keys') |
11 | |
12 | var u = require('./util') |
13 | |
14 | function isString (s) { |
15 | return typeof s === 'string' |
16 | } |
17 | |
18 | function errorCB (err) { |
19 | if (err) throw err |
20 | } |
21 | |
22 | module.exports = function (path, opts, keys) { |
23 | //_ was legacy db. removed that, but for backwards compatibilty reasons do not change interface |
24 | if(!path) throw new Error('path must be provided') |
25 | |
26 | keys = keys || ssbKeys.generate() |
27 | |
28 | var db = require('./db')(join(opts.path || path, 'flume'), keys, opts) |
29 | |
30 | // UGLY HACK, but... |
31 | // fairly sure that something up the stack expects ssb to be an event emitter. |
32 | db.__proto__ = new EventEmitter() // eslint-disable-line |
33 | |
34 | db.opts = opts |
35 | |
36 | db.id = keys.id |
37 | |
38 | var _get = db.get |
39 | |
40 | db.get = function (key, cb) { |
41 | let isPrivate = false |
42 | let unbox |
43 | let meta = false |
44 | if (typeof key === 'object') { |
45 | isPrivate = key.private === true |
46 | unbox = key.unbox |
47 | meta = key.meta |
48 | key = key.id |
49 | } |
50 | |
51 | if (ref.isMsg(key)) { |
52 | return db.keys.get(key, function (err, data) { |
53 | if (err) return cb(err) |
54 | |
55 | if (isPrivate && unbox) { |
56 | data = db.unbox(data, unbox) |
57 | } |
58 | |
59 | let result |
60 | |
61 | if (isPrivate) { |
62 | result = data.value |
63 | } else { |
64 | result = u.originalValue(data.value) |
65 | } |
66 | |
67 | cb(null, !meta ? result : {key: data.key, value: result, timestamp: data.timestamp}) |
68 | }) |
69 | } else if (ref.isMsgLink(key)) { |
70 | var link = ref.parseLink(key) |
71 | return db.get({ |
72 | id: link.link, |
73 | private: true, |
74 | unbox: link.query.unbox.replace(/\s/g, '+'), |
75 | meta: link.query.meta |
76 | }, cb) |
77 | } else if (Number.isInteger(key)) { |
78 | _get(key, cb) // seq |
79 | } else { |
80 | throw new Error('ssb-db.get: key *must* be a ssb message id or a flume offset') |
81 | } |
82 | } |
83 | |
84 | db.add = function (msg, cb) { |
85 | db.queue(msg, function (err, data) { |
86 | if (err) cb(err) |
87 | else db.flush(function () { cb(null, data) }) |
88 | }) |
89 | } |
90 | |
91 | //would like to remove this, but loads of tests use it. |
92 | db.createFeed = function (keys) { |
93 | console.error('deprecated api used: db.createFeed, please use db.publish directly') |
94 | if (!keys) keys = ssbKeys.generate() |
95 | function add (content, cb) { |
96 | // LEGACY: hacks to support add as a continuable |
97 | if (!cb) { return function (cb) { add(content, cb) } } |
98 | |
99 | db.append({ content: content, keys: keys }, cb) |
100 | } |
101 | return { |
102 | add: add, |
103 | publish: add, |
104 | id: keys.id, |
105 | keys: keys |
106 | } |
107 | } |
108 | |
109 | db.createRawLogStream = function (opts) { |
110 | opts = opts || {} |
111 | var isPrivate = opts.private === true |
112 | return pull( |
113 | db.stream(opts), |
114 | pull.map(function (data) { |
115 | if (isPrivate) { |
116 | return data |
117 | } else { |
118 | if(opts.seqs) |
119 | return { |
120 | seq: data.seq, |
121 | value: { |
122 | key: data.value.key, |
123 | value: u.originalValue(data.value.value), |
124 | timestamp: data.value.timestamp |
125 | } |
126 | } |
127 | else |
128 | return { |
129 | key: data.key, |
130 | value: u.originalValue(data.value), |
131 | timestamp: data.timestamp |
132 | } |
133 | } |
134 | }) |
135 | ) |
136 | } |
137 | |
138 | // called with [id, seq] or "<id>:<seq>" (used by ssb-edb replication) |
139 | db.getAtSequence = function (seqid, cb) { |
140 | // will NOT expose private plaintext |
141 | const parts = isString(seqid) ? seqid.split(':') : seqid |
142 | const id = parts[0], seq = parts[1] |
143 | db.clock.get(function (err, state) { |
144 | if(err) cb(err) |
145 | else if(!state[id] || state[id][seq] == null) |
146 | cb(new Error('not found: getAtSequence([' + id + ', '+seq+'])')) |
147 | else |
148 | db.get(state[id][seq], cb) |
149 | }) |
150 | } |
151 | |
152 | db.getVectorClock = function (_, cb) { |
153 | if (!cb) cb = _ |
154 | db.last.get(function (err, h) { |
155 | if (err) return cb(err) |
156 | var clock = {} |
157 | for (var k in h) { clock[k] = h[k].sequence } |
158 | cb(null, clock) |
159 | }) |
160 | } |
161 | |
162 | // db |
163 | // .use('time', ViewLevel(2, function (data) { |
164 | // return [data.timestamp] |
165 | // })) |
166 | // |
167 | db.createLogStream = function (opts) { |
168 | opts = u.options(opts) |
169 | if (opts.raw) { return db.stream(opts) } |
170 | |
171 | var keys = opts.keys; delete opts.keys |
172 | var values = opts.values; delete opts.values |
173 | if (opts.gt == null) { opts.gt = 0 } |
174 | |
175 | return pull( |
176 | //XXX not scalable, only usable for a proof of concept! |
177 | // a binary search would be better! |
178 | db.stream({seqs: false, live: opts.live, reverse: opts.reverse}), |
179 | pull.filter(function (data) { |
180 | return ltgt.contains(opts, data.timestamp, cmp) |
181 | }), |
182 | u.Format(keys, values, opts.private) |
183 | ) |
184 | } |
185 | |
186 | |
187 | return db |
188 | } |
189 | |
190 | |
191 | |
192 | |
193 | |
194 |
Built with git-ssb-web