Files: 58ab0241031aa549a35cce1e678c27065ae66221 / lib / plugins / network-feed.js
2963 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 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 | return pull( |
26 | ssb.createFeedStream({ live: true, old: false }), |
27 | pull.filter(bumpFilter), |
28 | LookupRoots({ ssb, cache }) |
29 | ) |
30 | }, |
31 | roots: function ({ reverse, limit, resume }) { |
32 | // use resume option if specified |
33 | const opts = { reverse, old: true } |
34 | if (resume) { |
35 | opts[reverse ? 'lt' : 'gt'] = resume |
36 | } |
37 | |
38 | return pullResume.source(ssb.createFeedStream(opts), { |
39 | limit, |
40 | getResume: (item) => { |
41 | return item && item.rts |
42 | }, |
43 | filterMap: pull( |
44 | // BUMP FILTER |
45 | pull.filter(bumpFilter), |
46 | |
47 | // LOOKUP AND ADD ROOTS |
48 | LookupRoots({ ssb, cache }), |
49 | |
50 | // FILTER BLOCKED (don't bump if author blocked, don't include if root author blocked) |
51 | FilterBlocked([ssb.id], { |
52 | isBlocking: ssb.patchwork.contacts.isBlocking, |
53 | useRootAuthorBlocks: true, |
54 | checkRoot: true |
55 | }), |
56 | |
57 | // DON'T REPEAT THE SAME THREAD |
58 | UniqueRoots(), |
59 | |
60 | // MAP ROOT ITEMS |
61 | pull.map(item => { |
62 | const root = item.root || item |
63 | return root |
64 | }), |
65 | |
66 | // RESOLVE ROOTS WITH ABOUTS |
67 | ResolveAbouts({ ssb }), |
68 | |
69 | // ADD THREAD SUMMARY |
70 | pull.asyncMap((item, cb) => { |
71 | threadSummary(item.key, { |
72 | recentLimit: 3, |
73 | readThread: ssb.patchwork.thread.read, |
74 | bumpFilter, |
75 | pullFilter: FilterBlocked([item.value && item.value.author, ssb.id], { isBlocking: ssb.patchwork.contacts.isBlocking }) |
76 | }, (err, summary) => { |
77 | if (err) return cb(err) |
78 | cb(null, extend(item, summary)) |
79 | }) |
80 | }) |
81 | ) |
82 | }) |
83 | } |
84 | } |
85 | } |
86 | |
87 | function isAttendee (msg) { |
88 | const content = msg.value && msg.value.content |
89 | return (content && content.type === 'about' && content.attendee && !content.attendee.remove) |
90 | } |
91 | |
92 | function bumpFilter (msg) { |
93 | if (isAttendee(msg)) { |
94 | return 'attending' |
95 | } else if (msg.value.content.type === 'post') { |
96 | if (getRoot(msg)) { |
97 | return 'reply' |
98 | } else { |
99 | return 'post' |
100 | } |
101 | } else if (msg.value.content.type === 'about') { |
102 | return 'updated' |
103 | } |
104 | } |
105 |
Built with git-ssb-web