git ssb

1+

Daan Patchwork / patchwork



Tree: 3451510316992d414ec76ba5b29681fe359b7428

Files: 3451510316992d414ec76ba5b29681fe359b7428 / lib / plugins / channel-feed.js

4047 bytesRaw
1'use strict'
2const pull = require('pull-stream')
3const HLRU = require('hashlru')
4const extend = require('xtend')
5const pullResume = require('../pull-resume')
6const threadSummary = require('../thread-summary')
7const LookupRoots = require('../lookup-roots')
8const ResolveAbouts = require('../resolve-abouts')
9const UniqueRoots = require('../unique-roots')
10const getRoot = require('../get-root')
11const normalizeChannel = require('ssb-ref').normalizeChannel
12const FilterBlocked = require('../filter-blocked')
13
14exports.manifest = {
15 latest: 'source',
16 roots: 'source'
17}
18
19exports.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
125function 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