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