Files: e12ebead4d7ea7822d39659718fe98175f3868de / about / obs.js
4293 bytesRaw
1 | var {Value, computed, onceTrue} = require('mutant') |
2 | var defer = require('pull-defer') |
3 | var pull = require('pull-stream') |
4 | var nest = require('depnest') |
5 | var ref = require('ssb-ref') |
6 | var colorHash = new (require('color-hash'))() |
7 | |
8 | exports.needs = nest({ |
9 | 'sbot.obs.connection': '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 | ] |
24 | }) |
25 | |
26 | exports.create = function (api) { |
27 | var sync = Value(false) |
28 | var cache = {} |
29 | var cacheLoading = false |
30 | |
31 | return nest({ |
32 | 'about.obs': { |
33 | name: (id) => get(id).name, |
34 | description: (id) => get(id).description, |
35 | image: (id) => get(id).image, |
36 | imageUrl: (id) => get(id).imageUrl, |
37 | names: (id) => get(id).names, |
38 | images: (id) => get(id).images, |
39 | color: (id) => computed(id, (id) => colorHash.hex(id)) |
40 | } |
41 | }) |
42 | |
43 | function get (id) { |
44 | if (!ref.isFeed(id)) throw new Error('About requires an id!') |
45 | if (!cacheLoading) { |
46 | cacheLoading = true |
47 | loadCache() |
48 | } |
49 | if (!cache[id]) { |
50 | cache[id] = About(api, id) |
51 | } |
52 | return cache[id] |
53 | } |
54 | |
55 | function loadCache () { |
56 | pull( |
57 | StreamWhenConnected(api.sbot.obs.connection, sbot => sbot.about.stream({live: true})), |
58 | pull.drain(item => { |
59 | for (var target in item) { |
60 | if (ref.isFeed(target)) { |
61 | get(target).push(item[target]) |
62 | } |
63 | } |
64 | |
65 | if (!sync()) { |
66 | sync.set(true) |
67 | } |
68 | }) |
69 | ) |
70 | } |
71 | } |
72 | |
73 | function About (api, id) { |
74 | // transparent image |
75 | var fallbackImageUrl = 'data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==' |
76 | |
77 | var state = Value({}) |
78 | var yourId = api.keys.sync.id() |
79 | var image = computed([state, 'image', id, yourId], socialValue) |
80 | var name = computed([state, 'name', id, yourId, id.slice(1, 10)], socialValue) |
81 | var description = computed([state, 'description', id, yourId], socialValue) |
82 | |
83 | return { |
84 | name, |
85 | image, |
86 | description, |
87 | names: computed([state, 'name', id, yourId, id.slice(1, 10)], allValues), |
88 | images: computed([state, 'image', id, yourId], allValues), |
89 | descriptions: computed([state, 'description', id, yourId], allValues), |
90 | imageUrl: computed(image, (blobId) => { |
91 | if (blobId) { |
92 | return api.blob.sync.url(blobId) |
93 | } else { |
94 | return fallbackImageUrl |
95 | } |
96 | }), |
97 | push: function (values) { |
98 | var lastState = state() |
99 | var changed = false |
100 | for (var key in values) { |
101 | var valuesForKey = lastState[key] = lastState[key] || {} |
102 | for (var author in values[key]) { |
103 | var value = values[key][author] |
104 | if (!valuesForKey[author] || value[1] > valuesForKey[author][1]) { |
105 | valuesForKey[author] = value |
106 | changed = true |
107 | } |
108 | } |
109 | } |
110 | if (changed) { |
111 | state.set(lastState) |
112 | } |
113 | } |
114 | } |
115 | } |
116 | |
117 | function socialValue (lookup, key, id, yourId, fallback) { |
118 | var result = lookup[key] ? getValue(lookup[key][yourId]) || getValue(lookup[key][id]) || highestRank(lookup[key]) : null |
119 | if (result != null) { |
120 | return result |
121 | } else { |
122 | return fallback || null |
123 | } |
124 | } |
125 | |
126 | function allValues (lookup, key, id, yourId) { |
127 | var values = {} |
128 | for (var author in lookup[key]) { |
129 | var value = getValue(lookup[key][author]) |
130 | if (value != null) { |
131 | values[value] = values[value] || [] |
132 | values[value].push(author) |
133 | } |
134 | } |
135 | return values |
136 | } |
137 | |
138 | function highestRank (lookup) { |
139 | var counts = {} |
140 | var highestCount = 0 |
141 | var currentHighest = null |
142 | for (var key in lookup) { |
143 | var value = getValue(lookup[key]) |
144 | if (value != null) { |
145 | counts[value] = (counts[value] || 0) + 1 |
146 | if (counts[value] > highestCount) { |
147 | currentHighest = value |
148 | highestCount = counts[value] |
149 | } |
150 | } |
151 | } |
152 | return currentHighest |
153 | } |
154 | |
155 | function getValue (item) { |
156 | if (item && item[0]) { |
157 | if (typeof item[0] === 'string') { |
158 | return item[0] |
159 | } else if (item[0] && item[0].link && ref.isLink(item[0].link)) { |
160 | return item[0].link |
161 | } |
162 | } |
163 | } |
164 | |
165 | function StreamWhenConnected (connection, fn) { |
166 | var stream = defer.source() |
167 | onceTrue(connection, function (connection) { |
168 | stream.resolve(fn(connection)) |
169 | }) |
170 | return stream |
171 | } |
172 |
Built with git-ssb-web