git ssb

0+

Matt McKegg / ssb-same-as



Tree: 4ec5edfb2081186e3802ba848a5c476a4edefcd6

Files: 4ec5edfb2081186e3802ba848a5c476a4edefcd6 / index.js

4019 bytesRaw
1'use strict'
2var G = require('graphreduce')
3var F = require('ssb-friends/alg')
4
5var Reduce = require('flumeview-reduce')
6var pull = require('pull-stream')
7var FlatMap = require('pull-flatmap')
8var ref = require('ssb-ref')
9
10exports.name = 'sameAs'
11exports.version = require('./package.json').version
12exports.manifest = {
13 get: 'async',
14 stream: 'source'
15}
16
17exports.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
125function isSameAsMsg (msg) {
126 return msg.value.content.type === 'contact' && ref.isFeed(msg.value.content.contact) && 'sameAs' in msg.value.content
127}
128
129function 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
146function reduce (target, source, value) {
147 if (target !== false) {
148 target = getValue(value)
149 }
150 return target
151}
152
153function expand (value) {
154 return value != null
155}
156

Built with git-ssb-web