git ssb

10+

Matt McKegg / patchwork



Tree: 38b0812f2f3a84faff8a7c371f0d54fe34ad12c8

Files: 38b0812f2f3a84faff8a7c371f0d54fe34ad12c8 / modules / public.js

6865 bytesRaw
1var MutantMap = require('@mmckegg/mutant/map')
2var computed = require('@mmckegg/mutant/computed')
3var when = require('@mmckegg/mutant/when')
4var send = require('@mmckegg/mutant/send')
5var pull = require('pull-stream')
6var extend = require('xtend')
7
8var plugs = require('patchbay/plugs')
9var h = require('../lib/h')
10var message_compose = plugs.first(exports.message_compose = [])
11var sbot_log = plugs.first(exports.sbot_log = [])
12var sbot_feed = plugs.first(exports.sbot_feed = [])
13var sbot_user_feed = plugs.first(exports.sbot_user_feed = [])
14
15var feed_summary = plugs.first(exports.feed_summary = [])
16var obs_channels = plugs.first(exports.obs_channels = [])
17var obs_subscribed_channels = plugs.first(exports.obs_subscribed_channels = [])
18var get_id = plugs.first(exports.get_id = [])
19var publish = plugs.first(exports.sbot_publish = [])
20var obs_following = plugs.first(exports.obs_following = [])
21var obs_recently_updated_feeds = plugs.first(exports.obs_recently_updated_feeds = [])
22var avatar_image = plugs.first(exports.avatar_image = [])
23var avatar_name = plugs.first(exports.avatar_name = [])
24var obs_local = plugs.first(exports.obs_local = [])
25var obs_connected = plugs.first(exports.obs_connected = [])
26
27exports.screen_view = function (path, sbot) {
28 if (path === '/public') {
29 var id = get_id()
30 var channels = computed(obs_channels(), items => items.slice(0, 8), {comparer: arrayEq})
31 var subscribedChannels = obs_subscribed_channels(id)
32 var loading = computed(subscribedChannels.sync, x => !x)
33 var connectedPeers = obs_connected()
34 var localPeers = obs_local()
35 var connectedPubs = computed([connectedPeers, localPeers], (c, l) => c.filter(x => !l.includes(x)))
36 var following = obs_following(id)
37
38 var oldest = Date.now() - (2 * 24 * 60 * 60e3)
39 getFirstMessage(id, (_, msg) => {
40 if (msg) {
41 // fall back to timestamp stream before this, give 48 hrs for feeds to stabilize
42 if (msg.value.timestamp > oldest) {
43 oldest = Date.now()
44 }
45 }
46 })
47
48 var whoToFollow = computed([obs_following(id), obs_recently_updated_feeds(200)], (following, recent) => {
49 return Array.from(recent).filter(x => x !== id && !following.has(x)).slice(0, 10)
50 })
51
52 var feedSummary = feed_summary(getFeed, [
53 message_compose({type: 'post'}, {placeholder: 'Write a public message'})
54 ], {
55 waitUntil: computed([
56 following.sync,
57 subscribedChannels.sync
58 ], x => x.every(Boolean)),
59 windowSize: 500,
60 filter: (item) => {
61 return (
62 id === item.author ||
63 following().has(item.author) ||
64 subscribedChannels().has(item.channel) ||
65 (item.repliesFrom && item.repliesFrom.has(id)) ||
66 item.digs && item.digs.has(id)
67 )
68 },
69 bumpFilter: (msg, group) => {
70 if (!group.message) {
71 return (
72 isMentioned(id, msg.value.content.mentions) ||
73 msg.value.author === id || (
74 fromDay(msg, group.fromTime) && (
75 following().has(msg.value.author) ||
76 group.repliesFrom.has(id)
77 )
78 )
79 )
80 }
81 return true
82 }
83 })
84
85 var result = h('SplitView', [
86 h('div.side', [
87 h('h2', 'Active Channels'),
88 when(loading, [ h('Loading') ]),
89 h('ChannelList', {
90 hidden: loading
91 }, [
92 MutantMap(channels, (channel) => {
93 var subscribed = subscribedChannels.has(channel.id)
94 return h('a.channel', {
95 href: `##${channel.id}`,
96 classList: [
97 when(subscribed, '-subscribed')
98 ]
99 }, [
100 h('span.name', '#' + channel.id),
101 when(subscribed,
102 h('a -unsubscribe', {
103 'ev-click': send(unsubscribe, channel.id)
104 }, 'Unsubscribe'),
105 h('a -subscribe', {
106 'ev-click': send(subscribe, channel.id)
107 }, 'Subscribe')
108 )
109 ])
110 }, {maxTime: 5})
111 ]),
112
113 when(computed(localPeers, x => x.length), h('h2', 'Local')),
114 h('ProfileList', [
115 MutantMap(localPeers, (id) => {
116 return h('a.profile', {
117 classList: [
118 when(computed([connectedPeers, id], (p, id) => p.includes(id)), '-connected')
119 ],
120 href: `#${id}`
121 }, [
122 h('div.avatar', [avatar_image(id)]),
123 h('div.main', [
124 h('div.name', [ avatar_name(id) ])
125 ])
126 ])
127 })
128 ]),
129
130 when(computed(whoToFollow, x => x.length), h('h2', 'Who to follow')),
131 h('ProfileList', [
132 MutantMap(whoToFollow, (id) => {
133 return h('a.profile', {
134 href: `#${id}`
135 }, [
136 h('div.avatar', [avatar_image(id)]),
137 h('div.main', [
138 h('div.name', [ avatar_name(id) ])
139 ])
140 ])
141 })
142 ]),
143
144 when(computed(connectedPubs, x => x.length), h('h2', 'Connected Pubs')),
145 h('ProfileList', [
146 MutantMap(connectedPubs, (id) => {
147 return h('a.profile', {
148 classList: [ '-connected' ],
149 href: `#${id}`
150 }, [
151 h('div.avatar', [avatar_image(id)]),
152 h('div.main', [
153 h('div.name', [ avatar_name(id) ])
154 ])
155 ])
156 })
157 ])
158 ]),
159 h('div.main', [ feedSummary ])
160 ])
161
162 result.pendingUpdates = feedSummary.pendingUpdates
163 result.reload = feedSummary.reload
164
165 return result
166 }
167
168 // scoped
169
170 function getFeed (opts) {
171 if (opts.lt && opts.lt < oldest) {
172 opts = extend(opts, {lt: parseInt(opts.lt, 10)})
173 return pull(
174 sbot_feed(opts),
175 pull.map((msg) => {
176 if (msg.sync) {
177 return msg
178 } else {
179 return {key: msg.key, value: msg.value, timestamp: msg.value.timestamp}
180 }
181 })
182 )
183 } else {
184 return sbot_log(opts)
185 }
186 }
187}
188
189function fromDay (msg, fromTime) {
190 return (fromTime - msg.timestamp) < (24 * 60 * 60e3)
191}
192
193function isMentioned (id, list) {
194 if (Array.isArray(list)) {
195 return list.includes(id)
196 } else {
197 return false
198 }
199}
200
201function subscribe (id) {
202 publish({
203 type: 'channel',
204 channel: id,
205 subscribed: true
206 })
207}
208
209function unsubscribe (id) {
210 publish({
211 type: 'channel',
212 channel: id,
213 subscribed: false
214 })
215}
216
217function arrayEq (a, b) {
218 if (Array.isArray(a) && Array.isArray(b) && a.length === b.length && a !== b) {
219 return a.every((value, i) => value === b[i])
220 }
221}
222
223function getFirstMessage (feedId, cb) {
224 sbot_user_feed({id: feedId, gte: 0, limit: 1})(null, cb)
225}
226

Built with git-ssb-web