Files: f120707982df391596bae10f1144b72fe1a25960 / contact / obs.js
3404 bytesRaw
1 | var nest = require('depnest') |
2 | var { Value, Dict, computed } = require('mutant') |
3 | var pull = require('pull-stream') |
4 | var ref = require('ssb-ref') |
5 | |
6 | exports.needs = nest({ |
7 | 'sbot.pull.stream': 'first' |
8 | }) |
9 | |
10 | exports.gives = nest({ |
11 | 'contact.obs': ['following', 'followers'], //, 'blocking', 'blockers'], |
12 | 'sbot.hook.publish': true |
13 | }) |
14 | |
15 | exports.create = function (api) { |
16 | var cacheLoading = false |
17 | var cache = Dict() |
18 | var sync = Value(false) |
19 | |
20 | return nest({ |
21 | 'contact.obs': { |
22 | following: following, |
23 | followers: followers, |
24 | // blocking: (id) => values(get(id), 'blocking', true), |
25 | // blockers: (id) => values(get(id), 'blockers', true), |
26 | }, |
27 | 'sbot.hook.publish': function (msg) { |
28 | // TODO ??? |
29 | // if (isContact(msg)) { |
30 | // // HACK: make interface more responsive when sbot is busy |
31 | // var source = msg.value.author |
32 | // var dest = msg.value.content.contact |
33 | |
34 | // if (typeof msg.value.content.following === 'boolean') { |
35 | // update(source, { |
36 | // following: { |
37 | // [dest]: [msg.value.content] |
38 | // } |
39 | // }) |
40 | // update(dest, { |
41 | // followers: { |
42 | // [source]: [msg.value.content] |
43 | // } |
44 | // }) |
45 | // } |
46 | // if (typeof msg.value.content.blocking === 'boolean') { |
47 | // update(source, { |
48 | // blocking: { |
49 | // [dest]: [msg.value.content] |
50 | // } |
51 | // }) |
52 | // update(dest, { |
53 | // blockers: { |
54 | // [source]: [msg.value.content] |
55 | // } |
56 | // }) |
57 | // } |
58 | // } |
59 | } |
60 | }) |
61 | |
62 | function following (key) { |
63 | var obs = computed(get(key), state => { |
64 | return Object.keys(state) |
65 | .reduce((sofar, next) => { |
66 | if (state[next]) return [...sofar, next] |
67 | else return sofar |
68 | }, []) |
69 | }) |
70 | |
71 | obs.sync = sync |
72 | return obs |
73 | } |
74 | |
75 | function followers (key) { |
76 | var obs = computed(cache, cache => { |
77 | return Object.keys(cache) |
78 | .reduce((sofar, next) => { |
79 | if (cache[next][key]) return [...sofar, next] |
80 | else return sofar |
81 | }, []) |
82 | }) |
83 | |
84 | obs.sync = sync |
85 | return obs |
86 | } |
87 | |
88 | function loadCache () { |
89 | pull( |
90 | api.sbot.pull.stream(sbot => sbot.friends.stream({live: true})), |
91 | pull.drain(item => { |
92 | for (var source in item) { |
93 | if (ref.isFeed(source)) update(source, item[source]) |
94 | } |
95 | |
96 | if (!sync()) { |
97 | sync.set(true) |
98 | } |
99 | }) |
100 | ) |
101 | } |
102 | |
103 | function update (sourceId, values) { |
104 | // ssb-friends: values = { |
105 | // keyA: true|null|false (friend, neutral, block) |
106 | // keyB: true|null|false (friend, neutral, block) |
107 | // } |
108 | var state = get(sourceId) |
109 | var lastState = state() |
110 | var changed = false |
111 | for (var targetId in values) { |
112 | if (values[targetId] != lastState[targetId]) { |
113 | lastState[targetId] = values[targetId] |
114 | changed = true |
115 | } |
116 | } |
117 | |
118 | if (changed) { |
119 | state.set(lastState) |
120 | } |
121 | } |
122 | |
123 | function get (id) { |
124 | if (!ref.isFeed(id)) throw new Error('Contact state requires an id!') |
125 | if (!cacheLoading) { |
126 | cacheLoading = true |
127 | loadCache() |
128 | } |
129 | if (!cache.has(id)) { |
130 | cache.put(id, Value({})) |
131 | } |
132 | return cache.get(id) |
133 | } |
134 | } |
135 | |
136 | function isContact (msg) { |
137 | return msg.value && msg.value.content && msg.value.content.type === 'contact' |
138 | } |
139 | |
140 |
Built with git-ssb-web