Files: 13be5ee9906beb5d8c2a24db46c68ef183c78d3a / lib / feed-summary.js
4172 bytesRaw
1 | var pull = require('pull-stream') |
2 | var pullPushable = require('pull-pushable') |
3 | var pullNext = require('pull-next') |
4 | var SortedArray = require('sorted-array-functions') |
5 | |
6 | module.exports = FeedSummary |
7 | |
8 | function FeedSummary (source, windowSize, cb) { |
9 | var last = null |
10 | var returned = false |
11 | var done = false |
12 | return pullNext(() => { |
13 | if (!done) { |
14 | var next = {reverse: true, limit: windowSize || 1000, live: false} |
15 | if (last) { |
16 | next.lt = last.timestamp || last.value.sequence |
17 | } |
18 | var pushable = pullPushable() |
19 | pull( |
20 | source(next), |
21 | pull.collect((err, values) => { |
22 | if (err) throw err |
23 | if (!values.length) { |
24 | done = true |
25 | } else { |
26 | groupMessages(values).forEach(v => pushable.push(v)) |
27 | last = values[values.length - 1] |
28 | } |
29 | pushable.end() |
30 | if (!returned) cb && cb() |
31 | returned = true |
32 | }) |
33 | ) |
34 | } |
35 | return pushable |
36 | }) |
37 | } |
38 | |
39 | function groupMessages (messages, filter) { |
40 | var follows = {} |
41 | var messageUpdates = {} |
42 | reverseForEach(messages, function (msg) { |
43 | if (!msg.value) return |
44 | var c = msg.value.content |
45 | if (c.type === 'contact') { |
46 | updateContact(msg, follows) |
47 | } else if (c.type === 'vote') { |
48 | if (c.vote && c.vote.link) { |
49 | // only show digs of posts added in the current window |
50 | // and only for the main post |
51 | const group = messageUpdates[c.vote.link] |
52 | if (group) { |
53 | if (c.vote.value > 0) { |
54 | group.lastUpdateType = 'dig' |
55 | group.digs.add(msg.value.author) |
56 | group.updated = msg.timestamp |
57 | } else { |
58 | group.digs.delete(msg.value.author) |
59 | if (group.lastUpdateType === 'dig' && !group.digs.size && !group.replies.length) { |
60 | group.lastUpdateType = 'reply' |
61 | } |
62 | } |
63 | } |
64 | } |
65 | } else { |
66 | if (c.root) { |
67 | const group = ensureMessage(c.root, messageUpdates) |
68 | group.lastUpdateType = 'reply' |
69 | group.repliesFrom.add(msg.value.author) |
70 | //SortedArray.add(group.replies, msg, compareUserTimestamp) |
71 | group.replies.push(msg) |
72 | group.channel = group.channel || msg.value.content.channel |
73 | group.updated = msg.timestamp |
74 | } else { |
75 | const group = ensureMessage(msg.key, messageUpdates) |
76 | group.lastUpdateType = 'post' |
77 | group.updated = msg.timestamp |
78 | group.author = msg.value.author |
79 | group.channel = msg.value.content.channel |
80 | group.message = msg |
81 | } |
82 | } |
83 | }) |
84 | |
85 | var result = [] |
86 | Object.keys(follows).forEach((key) => { |
87 | SortedArray.add(result, follows[key], compareUpdated) |
88 | }) |
89 | Object.keys(messageUpdates).forEach((key) => { |
90 | SortedArray.add(result, messageUpdates[key], compareUpdated) |
91 | }) |
92 | return result |
93 | } |
94 | |
95 | function compareUserTimestamp (a, b) { |
96 | return a.value.timestamp - b.value.timestamp |
97 | } |
98 | |
99 | function compareUpdated (a, b) { |
100 | return b.updated - a.updated |
101 | } |
102 | |
103 | function reverseForEach (items, fn) { |
104 | var i = items.length - 1 |
105 | var start = Date.now() |
106 | nextBatch() |
107 | |
108 | function nextBatch () { |
109 | while (i >= 0 && Date.now() - start < 10) { |
110 | fn(items[i], i) |
111 | i -= 1 |
112 | } |
113 | |
114 | if (i > 0) { |
115 | setImmediate(nextBatch) |
116 | } |
117 | } |
118 | } |
119 | |
120 | function updateContact (msg, groups) { |
121 | var c = msg.value.content |
122 | var id = msg.value.author |
123 | var group = groups[id] |
124 | if (c.contact) { |
125 | if (c.following) { |
126 | if (!group) { |
127 | group = groups[id] = { |
128 | type: 'follow', |
129 | lastUpdateType: null, |
130 | contacts: new Set(), |
131 | updated: 0, |
132 | author: id, |
133 | id: id |
134 | } |
135 | } |
136 | group.contacts.add(c.contact) |
137 | group.updated = msg.timestamp |
138 | } else { |
139 | if (group) { |
140 | group.contacts.delete(c.contact) |
141 | if (!group.contacts.size) { |
142 | delete groups[id] |
143 | } |
144 | } |
145 | } |
146 | } |
147 | } |
148 | |
149 | function ensureMessage (id, groups) { |
150 | var group = groups[id] |
151 | if (!group) { |
152 | group = groups[id] = { |
153 | type: 'message', |
154 | repliesFrom: new Set(), |
155 | replies: [], |
156 | message: null, |
157 | messageId: id, |
158 | digs: new Set(), |
159 | updated: 0 |
160 | } |
161 | } |
162 | return group |
163 | } |
164 |
Built with git-ssb-web