git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: e4249874689b314078266a74aed30d8d3960e8db

Files: e4249874689b314078266a74aed30d8d3960e8db / modules / public.js

6318 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 following = obs_following(id)
36
37 var oldest = Date.now() - (2 * 24 * 60 * 60e3)
38 getFirstMessage(id, (_, msg) => {
39 if (msg) {
40 // fall back to timestamp stream before this, give 48 hrs for feeds to stabilize
41 if (msg.value.timestamp > oldest) {
42 oldest = Date.now()
43 }
44 }
45 })
46
47 var whoToFollow = computed([obs_following(id), obs_recently_updated_feeds(200)], (following, recent) => {
48 return Array.from(recent).filter(x => x !== id && !following.has(x)).slice(0, 10)
49 })
50
51 return h('SplitView', [
52 h('div.side', [
53 h('h2', 'Active Channels'),
54 when(loading, [ h('Loading') ]),
55 h('ChannelList', {
56 hidden: loading
57 }, [
58 MutantMap(channels, (channel) => {
59 var subscribed = subscribedChannels.has(channel.id)
60 return h('a.channel', {
61 href: `##${channel.id}`,
62 classList: [
63 when(subscribed, '-subscribed')
64 ]
65 }, [
66 h('span.name', '#' + channel.id),
67 when(subscribed,
68 h('a -unsubscribe', {
69 'ev-click': send(unsubscribe, channel.id)
70 }, 'Unsubscribe'),
71 h('a -subscribe', {
72 'ev-click': send(subscribe, channel.id)
73 }, 'Subscribe')
74 )
75 ])
76 }, {maxTime: 5})
77 ]),
78
79 when(computed(localPeers, x => x.length), h('h2', 'Local')),
80 h('ProfileList', [
81 MutantMap(localPeers, (id) => {
82 return h('a.profile', {
83 classList: [
84 when(computed([connectedPeers, id], (p, id) => p.includes(id)), '-connected')
85 ],
86 href: `#${id}`
87 }, [
88 h('div.avatar', [avatar_image(id)]),
89 h('div.main', [
90 h('div.name', [ avatar_name(id) ])
91 ])
92 ])
93 })
94 ]),
95
96 when(computed(whoToFollow, x => x.length), h('h2', 'Who to follow')),
97 h('ProfileList', [
98 MutantMap(whoToFollow, (id) => {
99 return h('a.profile', {
100 href: `#${id}`
101 }, [
102 h('div.avatar', [avatar_image(id)]),
103 h('div.main', [
104 h('div.name', [ avatar_name(id) ])
105 ])
106 ])
107 })
108 ])
109 ]),
110 h('div.main', [
111 feed_summary(getFeed, [
112 message_compose({type: 'post'}, {placeholder: 'Write a public message'})
113 ], {
114 waitUntil: computed([
115 following.sync,
116 subscribedChannels.sync
117 ], x => x.every(Boolean)),
118 windowSize: 500,
119 filter: (item) => {
120 return (
121 id === item.author ||
122 following().has(item.author) ||
123 subscribedChannels().has(item.channel) ||
124 (item.repliesFrom && item.repliesFrom.has(id)) ||
125 item.digs && item.digs.has(id)
126 )
127 },
128 bumpFilter: (msg, group) => {
129 if (!group.message) {
130 return (
131 isMentioned(id, msg.value.content.mentions) ||
132 msg.value.author === id || (
133 fromDay(msg, group.fromTime) && (
134 following().has(msg.value.author) ||
135 group.repliesFrom.has(id)
136 )
137 )
138 )
139 }
140 return true
141 }
142 })
143 ])
144 ])
145 }
146
147 // scoped
148
149 function getFeed (opts) {
150 if (opts.lt && opts.lt < oldest) {
151 opts = extend(opts, {lt: parseInt(opts.lt, 10)})
152 console.log('using old feed', opts)
153 return pull(
154 sbot_feed(opts),
155 pull.map((msg) => {
156 if (msg.sync) {
157 return msg
158 } else {
159 return {key: msg.key, value: msg.value, timestamp: msg.value.timestamp}
160 }
161 })
162 )
163 } else {
164 return sbot_log(opts)
165 }
166 }
167}
168
169function fromDay (msg, fromTime) {
170 return (fromTime - msg.timestamp) < (24 * 60 * 60e3)
171}
172
173function isMentioned (id, list) {
174 if (Array.isArray(list)) {
175 return list.includes(id)
176 } else {
177 return false
178 }
179}
180
181function subscribe (id) {
182 publish({
183 type: 'channel',
184 channel: id,
185 subscribed: true
186 })
187}
188
189function unsubscribe (id) {
190 publish({
191 type: 'channel',
192 channel: id,
193 subscribed: false
194 })
195}
196
197function arrayEq (a, b) {
198 if (Array.isArray(a) && Array.isArray(b) && a.length === b.length && a !== b) {
199 return a.every((value, i) => value === b[i])
200 }
201}
202
203function getFirstMessage (feedId, cb) {
204 sbot_user_feed({id: feedId, gte: 0, limit: 1})(null, cb)
205}
206

Built with git-ssb-web