git ssb

7+

dinoworm ๐Ÿ› / patchcore



Tree: 7bd9775b75c52ca02f3e47ccb20e59533accb156

Files: 7bd9775b75c52ca02f3e47ccb20e59533accb156 / contact / obs.js

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

Built with git-ssb-web