Files: 3451510316992d414ec76ba5b29681fe359b7428 / lib / plugins / channel-feed.js
4047 bytesRaw
1 | |
2 | const pull = require('pull-stream') |
3 | const HLRU = require('hashlru') |
4 | const extend = require('xtend') |
5 | const pullResume = require('../pull-resume') |
6 | const threadSummary = require('../thread-summary') |
7 | const LookupRoots = require('../lookup-roots') |
8 | const ResolveAbouts = require('../resolve-abouts') |
9 | const UniqueRoots = require('../unique-roots') |
10 | const getRoot = require('../get-root') |
11 | const normalizeChannel = require('ssb-ref').normalizeChannel |
12 | const FilterBlocked = require('../filter-blocked') |
13 | |
14 | exports.manifest = { |
15 | latest: 'source', |
16 | roots: 'source' |
17 | } |
18 | |
19 | exports.init = function (ssb) { |
20 | // cache mostly just to avoid reading the same roots over and over again |
21 | // not really big enough for multiple refresh cycles |
22 | const cache = HLRU(100) |
23 | |
24 | return { |
25 | latest: function ({ channel }) { |
26 | channel = normalizeChannel(channel) |
27 | const query = [{ |
28 | $filter: { |
29 | dest: `#${channel}` |
30 | } |
31 | }] |
32 | return pull( |
33 | ssb.backlinks.read({ old: false, live: true, query, awaitReady: false }), |
34 | pull.filter(msg => checkBump(msg, { channel })), |
35 | LookupRoots({ ssb, cache }) |
36 | // TODO: don't bump if author blocked |
37 | ) |
38 | }, |
39 | /** |
40 | * @param {Object} opts |
41 | * @param {Boolean} opts.reverse |
42 | * @param opts.limit |
43 | * @param {Number} opts.resume |
44 | * @param opts.channel |
45 | */ |
46 | roots: function ({ reverse = false, limit = null, resume = null, channel = null }) { |
47 | channel = normalizeChannel(channel) |
48 | |
49 | // use resume option if specified |
50 | let rts |
51 | if (resume) { |
52 | rts = reverse ? { $lt: resume } : { $gt: resume } |
53 | } else { |
54 | rts = { $gt: 0 } |
55 | } |
56 | |
57 | const opts = { |
58 | reverse, |
59 | awaitReady: false, |
60 | old: true, |
61 | query: [{ |
62 | $filter: { |
63 | dest: `#${channel}`, |
64 | rts |
65 | } |
66 | }] |
67 | } |
68 | |
69 | return pullResume.source(ssb.backlinks.read(opts), { |
70 | limit, |
71 | getResume: (item) => { |
72 | return item.rts |
73 | }, |
74 | filterMap: pull( |
75 | // CHECK IF SHOULD BE INCLUDED |
76 | pull.filter(bumpFilter), |
77 | |
78 | // LOOKUP AND ADD ROOTS |
79 | LookupRoots({ ssb, cache }), |
80 | |
81 | // FILTER BLOCKED (don't bump if author blocked, don't include if root author blocked) |
82 | FilterBlocked([ssb.id], { |
83 | isBlocking: ssb.patchwork.contacts.isBlocking, |
84 | useRootAuthorBlocks: true, |
85 | checkRoot: true |
86 | }), |
87 | |
88 | // DON'T REPEAT THE SAME THREAD |
89 | UniqueRoots(), |
90 | |
91 | // MAP ROOT ITEMS |
92 | pull.map(item => { |
93 | const root = item.root || item |
94 | return root |
95 | }), |
96 | |
97 | // RESOLVE ROOTS WITH ABOUTS |
98 | ResolveAbouts({ ssb }), |
99 | |
100 | // ADD THREAD SUMMARY |
101 | pull.asyncMap((item, cb) => { |
102 | threadSummary(item.key, { |
103 | recentLimit: 3, |
104 | readThread: ssb.patchwork.thread.read, |
105 | bumpFilter, |
106 | recentFilter: bumpFilter, |
107 | pullFilter: FilterBlocked([item.value && item.value.author, ssb.id], { isBlocking: ssb.patchwork.contacts.isBlocking }) |
108 | }, (err, summary) => { |
109 | if (err) return cb(err) |
110 | cb(null, extend(item, summary, { |
111 | rootBump: bumpFilter(item) |
112 | })) |
113 | }) |
114 | }) |
115 | ) |
116 | }) |
117 | |
118 | function bumpFilter (msg) { |
119 | return checkBump(msg, { channel }) |
120 | } |
121 | } |
122 | } |
123 | } |
124 | |
125 | function checkBump (msg, { channel }) { |
126 | if (!msg.value) return |
127 | if (msg.value.content.type === 'vote') return |
128 | if (normalizeChannel(msg.value.content.channel) === channel) { |
129 | if (getRoot(msg)) { |
130 | return 'reply' |
131 | } else { |
132 | return 'post' |
133 | } |
134 | } |
135 | |
136 | if (Array.isArray(msg.value.content.mentions)) { |
137 | if (msg.value.content.mentions.some(mention => |
138 | mention && typeof mention.link === 'string' && |
139 | mention.link.startsWith('#') && normalizeChannel(mention.link) === channel |
140 | )) { |
141 | return 'channel-mention' |
142 | } |
143 | } |
144 | } |
145 |
Built with git-ssb-web