diff --git a/services/gunDB/contact-api/getters/feed.js b/services/gunDB/contact-api/getters/feed.js new file mode 100644 index 00000000..0d7a9a72 --- /dev/null +++ b/services/gunDB/contact-api/getters/feed.js @@ -0,0 +1,64 @@ +/** + * @format + */ +const Common = require('shock-common') +const isFinite = require('lodash/isFinite') +const shuffle = require('lodash/shuffle') +const R = require('ramda') + +const Follows = require('./follows') +const Wall = require('./wall') + +/** + * @param {number} page + * @throws {TypeError} + * @throws {RangeError} + * @returns {Promise} + */ +const getFeedPage = async page => { + if (!isFinite(page)) { + throw new TypeError(`Please provide an actual number for [page]`) + } + + if (page <= 0) { + throw new RangeError(`Please provide only positive numbers for [page]`) + } + + const subbedPublicKeys = Object.values(await Follows.currentFollows()).map( + f => f.user + ) + + if (subbedPublicKeys.length === 0) { + return [] + } + + // say there are 20 public keys total + // page 1: page 1 from first 10 public keys + // page 2: page 1 from second 10 public keys + // page 3: page 2 from first 10 public keys + // page 4: page 2 from first 10 public keys + // etc + + const pagedPublicKeys = R.splitEvery(10, shuffle(subbedPublicKeys)) + + if (pagedPublicKeys.length === 1) { + const [publicKeys] = pagedPublicKeys + + const fetchedPages = await Promise.all( + publicKeys.map(pk => Wall.getWallPage(page, pk)) + ) + + const allPosts = fetchedPages.map(fp => Object.values(fp.posts)) + const posts = R.flatten(allPosts) + // @ts-ignore + const sorted = R.sortBy((a, b) => b.date - a.date, posts) + + return sorted + } + + return [] +} + +module.exports = { + getFeedPage +} diff --git a/services/gunDB/contact-api/getters/index.js b/services/gunDB/contact-api/getters/index.js index 2bb192fb..a21048c9 100644 --- a/services/gunDB/contact-api/getters/index.js +++ b/services/gunDB/contact-api/getters/index.js @@ -7,6 +7,7 @@ const Key = require('../key') const Utils = require('../utils') const Wall = require('./wall') +const Feed = require('./feed') /** * @param {string} pub @@ -94,3 +95,5 @@ module.exports.Follows = require('./follows') module.exports.getWallPage = Wall.getWallPage module.exports.getWallTotalPages = Wall.getWallTotalPages + +module.exports.getFeedPage = Feed.getFeedPage diff --git a/src/routes.js b/src/routes.js index 199f4346..0b82f7e5 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1971,6 +1971,48 @@ module.exports = async ( ap.put(`/api/gun/follows/:publicKey`,apiGunFollowsPut) ap.delete(`/api/gun/follows/:publicKey`, apiGunFollowsDelete) + /** + * @type {RequestHandler<{}>} + */ + const apiGunFeedGet = async (req, res) => { + try { + const { page } = req.query; + + if (!isFinite(page)) { + return res.json(401).json({ + field: page, + errorMessage: 'page must be a number' + }) + } + + if (!isFinite(page)) { + return res.json(400).json({ + field: page, + errorMessage: 'page must be a number' + }) + } + + if (page < 1) { + return res.json(400).json({ + field: page, + errorMessage: 'page must be a positive number' + }) + } + + + + return res.status(200).json({ + posts: await GunGetters.getFeedPage(page) + }) + } catch (err) { + return res.status(500).json({ + errorMessage: err.message || 'Unknown error inside /api/gun/follows/' + }) + } + } + + ap.get(`/api/gun/feed`, apiGunFeedGet) + /** * Return app so that it can be used by express. */