git ssb

2+

mixmix / ticktack



Commit b594e41bf900f3f0b270f809fae0596be6cceb54

refactor ticktack-plugin to make generic readAll sources

mix irving committed on 5/7/2018, 6:52:48 AM
Parent: f3a07a62ed183316f08c7c0cf24dcb767afd29b1

Files changed

app/page/notifications.jschanged
app/page/statsShow.jschanged
background-process.jschanged
ssb-server-blog-stats.jsdeleted
ssb-server-ticktack.jsadded
app/page/notifications.jsView
@@ -15,8 +15,10 @@
1515 exports.create = (api) => {
1616 return nest('app.page.notifications', function (location) {
1717 // location here can expected to be: { page: 'notifications', section: * }
1818
19+ if (!location.section) return
20+
1921 var scroller = api.app.html.scroller({
2022 classList: ['content'],
2123 stream: createBlogCommentStream,
2224 render: Comment
@@ -28,9 +30,9 @@
2830
2931 onceTrue(api.sbot.obs.connection, server => {
3032 if (resolved) return
3133
32- source.resolve(server.blogStats.readAllComments(opts))
34+ source.resolve(server.ticktack.readAllComments(opts))
3335 resolved = true
3436 })
3537
3638 return source
app/page/statsShow.jsView
@@ -186,9 +186,9 @@
186186
187187 function fetchBlogData ({ server, store }) {
188188 const myKey = server.id
189189
190- server.blogStats.getBlogs({}, (err, blogs) => {
190+ server.ticktack.getBlogs({}, (err, blogs) => {
191191 if (err) console.error(err)
192192
193193 // TODO - change this once merge in the new notifications-hanger work
194194 // i.e. do one query for ALL comments on my blogs as opposed to N queries
@@ -205,9 +205,9 @@
205205 function fetchComments ({ server, store, blog }) {
206206 if (!store.comments.has(blog.key)) store.comments.put(blog.key, MutantArray())
207207
208208 pull(
209- server.blogStats.readComments(blog),
209+ server.ticktack.readComments(blog),
210210 pull.drain(msg => {
211211 if (msg.value.author === myKey) return
212212 store.comments.get(blog.key).push(msg)
213213 })
@@ -217,9 +217,9 @@
217217 function fetchLikes ({ server, store, blog }) {
218218 if (!store.likes.has(blog.key)) store.likes.put(blog.key, MutantArray())
219219
220220 pull(
221- server.blogStats.readLikes(blog),
221+ server.ticktack.readLikes(blog),
222222 pull.drain(msg => {
223223 if (msg.value.author === myKey) return
224224
225225 const isUnlike = get(msg, 'value.content.vote.value', 1) < 1
background-process.jsView
@@ -21,9 +21,9 @@
2121 .use(require('ssb-about'))
2222 // .use(require('ssb-ebt'))
2323 .use(require('ssb-ws'))
2424 .use(require('ssb-server-channel'))
25- .use(require('./ssb-server-blog-stats'))
25+ .use(require('./ssb-server-ticktack'))
2626
2727 Client(config.keys, config, (err, ssbServer) => {
2828 if (err) {
2929 console.log('> starting sbot')
ssb-server-blog-stats.jsView
@@ -1,206 +1,0 @@
1-const FlumeView = require('flumeview-level')
2-const get = require('lodash/get')
3-const pull = require('pull-stream')
4-const defer = require('pull-defer')
5-const isBlog = require('scuttle-blog/isBlog')
6-const { isMsg: isMsgRef } = require('ssb-ref')
7-
8-const getType = (msg) => get(msg, 'value.content.type')
9-const getAuthor = (msg) => get(msg, 'value.author')
10-const getCommentRoot = (msg) => get(msg, 'value.content.root')
11-const getLikeRoot = (msg) => get(msg, 'value.content.vote.link')
12-const getTimestamp = (msg) => get(msg, 'value.timestamp')
13-
14-const FLUME_VIEW_VERSION = 1
15-
16-module.exports = {
17- name: 'blogStats',
18- version: 1,
19- manifest: {
20- get: 'async',
21- read: 'source',
22- readBlogs: 'source',
23- getBlogs: 'async',
24- readComments: 'source',
25- readAllComments: 'source', // TEMP
26- readLikes: 'source'
27- },
28- init: (server, config) => {
29- console.log('> initialising blog-stats plugin')
30- const myKey = server.keys.id
31-
32- const view = server._flumeUse(
33- 'internalblogStats',
34- FlumeView(FLUME_VIEW_VERSION, map)
35- )
36-
37- return {
38- get: view.get,
39- read: view.read,
40- readBlogs,
41- getBlogs,
42- readComments,
43- readAllComments,
44- readLikes
45- // readShares
46- }
47-
48- function map (msg, seq) {
49- var root
50-
51- switch (getType(msg)) {
52- case 'blog':
53- if (isBlog(msg) && isMyMsg(msg)) return [['B', msg.key, getTimestamp(msg)]]
54- else return []
55-
56- case 'vote':
57- root = getLikeRoot(msg)
58- // TODO figure out how to only store likes I care about
59- if (root) return [['L', root, getTimestamp(msg)]]
60- else return []
61-
62- // Note this catches:
63- // - all likes, on all things D:
64- // - likes AND unlikes
65-
66- case 'post':
67- root = getCommentRoot(msg)
68- // TODO figure out how to only store comments I care about
69- if (!root && isMyMsg(msg) && isPlog(msg)) return [['B', msg.key, getTimestamp(msg)]]
70- else if (root) return [['C', root, getTimestamp(msg)]]
71- else return []
72-
73- // Note this catches:
74- // - all comments, on all things D:
75-
76- default:
77- return []
78- }
79- }
80-
81- // a Plog is a Blog shaped Post!
82- function isPlog (msg) {
83- // if (get(msg, 'value.content.text', '').length >= 2500) console.log(get(msg, 'value.content.text', '').length)
84- return get(msg, 'value.content.text', '').length >= 2500
85- }
86-
87- function readBlogs (options = {}) {
88- const query = Object.assign({}, {
89- gte: ['B', null, null],
90- // null is the 'minimum' structure in bytewise ordering
91- lte: ['B', undefined, undefined],
92- reverse: true,
93- values: true,
94- keys: false,
95- seqs: false
96- }, options)
97-
98- return view.read(query)
99- }
100-
101- function getBlogs (options, cb) {
102- if (typeof options === 'function') {
103- cb = options
104- options = {}
105- }
106-
107- pull(
108- readBlogs(options),
109- pull.collect(cb)
110- )
111- }
112-
113- function readComments (blog, options = {}) {
114- var key = getBlogKey(blog)
115-
116- const query = Object.assign({}, {
117- gt: ['C', key, null],
118- lt: ['C', key, undefined],
119- // undefined is the 'maximum' structure in bytewise ordering https://www.npmjs.com/package/bytewise#order-of-supported-structures
120- reverse: true,
121- values: true,
122- keys: false,
123- seqs: false
124- }, options)
125-
126- return view.read(query)
127- }
128-
129- function readAllComments (opts = {}) {
130- var source = defer.source()
131-
132- getBlogs({ keys: true, values: false }, (err, data) => {
133- if (err) throw err
134-
135- const blogIds = data.map(d => d[1])
136-
137- opts.type = 'post'
138- var limit = opts.limit
139- delete opts.limit
140- // have to remove limit from the query otherwise Next stalls out if it doesn't get a new result
141-
142- const _source = pull(
143- server.messagesByType(opts),
144- pull.filter(msg => {
145- if (msg.value.author === server.id) return false // exclude my posts
146- if (msg.value.content.root === undefined) return false // want only 'comments' (reply posts)
147-
148- return blogIds.includes(msg.value.content.root) // is about one of my blogs
149- }),
150- limit ? pull.take(limit) : true
151- )
152-
153- // I don't know what order results some out of flumeview-level read
154- // which makes this perhaps unideal for Next / mutant-scroll
155- // const query = {
156- // gt: [ 'C', null, opts.gt || null ],
157- // lt: [ 'C', undefined, opts.lt || undefined ],
158- // reverse: opts.reverse === undefined ? true : opts.reverse,
159- // live: opts.reverse === undefined ? true : opts.reverse,
160- // values: true,
161- // keys: true,
162- // seqs: false
163- // }
164- // const _source = pull(
165- // view.read(query),
166- // pull.filter(result => {
167- // return blogIds.includes(result.key[1])
168- // }),
169- // pull.map(result => result.value),
170- // pull.take(opts.limit)
171- // )
172-
173- source.resolve(_source)
174- })
175-
176- return pull(
177- source
178- )
179- }
180-
181- function readLikes (blog, options = {}) {
182- var key = getBlogKey(blog)
183-
184- const query = Object.assign({}, {
185- gt: ['L', key, null],
186- lt: ['L', key, undefined],
187- reverse: true,
188- values: true,
189- keys: false,
190- seqs: false
191- }, options)
192-
193- return view.read(query)
194- }
195-
196- function getBlogKey (blog) {
197- if (isMsgRef(blog)) return blog
198- // else if (isMsgRef(blog.key) && isBlog(blog)) return blog.key
199- else if (isMsgRef(blog.key) && (isBlog(blog) || isPlog(blog))) return blog.key
200- }
201-
202- function isMyMsg (msg) {
203- return getAuthor(msg) === myKey
204- }
205- }
206-}
ssb-server-ticktack.jsView
@@ -1,0 +1,221 @@
1+const FlumeView = require('flumeview-level')
2+const get = require('lodash/get')
3+const pull = require('pull-stream')
4+const defer = require('pull-defer')
5+const isBlog = require('scuttle-blog/isBlog')
6+const { isMsg: isMsgRef } = require('ssb-ref')
7+
8+const getType = (msg) => get(msg, 'value.content.type')
9+const getAuthor = (msg) => get(msg, 'value.author')
10+const getCommentRoot = (msg) => get(msg, 'value.content.root')
11+const getLikeRoot = (msg) => get(msg, 'value.content.vote.link')
12+const getTimestamp = (msg) => get(msg, 'value.timestamp')
13+
14+const FLUME_VIEW_VERSION = 1
15+
16+module.exports = {
17+ name: 'ticktack',
18+ version: 1,
19+ manifest: {
20+ get: 'async',
21+ read: 'source',
22+ readBlogs: 'source',
23+ getBlogs: 'async',
24+ readComments: 'source',
25+ readAllComments: 'source',
26+ readAllLikes: 'source',
27+ readAllShares: 'source',
28+ readLikes: 'source'
29+ },
30+ init: (server, config) => {
31+ console.log('> initialising ticktack plugin')
32+ const myKey = server.keys.id
33+
34+ const view = server._flumeUse(
35+ 'ticktack',
36+ FlumeView(FLUME_VIEW_VERSION, map)
37+ )
38+
39+ return {
40+ get: view.get,
41+ read: view.read,
42+ readBlogs,
43+ getBlogs,
44+ readComments,
45+ readAllComments,
46+ readAllLikes,
47+ readAllShares,
48+ readLikes
49+ // readShares
50+ }
51+
52+ function map (msg, seq) {
53+ var root
54+
55+ switch (getType(msg)) {
56+ case 'blog':
57+ if (isBlog(msg) && isMyMsg(msg)) return [['B', msg.key, getTimestamp(msg)]]
58+ else return []
59+
60+ case 'vote':
61+ root = getLikeRoot(msg)
62+ // TODO figure out how to only store likes I care about
63+ if (root) return [['L', root, getTimestamp(msg)]]
64+ else return []
65+
66+ // Note this catches:
67+ // - all likes, on all things D:
68+ // - likes AND unlikes
69+
70+ case 'post':
71+ root = getCommentRoot(msg)
72+ // TODO figure out how to only store comments I care about
73+ if (!root && isMyMsg(msg) && isPlog(msg)) return [['B', msg.key, getTimestamp(msg)]]
74+ else if (root) return [['C', root, getTimestamp(msg)]]
75+ else return []
76+
77+ // Note this catches:
78+ // - all comments, on all things D:
79+
80+ default:
81+ return []
82+ }
83+ }
84+
85+ function readBlogs (options = {}) {
86+ const query = Object.assign({}, {
87+ gte: ['B', null, null],
88+ // null is the 'minimum' structure in bytewise ordering
89+ lte: ['B', undefined, undefined],
90+ reverse: true,
91+ values: true,
92+ keys: false,
93+ seqs: false
94+ }, options)
95+
96+ return view.read(query)
97+ }
98+
99+ function getBlogs (options, cb) {
100+ if (typeof options === 'function') {
101+ cb = options
102+ options = {}
103+ }
104+
105+ pull(
106+ readBlogs(options),
107+ pull.collect(cb)
108+ )
109+ }
110+
111+ function readComments (blog, options = {}) {
112+ var key = getBlogKey(blog)
113+
114+ const query = Object.assign({}, {
115+ gt: ['C', key, null],
116+ lt: ['C', key, undefined],
117+ // undefined is the 'maximum' structure in bytewise ordering https://www.npmjs.com/package/bytewise#order-of-supported-structures
118+ reverse: true,
119+ values: true,
120+ keys: false,
121+ seqs: false
122+ }, options)
123+
124+ return view.read(query)
125+ }
126+
127+ function readLikes (blog, options = {}) {
128+ var key = getBlogKey(blog)
129+
130+ const query = Object.assign({}, {
131+ gt: ['L', key, null],
132+ lt: ['L', key, undefined],
133+ reverse: true,
134+ values: true,
135+ keys: false,
136+ seqs: false
137+ }, options)
138+
139+ return view.read(query)
140+ }
141+
142+ function readAllComments (opts = {}) {
143+ return readAllSource({
144+ type: 'post',
145+ makeFilter: blogIds => msg => {
146+ if (getAuthor(msg) === myKey) return false // exclude my posts
147+ if (getCommentRoot(msg) === undefined) return false // want only 'comments' (reply posts)
148+ // NOTE - this one will get nested replies too
149+
150+ return blogIds.includes(getCommentRoot(msg)) // is about one of my blogs
151+ },
152+ opts
153+ })
154+ }
155+
156+ function readAllLikes (opts = {}) {
157+ return readAllSource({
158+ type: 'vote',
159+ makeFilter: blogIds => msg => {
160+ if (getAuthor(msg) === myKey) return false // exclude my likes
161+
162+ return blogIds.includes(getLikeRoot(msg)) // is about one of my blogs
163+ },
164+ opts
165+ })
166+ }
167+
168+ function readAllShares (opts = {}) {
169+ return readAllSource({
170+ type: 'share',
171+ makeFilter: (blogIds) => msg => {
172+ if (getAuthor(msg) === myKey) return false // exclude my shares
173+
174+ return blogIds.includes(getLikeRoot(msg)) // is about one of my blogs
175+ },
176+ opts
177+ })
178+ }
179+
180+ function readAllSource ({ type, makeFilter, opts = {} }) {
181+ var source = defer.source()
182+
183+ getBlogs({ keys: true, values: false }, (err, data) => {
184+ if (err) throw err
185+
186+ const blogIds = data.map(d => d[1])
187+
188+ opts.type = type
189+ var limit = opts.limit
190+ delete opts.limit
191+ // have to remove limit from the query otherwise Next stalls out if it doesn't get a new result
192+
193+ const _source = pull(
194+ server.messagesByType(opts),
195+ pull.filter(makeFilter(blogIds)),
196+ limit ? pull.take(limit) : true
197+ )
198+
199+ source.resolve(_source)
200+ })
201+
202+ return source
203+ }
204+
205+ function isMyMsg (msg) {
206+ return getAuthor(msg) === myKey
207+ }
208+ }
209+}
210+
211+function getBlogKey (blog) {
212+ if (isMsgRef(blog)) return blog
213+ // else if (isMsgRef(blog.key) && isBlog(blog)) return blog.key
214+ else if (isMsgRef(blog.key) && (isBlog(blog) || isPlog(blog))) return blog.key
215+}
216+
217+// a Plog is a Blog shaped Post!
218+function isPlog (msg) {
219+ // if (get(msg, 'value.content.text', '').length >= 2500) console.log(get(msg, 'value.content.text', '').length)
220+ return get(msg, 'value.content.text', '').length >= 2500
221+}

Built with git-ssb-web