Files: d06c60e3b13b5795e7acad4aff8901f5039efb83 / about / obs.js
5036 bytesRaw
1 | var {Value, computed} = require('mutant') |
2 | var pull = require('pull-stream') |
3 | var nest = require('depnest') |
4 | var ref = require('ssb-ref') |
5 | var colorHash = new (require('color-hash'))() |
6 | var fallbackImageUrl = 'data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==' |
7 | |
8 | exports.needs = nest({ |
9 | 'sbot.pull.stream': 'first', |
10 | 'blob.sync.url': 'first', |
11 | 'keys.sync.id': 'first' |
12 | }) |
13 | |
14 | exports.gives = nest({ |
15 | 'about.obs': [ |
16 | 'name', |
17 | 'description', |
18 | 'image', |
19 | 'imageUrl', |
20 | 'names', |
21 | 'images', |
22 | 'color', |
23 | 'latestValue', |
24 | 'valueFrom', |
25 | 'socialValue', |
26 | 'groupedValues' |
27 | ] |
28 | }) |
29 | |
30 | exports.create = function (api) { |
31 | var sync = Value(false) |
32 | var cache = null |
33 | |
34 | return nest({ |
35 | 'about.obs': { |
36 | // quick helpers, probably should deprecate! |
37 | name: (id) => socialValue(id, 'name', id.slice(1, 10)), |
38 | description: (id) => socialValue(id, 'description'), |
39 | image: (id) => socialValue(id, 'image'), |
40 | names: (id) => groupedValues(id, 'name'), |
41 | images: (id) => groupedValues(id, 'image'), |
42 | color: (id) => computed(id, (id) => colorHash.hex(id)), |
43 | imageUrl: (id) => computed(socialValue(id, 'image'), (blobId) => { |
44 | return blobId ? api.blob.sync.url(blobId) : fallbackImageUrl |
45 | }), |
46 | |
47 | // custom abouts (the future!) |
48 | valueFrom, |
49 | latestValue, |
50 | socialValue, |
51 | groupedValues |
52 | } |
53 | }) |
54 | |
55 | |
56 | function valueFrom (id, key, author) { |
57 | if (!ref.isLink(id)) throw new Error('About requires an ssb ref!') |
58 | return computed([get(id), key, author], getValueFrom) |
59 | } |
60 | |
61 | function latestValue (id, key) { |
62 | if (!ref.isLink(id)) throw new Error('About requires an ssb ref!') |
63 | return computed([get(id), key], getLatestValue) |
64 | } |
65 | |
66 | function socialValue (id, key, defaultValue) { |
67 | if (!ref.isLink(id)) throw new Error('About requires an ssb ref!') |
68 | var yourId = api.keys.sync.id() |
69 | return computed([get(id), key, id, yourId, defaultValue], getSocialValue) |
70 | } |
71 | |
72 | function groupedValues (id, key) { |
73 | if (!ref.isLink(id)) throw new Error('About requires an ssb ref!') |
74 | return computed([get(id), key], getGroupedValues) |
75 | } |
76 | |
77 | function get (id) { |
78 | if (!ref.isLink(id)) throw new Error('About requires an ssb ref!') |
79 | load() |
80 | if (!cache[id]) { |
81 | cache[id] = Value({}) |
82 | } |
83 | return cache[id] |
84 | } |
85 | |
86 | function load () { |
87 | if (!cache) { |
88 | cache = {} |
89 | pull( |
90 | api.sbot.pull.stream(sbot => sbot.about.stream({live: true})), |
91 | pull.drain(item => { |
92 | for (var target in item) { |
93 | var state = get(target) |
94 | var lastState = state() |
95 | var values = item[target] |
96 | var changed = false |
97 | for (var key in values) { |
98 | var valuesForKey = lastState[key] = lastState[key] || {} |
99 | for (var author in values[key]) { |
100 | var value = values[key][author] |
101 | if (!valuesForKey[author] || value[1] > valuesForKey[author][1]) { |
102 | valuesForKey[author] = value |
103 | changed = true |
104 | } |
105 | } |
106 | } |
107 | if (changed) { |
108 | state.set(lastState) |
109 | } |
110 | } |
111 | |
112 | if (!sync()) { |
113 | sync.set(true) |
114 | } |
115 | }) |
116 | ) |
117 | } |
118 | } |
119 | } |
120 | |
121 | function getSocialValue (lookup, key, id, yourId, fallback) { |
122 | var result = lookup[key] ? getValue(lookup[key][yourId]) || getValue(lookup[key][id]) || highestRank(lookup[key]) : null |
123 | if (result != null) { |
124 | return result |
125 | } else { |
126 | return fallback || null |
127 | } |
128 | } |
129 | |
130 | function getGroupedValues (lookup, key) { |
131 | var values = {} |
132 | for (var author in lookup[key]) { |
133 | var value = getValue(lookup[key][author]) |
134 | if (value != null) { |
135 | values[value] = values[value] || [] |
136 | values[value].push(author) |
137 | } |
138 | } |
139 | return values |
140 | } |
141 | |
142 | function highestRank (lookup) { |
143 | var counts = {} |
144 | var highestCount = 0 |
145 | var currentHighest = null |
146 | for (var key in lookup) { |
147 | var value = getValue(lookup[key]) |
148 | if (value != null) { |
149 | counts[value] = (counts[value] || 0) + 1 |
150 | if (counts[value] > highestCount) { |
151 | currentHighest = value |
152 | highestCount = counts[value] |
153 | } |
154 | } |
155 | } |
156 | return currentHighest |
157 | } |
158 | |
159 | function getValue (item) { |
160 | if (item && item[0]) { |
161 | if (typeof item[0] === 'string') { |
162 | return item[0] |
163 | } else if (item[0] && item[0].link && ref.isLink(item[0].link) && !item[0].remove) { |
164 | return item[0].link |
165 | } |
166 | } |
167 | } |
168 | |
169 | function getLatestValue (lookup, key) { |
170 | var latestTime = 0 |
171 | var latestValue = null |
172 | |
173 | if (lookup[key]) { |
174 | for (var author in lookup[key]) { |
175 | if (Array.isArray(lookup[key][author])) { |
176 | var value = lookup[key][author][0] |
177 | var timestamp = lookup[key][author][1] |
178 | if (timestamp > latestTime) { |
179 | latestTime = timestamp |
180 | latestValue = value |
181 | } |
182 | } |
183 | } |
184 | } |
185 | |
186 | return latestValue |
187 | } |
188 | |
189 | function getValueFrom (lookup, key, author) { |
190 | if (lookup[key] && Array.isArray(lookup[key][author])) { |
191 | return lookup[key][author][0] |
192 | } |
193 | } |
194 |
Built with git-ssb-web