git ssb

2+

mixmix / ticktack



Tree: 257c6726a8e5783a5865977441b704c1199bbe90

Files: 257c6726a8e5783a5865977441b704c1199bbe90 / ssb-server-ticktack.js

6461 bytesRaw
1const FlumeView = require('flumeview-level')
2const get = require('lodash/get')
3const pull = require('pull-stream')
4const defer = require('pull-defer')
5const isBlog = require('scuttle-blog/isBlog')
6const { isMsg: isMsgRef } = require('ssb-ref')
7
8const getType = (msg) => get(msg, 'value.content.type')
9const getAuthor = (msg) => get(msg, 'value.author')
10const getCommentRoot = (msg) => get(msg, 'value.content.root')
11const getLikeRoot = (msg) => get(msg, 'value.content.vote.link')
12const getShareRoot = (msg) => get(msg, 'value.content.share.link')
13const getTimestamp = (msg) => get(msg, 'value.timestamp')
14
15const FLUME_VIEW_VERSION = 1
16const MIN_LENGTH_FOR_BLOG_POST = 2500 // note this defn duplicated in blog.sync.isBlog
17
18module.exports = {
19 name: 'ticktack',
20 version: 1,
21 manifest: {
22 get: 'async',
23 read: 'source',
24 readBlogs: 'source',
25 getBlogs: 'async',
26 readComments: 'source',
27 readAllComments: 'source',
28 readAllLikes: 'source',
29 readAllShares: 'source',
30 readLikes: 'source'
31 },
32 init: (server, config) => {
33 // NOTE - this could and should be refactored to use e.g. ssb-query
34 // because ssb-query I think can provide much of this functionality
35 // and then I can provide better stepping tools for pull-streams, like pull-next-query
36 console.log('> initialising ticktack plugin')
37 const myKey = server.keys.id
38
39 const view = server._flumeUse(
40 'ticktack',
41 FlumeView(FLUME_VIEW_VERSION, map)
42 )
43
44 return {
45 get: view.get,
46 read: view.read,
47 readBlogs,
48 getBlogs,
49 readComments,
50 readAllComments,
51 readAllLikes,
52 readAllShares,
53 readLikes
54 // readShares
55 }
56
57 function map (msg, seq) {
58 var root
59
60 switch (getType(msg)) {
61 case 'blog':
62 if (isBlog(msg) && isMyMsg(msg)) return [['B', msg.key, getTimestamp(msg)]]
63 else return []
64
65 case 'vote':
66 root = getLikeRoot(msg)
67 // TODO figure out how to only store likes I care about
68 if (root) return [['L', root, getTimestamp(msg)]]
69 else return []
70
71 // Note this catches:
72 // - all likes, on all things D:
73 // - likes AND unlikes
74
75 case 'post':
76 root = getCommentRoot(msg)
77 // TODO figure out how to only store comments I care about
78 if (!root && isMyMsg(msg) && isPlog(msg)) return [['B', msg.key, getTimestamp(msg)]]
79 else if (root) return [['C', root, getTimestamp(msg)]]
80 else return []
81
82 // Note this catches:
83 // - all comments, on all things D:
84
85 default:
86 return []
87 }
88 }
89
90 function readBlogs (options = {}) {
91 const query = Object.assign({}, {
92 gte: ['B', null, null],
93 // null is the 'minimum' structure in bytewise ordering
94 lte: ['B', undefined, undefined],
95 reverse: true,
96 values: true,
97 keys: false,
98 seqs: false
99 }, options)
100
101 return view.read(query)
102 }
103
104 function getBlogs (options, cb) {
105 if (typeof options === 'function') {
106 cb = options
107 options = {}
108 }
109
110 pull(
111 readBlogs(options),
112 pull.collect(cb)
113 )
114 }
115
116 function readComments (blog, options = {}) {
117 var key = getBlogKey(blog)
118
119 const query = Object.assign({}, {
120 gt: ['C', key, null],
121 lt: ['C', key, undefined],
122 // undefined is the 'maximum' structure in bytewise ordering https://www.npmjs.com/package/bytewise#order-of-supported-structures
123 reverse: true,
124 values: true,
125 keys: false,
126 seqs: false
127 }, options)
128
129 return view.read(query)
130 }
131
132 function readLikes (blog, options = {}) {
133 var key = getBlogKey(blog)
134
135 const query = Object.assign({}, {
136 gt: ['L', key, null],
137 lt: ['L', key, undefined],
138 reverse: true,
139 values: true,
140 keys: false,
141 seqs: false
142 }, options)
143
144 return view.read(query)
145 }
146
147 function readAllComments (opts = {}) {
148 return readAllSource({
149 type: 'post',
150 makeFilter: blogIds => msg => {
151 if (getAuthor(msg) === myKey) return false // exclude my posts
152 if (getCommentRoot(msg) === undefined) return false // want only 'comments' (reply posts)
153 // NOTE - this one will get nested replies too
154
155 return blogIds.includes(getCommentRoot(msg)) // is about one of my blogs
156 },
157 opts
158 })
159 }
160
161 function readAllLikes (opts = {}) {
162 return readAllSource({
163 type: 'vote',
164 makeFilter: blogIds => msg => {
165 if (getAuthor(msg) === myKey) return false // exclude my likes
166
167 return blogIds.includes(getLikeRoot(msg)) // is about one of my blogs
168 },
169 opts
170 })
171 }
172
173 function readAllShares (opts = {}) {
174 return readAllSource({
175 type: 'share',
176 makeFilter: (blogIds) => msg => {
177 if (getAuthor(msg) === myKey) return false // exclude my shares
178
179 return blogIds.includes(getShareRoot(msg)) // is about one of my blogs
180 },
181 opts
182 })
183 }
184
185 function readAllSource ({ type, makeFilter, opts = {} }) {
186 var source = defer.source()
187
188 getBlogs({ keys: true, values: false }, (err, data) => {
189 if (err) throw err
190
191 const blogIds = data.map(d => d[1])
192
193 opts.type = type
194 var limit = opts.limit
195 delete opts.limit
196 // have to remove limit from the query otherwise Next stalls out if it doesn't get a new result
197
198 const _source = pull(
199 server.messagesByType(opts), // TODO - check/ note why I didn't use e.g. readComments
200 pull.filter(makeFilter(blogIds)),
201 limit ? pull.take(limit) : true
202 )
203
204 source.resolve(_source)
205 })
206
207 return source
208 }
209
210 function isMyMsg (msg) {
211 return getAuthor(msg) === myKey
212 }
213 }
214}
215
216function getBlogKey (blog) {
217 if (isMsgRef(blog)) return blog
218 // else if (isMsgRef(blog.key) && isBlog(blog)) return blog.key
219 else if (isMsgRef(blog.key) && (isBlog(blog) || isPlog(blog))) return blog.key
220}
221
222// a Plog is a Blog shaped Post!
223function isPlog (msg) {
224 // if (get(msg, 'value.content.text', '').length >= MIN_LENGTH_FOR_BLOG_POST) console.log(get(msg, 'value.content.text', '').length)
225 return get(msg, 'value.content.text', '').length >= MIN_LENGTH_FOR_BLOG_POST
226}
227

Built with git-ssb-web