git ssb

1+

Dominic / secure-scuttlebutt



Tree: 9a7e43ac498a13a9720df2ba9fdd94eafe23d04d

Files: 9a7e43ac498a13a9720df2ba9fdd94eafe23d04d / indexes / links.js

5276 bytesRaw
1var ref = require('ssb-ref')
2var path = require('path')
3var pull = require('pull-stream')
4var ltgt = require('ltgt')
5var ssbKeys = require('ssb-keys')
6var paramap = require('pull-paramap')
7var Format = require('../util').formatStream
8var ViewLevel = require('flumeview-level')
9
10
11
12//53 bit integer
13var MAX_INT = 0x1fffffffffffff
14var u = require('../util')
15
16var mlib = require('ssb-msgs')
17
18function isString (s) {
19 return 'string' === typeof s
20}
21
22module.exports = function (keys) {
23
24 function indexMsg (localtime, id, msg) {
25 //DECRYPT the message, if possible
26 //to enable indexing. If external apis
27 //are not provided that may access indexes
28 //then this will not leak information.
29 //otherwise, we may need to figure something out.
30
31 var content = (keys && isString(msg.content))
32 ? ssbKeys.unbox(msg.content, keys)
33 : msg.content
34
35 if(!content) return []
36
37 var a = []
38
39 if(isString(content.type))
40 a.push(['type', content.type.toString().substring(0, 32), localtime])
41
42 mlib.indexLinks(content, function (obj, rel) {
43 a.push(['link', msg.author, rel, obj.link, msg.sequence, id])
44 a.push(['_link', obj.link, rel, msg.author, msg.sequence, id])
45 })
46
47 return a
48 }
49
50 var createIndex = ViewLevel(1, function (data) {
51 return indexMsg(data.timestamp, data.key, data.value)
52 })
53
54 return function (log, name) {
55 var index = createIndex(log, name)
56
57 index.methods = {
58 messagesByType: 'source',
59 links: 'source'
60 }
61
62 index.messagesByType = function (opts) {
63 if(!opts)
64 throw new Error('must provide {type: string} to messagesByType')
65
66 if(isString(opts))
67 opts = {type: opts}
68
69 opts = u.options(opts)
70 var keys = opts.keys !== false
71 var values = opts.values !== false
72 opts.values = true
73
74 ltgt.toLtgt(opts, opts, function (value) {
75 return ['type', opts.type, value]
76 }, u.lo, u.hi)
77
78 return pull(
79 index.read(opts),
80 Format(keys, values)
81 )
82 }
83
84 function format(opts, op, key, value) {
85 var meta = opts.meta !== false //default: true
86 var keys = opts.keys !== false //default: true
87 var vals = opts.values === true //default: false
88 if(!meta&&!keys&&!vals)
89 throw new Error('a stream without any values does not make sense')
90 if(!meta) return (
91 keys && vals ? {key: op.key, value: value}
92 : keys ? op.key
93 : value
94 )
95 else {
96 if(vals) op.value = value
97 if(!keys) delete op.key
98 delete op._value
99 return op
100 }
101 }
102
103 function type(t) { return {feed: '@', msg: '%', blob: '&'}[t] || t }
104
105 function linksOpts (opts) {
106 if(!opts) throw new Error('opts *must* be provided')
107
108 if( !(opts.values === true)
109 && !(opts.meta !== false)
110 && !(opts.keys !== false)
111 )
112 throw new Error('makes no sense to return stream without results'
113 + 'set at least one of {keys, values, meta} to true')
114
115 var src = type(opts.source), dst = type(opts.dest), rel = opts.rel
116
117 var back = dst && !src
118 var from = back ? dst : src, to = back ? src : dst
119
120 function range(value, end, def) {
121 return !value ? def : /^[@%&]$/.test(value) ? value + end : value
122 }
123 function lo(value) { return range(value, "!", u.lo) }
124 function hi(value) { return range(value, "~", u.hi) }
125
126 var index = back ? '_link' : 'link'
127 var gte = [index, lo(from), rel || u.lo, lo(to), u.lo, u.lo]
128 var lte = [index, hi(from), rel || u.hi, hi(to), u.hi, u.hi]
129 return {
130 gte: gte, lte: lte, reverse: opts.reverse,
131 back: back, rel: rel, source: src, dest: dst,
132 live: opts.live, sync: opts.sync, old: opts.old,
133 props: {
134 keys: opts.keys !== false, //default: true
135 meta: opts.meta !== false, //default: true
136 values: opts.values === true, //default: false
137 }
138 }
139 }
140
141 function testLink (a, e) { //actual, expected
142 return e ? e.length === 1 ? a[0]==e[0] : a===e : true
143 }
144
145 index.links = function (opts) {
146 opts = linksOpts(opts)
147 return pull(
148 index.read(opts),
149 pull.map(function (op) {
150 if(op.sync) return op
151 return {
152 source: op.key[opts.back?3:1],
153 rel: op.key[2],
154 dest: op.key[opts.back?1:3],
155 key: op.key[5],
156 _value: op.value.value,
157 //timestamp: op.value.timestamp
158 }
159 }),
160 // in case source and dest are known but not rel,
161 // this will scan all links from the source
162 // and filter out those to the dest. not efficient
163 // but probably a rare query.
164 pull.filter(function (data) {
165 if(data.sync) return true
166 if(opts.rel && opts.rel !== data.rel) return false
167 if(!testLink(data.dest, opts.dest)) return false
168 if(!testLink(data.source, opts.source)) return false
169 return true
170 }),
171 pull.map(function (op) {
172 if(op.sync) return op
173 return format(opts.props, op, op.key, op._value)
174 })
175 )
176 }
177
178 return index
179 }
180}
181
182
183
184
185
186
187
188

Built with git-ssb-web