Files: 51b10fcae8f88e89444a0c702a5a50bcaf49c157 / about / obs.js
4406 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)) { |
45 | console.log(id) //throw new Error('About requires an id!') |
46 | console.trace() |
47 | } |
48 | if (!cacheLoading) { |
49 | cacheLoading = true |
50 | loadCache() |
51 | window.things = cache |
52 | } |
53 | if (!cache[id]) { |
54 | cache[id] = About(api, id) |
55 | } |
56 | return cache[id] |
57 | } |
58 | |
59 | function loadCache () { |
60 | pull( |
61 | StreamWhenConnected(api.sbot.obs.connection, sbot => sbot.about.stream({live: true})), |
62 | pull.drain(item => { |
63 | for (var target in item) { |
64 | if (ref.isFeed(target)) { |
65 | get(target).push(item[target]) |
66 | } |
67 | } |
68 | |
69 | if (!sync()) { |
70 | sync.set(true) |
71 | } |
72 | }) |
73 | ) |
74 | } |
75 | } |
76 | |
77 | function About (api, id) { |
78 | // transparent image |
79 | var fallbackImageUrl = 'data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==' |
80 | |
81 | var state = Value({}) |
82 | var yourId = api.keys.sync.id() |
83 | var image = computed([state, 'image', id, yourId], socialValue) |
84 | var name = computed([state, 'name', id, yourId, id.slice(1, 10)], socialValue) |
85 | var description = computed([state, 'description', id, yourId], socialValue) |
86 | |
87 | return { |
88 | name, |
89 | image, |
90 | description, |
91 | names: computed([state, 'name', id, yourId, id.slice(1, 10)], allValues), |
92 | images: computed([state, 'image', id, yourId], allValues), |
93 | descriptions: computed([state, 'description', id, yourId], allValues), |
94 | imageUrl: computed(image, (blobId) => { |
95 | if (blobId) { |
96 | return api.blob.sync.url(blobId) |
97 | } else { |
98 | return fallbackImageUrl |
99 | } |
100 | }), |
101 | push: function (values) { |
102 | var lastState = state() |
103 | var changed = false |
104 | for (var key in values) { |
105 | var valuesForKey = lastState[key] = lastState[key] || {} |
106 | for (var author in values[key]) { |
107 | var value = values[key][author] |
108 | if (!valuesForKey[author] || value.lastSeq > valuesForKey[author].lastSeq) { |
109 | valuesForKey[author] = value |
110 | changed = true |
111 | } |
112 | } |
113 | } |
114 | if (changed) { |
115 | state.set(lastState) |
116 | } |
117 | } |
118 | } |
119 | } |
120 | |
121 | function socialValue (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 allValues (lookup, key, id, yourId) { |
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.value) { |
161 | if (typeof item.value === 'string') { |
162 | return item.value |
163 | } else if (item.value && item.value.link && ref.isLink(item.value.link)) { |
164 | return item.value.link |
165 | } |
166 | } |
167 | } |
168 | |
169 | function StreamWhenConnected (connection, fn) { |
170 | var stream = defer.source() |
171 | onceTrue(connection, function (connection) { |
172 | stream.resolve(fn(connection)) |
173 | }) |
174 | return stream |
175 | } |
176 |
Built with git-ssb-web