Files: 3451510316992d414ec76ba5b29681fe359b7428 / lib / plugins / mentions-feed.js
3682 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 Paramap = require('pull-paramap') |
11 | const FilterBlocked = require('../filter-blocked') |
12 | |
13 | exports.manifest = { |
14 | latest: 'source', |
15 | roots: 'source' |
16 | } |
17 | |
18 | exports.init = function (ssb) { |
19 | // cache mostly just to avoid reading the same roots over and over again |
20 | // not really big enough for multiple refresh cycles |
21 | const cache = HLRU(100) |
22 | |
23 | return { |
24 | latest: function () { |
25 | const query = [{ |
26 | $filter: { |
27 | dest: ssb.id |
28 | } |
29 | }] |
30 | return pull( |
31 | ssb.backlinks.read({ query, live: true, old: false }), |
32 | pull.filter(bumpFilter), |
33 | LookupRoots({ ssb, cache }) |
34 | ) |
35 | |
36 | function bumpFilter (msg) { |
37 | return checkBump(msg, { id: ssb.id }) |
38 | } |
39 | }, |
40 | roots: function ({ reverse, limit, resume }) { |
41 | const filter = { |
42 | dest: ssb.id |
43 | } |
44 | |
45 | // use resume option if specified |
46 | if (resume) { |
47 | filter.timestamp = reverse ? { $lt: resume } : { $gt: resume } |
48 | } |
49 | |
50 | const opts = { |
51 | reverse, |
52 | old: true, |
53 | index: 'DTS', |
54 | query: [ |
55 | { $filter: filter } |
56 | ] |
57 | } |
58 | |
59 | return pullResume.source(ssb.backlinks.read(opts), { |
60 | limit, |
61 | getResume: (item) => { |
62 | return item.timestamp |
63 | }, |
64 | filterMap: pull( |
65 | // CHECK IF IS MENTION |
66 | pull.filter(bumpFilter), |
67 | |
68 | // LOOKUP AND ADD ROOTS |
69 | LookupRoots({ ssb, cache }), |
70 | |
71 | // FILTER BLOCKED (don't bump if author blocked, don't include if root author blocked) |
72 | FilterBlocked([ssb.id], { |
73 | isBlocking: ssb.patchwork.contacts.isBlocking, |
74 | useRootAuthorBlocks: true, |
75 | checkRoot: true |
76 | }), |
77 | |
78 | // DON'T REPEAT THE SAME THREAD |
79 | UniqueRoots(), |
80 | |
81 | // MAP ROOT ITEMS |
82 | pull.map(item => { |
83 | const root = item.root || item |
84 | return root |
85 | }), |
86 | |
87 | // RESOLVE ROOTS WITH ABOUTS |
88 | ResolveAbouts({ ssb }), |
89 | |
90 | // ADD THREAD SUMMARY |
91 | Paramap((item, cb) => { |
92 | threadSummary(item.key, { |
93 | recentLimit: 3, |
94 | readThread: ssb.patchwork.thread.read, |
95 | bumpFilter, |
96 | recentFilter: bumpFilter, |
97 | pullFilter: FilterBlocked([ssb.id], { isBlocking: ssb.patchwork.contacts.isBlocking }) |
98 | }, (err, summary) => { |
99 | if (err) return cb(err) |
100 | cb(null, extend(item, summary, { |
101 | filterResult: undefined, |
102 | rootBump: bumpFilter(item) |
103 | })) |
104 | }) |
105 | }, 10) |
106 | ) |
107 | }) |
108 | |
109 | function bumpFilter (msg) { |
110 | return checkBump(msg, { id: ssb.id }) |
111 | } |
112 | } |
113 | } |
114 | } |
115 | |
116 | function checkBump (msg, { id }) { |
117 | if (msg && msg.value && msg.value.author !== id) { |
118 | if (Array.isArray(msg.value.content.mentions) && msg.value.content.mentions.some(mention => { |
119 | return mention && mention.link === id |
120 | })) { |
121 | return 'mention' |
122 | } else if (msg.value.content.type === 'contact' && msg.value.content.following === true && msg.value.content.contact === id) { |
123 | return 'follow' |
124 | } |
125 | // private gathering invite |
126 | if (msg.value.content.type === 'gathering' && Array.isArray(msg.value.content.recps) && msg.value.content.recps.includes(id)) { |
127 | return 'invite' |
128 | } |
129 | } |
130 | } |
131 |
Built with git-ssb-web