Files: d5b1e6e6827f845ce25a452fba8210b7f6052c3b / index.js
4019 bytesRaw
1 | |
2 | var G = require('graphreduce') |
3 | var F = require('ssb-friends/alg') |
4 | |
5 | var Reduce = require('flumeview-reduce') |
6 | var pull = require('pull-stream') |
7 | var FlatMap = require('pull-flatmap') |
8 | var ref = require('ssb-ref') |
9 | |
10 | exports.name = 'sameAs' |
11 | exports.version = require('./package.json').version |
12 | exports.manifest = { |
13 | get: 'async', |
14 | stream: 'source' |
15 | } |
16 | |
17 | exports.init = function (sbot, config) { |
18 | var g = {} |
19 | var index = sbot._flumeUse('sameAs', Reduce(2, function (graph, rel) { |
20 | if (!graph) graph = {} |
21 | |
22 | if (rel) { |
23 | if (ref.isFeed(rel.from) && ref.isFeed(rel.to)) { |
24 | var outgoing = G.get(graph, rel.from, rel.to) || [] |
25 | var incoming = G.get(graph, rel.to, rel.from) || [] |
26 | incoming[1] = outgoing[0] = rel.value |
27 | G.addEdge(graph, rel.from, rel.to, outgoing) |
28 | G.addEdge(graph, rel.to, rel.from, incoming) |
29 | } else if (rel.localClaims) { |
30 | G.eachEdge(rel.localClaims, (from, to, value) => { |
31 | var outgoing = G.get(graph, from, to) || [] |
32 | var incoming = G.get(graph, to, from) || [] |
33 | outgoing[2] = incoming[2] = value |
34 | G.addEdge(graph, from, to, outgoing) |
35 | G.addEdge(graph, to, from, incoming) |
36 | }) |
37 | } |
38 | } |
39 | return graph |
40 | }, function (data) { |
41 | if (isSameAsMsg(data)) { |
42 | var author = data.value.author |
43 | var contact = data.value.content.contact |
44 | var sameAs = data.value.content.sameAs |
45 | if (typeof sameAs === 'boolean') { |
46 | return { |
47 | from: author, |
48 | to: contact, |
49 | value: sameAs |
50 | } |
51 | } else if (data.value.content.sameAs instanceof Object && data.value.author === sbot.id) { |
52 | return { |
53 | localClaims: { |
54 | [contact]: sameAs |
55 | } |
56 | } |
57 | } |
58 | } |
59 | }, null, g)) |
60 | |
61 | function get (id) { |
62 | var graph = index.value.value |
63 | return F.reachable(graph, id, { |
64 | initial: undefined, reduce, expand |
65 | }) |
66 | } |
67 | |
68 | function createSameAsStream (opts) { |
69 | opts = opts || {} |
70 | var sameAs = {} |
71 | |
72 | return pull( |
73 | index.stream(opts), |
74 | pull.filter(), |
75 | FlatMap(function (value) { |
76 | var result = [] |
77 | var graph = index.value.value |
78 | |
79 | // TODO: this has to traverse the entire graph, should use the subset when realtime update |
80 | G.eachEdge(graph, (from, to, values) => { |
81 | var sameAs = get(from) |
82 | |
83 | // clear out unreachable keys |
84 | for (let dest in sameAs[from]) { |
85 | if (sameAs[dest] == null && sameAs[from] !== false) { |
86 | update(from, dest, false) |
87 | } |
88 | } |
89 | |
90 | // update reachable |
91 | for (let dest in sameAs) { |
92 | if (sameAs[dest] != null && from !== dest) { |
93 | update(from, dest, sameAs[dest]) |
94 | } |
95 | } |
96 | }) |
97 | |
98 | return result |
99 | |
100 | function update (from, to, value) { |
101 | var lastValue = G.get(sameAs, from, to) |
102 | if (lastValue !== value && !(lastValue == null && value === false)) { |
103 | G.addEdge(sameAs, from, to, value) |
104 | result.push({from, to, value}) |
105 | } |
106 | } |
107 | }) |
108 | ) |
109 | } |
110 | |
111 | // REPLICATION |
112 | if (sbot.replicate) { |
113 | // probably should sit on ssb-friends createFriendStream and then check emitted values for sameAs |
114 | // TODO: add sameAs peers to replicate map |
115 | } |
116 | |
117 | return { |
118 | get: function (opts) { |
119 | return get(opts.id) |
120 | }, |
121 | stream: createSameAsStream |
122 | } |
123 | } |
124 | |
125 | function isSameAsMsg (msg) { |
126 | return msg.value.content.type === 'contact' && ref.isFeed(msg.value.content.contact) && 'sameAs' in msg.value.content |
127 | } |
128 | |
129 | function getValue (values) { |
130 | // mutual sameAs |
131 | if (values[0] && values[1]) { |
132 | return true |
133 | } |
134 | |
135 | // one party disagrees |
136 | if (values[0] === false || values[1] === false) { |
137 | return false |
138 | } |
139 | |
140 | // partial with |
141 | if ((values[0] || values[1]) && values[2]) { |
142 | return true |
143 | } |
144 | } |
145 | |
146 | function reduce (target, source, value) { |
147 | if (target !== false) { |
148 | target = getValue(value) |
149 | } |
150 | return target |
151 | } |
152 | |
153 | function expand (value) { |
154 | return value != null |
155 | } |
156 |
Built with git-ssb-web