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
|
var pull = require('pull-stream')
var multicb = require('multicb')
var cat = require('pull-cat')
var u = require('./util')
module.exports = About
function About(app, myId) {
this.app = app
this.myId = myId
}
About.prototype.createAboutOpStream = function (id) {
return pull(
this.app.sbot.links({dest: id, rel: 'about', values: true, reverse: true}),
pull.map(function (msg) {
var c = msg.value.content || {}
return Object.keys(c).filter(function (key) {
return key !== 'about'
&& key !== 'type'
&& key !== 'recps'
}).map(function (key) {
var value = c[key]
return {
id: msg.key,
author: msg.value.author,
timestamp: msg.value.timestamp,
prop: key,
value: value,
remove: value && value.remove,
}
})
}),
pull.flatten()
)
}
About.prototype.createAboutStreams = function (id) {
var ops = this.createAboutOpStream(id)
var scalars = {/* author: {prop: value} */}
var sets = {/* author: {prop: {link}} */}
var setsDone = multicb({pluck: 1, spread: true})
setsDone()(null, pull.values([]))
return {
scalars: pull(
ops,
pull.unique(function (op) {
return op.author + '-' + op.prop + '-'
}),
pull.filter(function (op) {
return !op.remove
})
),
sets: u.readNext(setsDone)
}
}
function computeTopAbout(aboutByFeed) {
var propValueCounts = {/* prop: {value: count} */}
var topValues = {/* prop: value */}
var topValueCounts = {/* prop: count */}
for (var feed in aboutByFeed) {
var feedAbout = aboutByFeed[feed]
for (var prop in feedAbout) {
var value = feedAbout[prop]
var valueCounts = propValueCounts[prop] || (propValueCounts[prop] = {})
var count = (valueCounts[value] || 0) + 1
valueCounts[value] = count
if (count > (topValueCounts[prop] || 0)) {
topValueCounts[prop] = count
topValues[prop] = value
}
}
}
return topValues
}
About.prototype.get = function (dest, cb) {
var self = this
var aboutByFeed = {}
pull(
cat([
dest[0] === '%' && self.app.pullGetMsg(dest),
self.app.sbot.links({
rel: 'about',
dest: dest,
values: true,
})
]),
self.app.unboxMessages(),
pull.drain(function (msg) {
var author = msg.value.author
var c = msg.value.content
if (!c) return
if (msg.key === dest && c.type === 'about') {
// don't describe an about message with itself
return
}
var about = aboutByFeed[author] || (aboutByFeed[author] = {})
if (c.name) about.name = c.name
if (c.title) about.title = c.title
if (c.image) about.image = u.linkDest(c.image)
if (c.description) about.description = c.description
}, function (err) {
if (err) return cb(err)
// bias the author's choices by giving them an extra vote
aboutByFeed._author = aboutByFeed[dest]
var about = {}
var myAbout = aboutByFeed[self.myId] || {}
var topAbout = computeTopAbout(aboutByFeed)
for (var k in topAbout) about[k] = topAbout[k]
// always prefer own choices
for (var k in myAbout) about[k] = myAbout[k]
cb(null, about)
})
)
}
|