get-posts-stateless All Flags Set to False
so i had asked in the DeSo Discord about if there was some kind of hardcoded limit to the amount of records that would get returned by get-posts-stateless. since it’s really for the feeds, i thought maybe it did have a limit, since who would ever scroll the feeds to the beginning of the blockchain? and it seemed like my code to retrieve the records was ending without getting all that many records. anyway- i’ve got the Discord chat here. and after that, i’ll include my updated code too, cause i’m pretty sure i had a problem with the code before.
DeSo Foundation Tech - DEVELOPERS > dev-support | Updated Kitty4D JavaScript
so, because i don’t want it to be hard to find any information, these seem to be the key takeaways. none of these things are documented anywhere so, hopefully this help someone else not have to ask these questions!
- get-posts-stateless, with none of the flags set to true, will return ALL posts if you keep paginating until you reach the end. in reverse chron order. this was my assumption, but it’s not stated anywhere.
- following feed is only computed for the past 2 days - i don’t believe this is documented.
- the feed by DESO goes only an hour back - this is documented.
- NumToFetch is not necessarily going to match the # of top-level post records you get back. i believe this is primarily due to reposts counting as additional posts in the response. it’s possible it’s also due to hidden posts, though i feel like that SHOULD be dealt with in the backend. but i don’t know for sure. either way don’t be shocked to get 35 records when you request 50.
- the deprecated fields like RecloutedPostEntryResponse and numeric counts for Reclouted/QuoteReclouted will contain the same data as the newer-named fields. the docs don’t mention the old fields in the response type documentation, it threw me off for a second.
- addGlobalFeedBool is documented as adding the isGlobal bool in the response, but it also controls the inHotFeed bool.
doing the call with none of the “feed flags” (GetPostsForFollowFeed, GetPostsForGlobalWhitelist, GetPostsByDESO) is the “get all posts ever” call. using any of the flags makes it into a much different call, because you cannot go forever with any of the 3 feeds.
when doing the “get all posts ever”, the default OrderBy is “newest” (reverse chron) - and i believe (this i have not confirmed 100% but it makes sense to me, while also not making total sense) - the pagination of posts only works in this order. and results ONLY come out in this order technically. if i fetch 50 posts at once, i’m getting those 50 posts in the reverse chron order based on where i set my starting point at - and any change of OrderBy is only done AFTER the fact. so, i can get the most recent 50 posts, and i can then order those 50 posts in “oldest” order, but you can’t simply do orderBy: oldest and fetch 50 posts with no postHashHex and get the absolute 50 first posts ever made on the blockchain. blame it on the linked list? i’ve tested this multiple times and i feel that this is correct but i have never done something like: grab 50 posts, set order by to oldest, then try to retrieve the next page of data using what is now the last element’s posthashhex in those results. i don’t think it would work though, at least not in the expected way (if your expectation is that the next page is going to be the next 50 NEWEST posts after that post, since ordering by oldest would cause that - i think it will be the 50 next oldest posts).
i also have not attempted to use OrderBy with any of the feeds. i don’t see why it wouldn’t work, but probably in the same fashion. will confirm this stuff eventually!
DeSo Foundation Tech - DEVELOPERS > dev-support
okay so here’s my current code that uses get-posts-stateless. i realized that the problem i was having before might have been that when i abstracted out my call for fetch to make a fetchCache function, i didn’t make that function async. i’m just learning the async stuff so, hopefully i’m doing it right now. i think i can download all records now if i let it, but i have a limit hardcoded in now.
also to note, i have a blacklistedUsers array, i’m not showing it since the public keys are for users whose data i don’t want to share.
so i had left this function out before actually. before i didn’t have it async with awaits. i dunno if i really need these on everything but like i said, seems to work so lol.
async function fetchCache(url, params) {
/* pseudoGetParams will be appended to the URL in order to maintain a cache per unique API call
otherwise, a call to get the number of followers for a user and a call to get the number of followings for a user will
be cached as a shared object, which is not the expected behavior.
i had expected the caching to take into account POST parameters the same way it does GET parameters, but
since it doesn't, this seems to be a working solution.
*/
const pseudoGetParams = params.body ? encodeURIComponent(params.body) : '';
let res = await Cache(url + '?' + pseudoGetParams, {
duration: "1d",
type: "json",
fetchOptions: params,
});
return await res;
}
i’ll show a bit more of the file now, with the class definition and stuff.
class DesoLite {
constructor({ apiurl = default_apiurl, pkey = '', userName = '' }) {
this.apiurl = apiurl;
this.pkey = pkey;
this.userName = userName;
}
async getPosts({ pk = this.pkey, postHashHex = null, orderBy = '', postContent = '', numToFetch = null, fetchSubComments = false, getPostsForFollowFeed = false, getPostsForGlobalWhitelist = false, getPostsByDESO = false, mediaRequired = false, postsByDESOMinutesLookback = null, addGlobalFeedBool = false }) {
let url = this.apiurl + 'get-posts-stateless';
try {
let res = await fetchCache(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
ReaderPublicKeyBase58Check: pk,
PostHashHex: postHashHex,
OrderBy: orderBy,
StartTstampSecs: null,
PostContent: postContent,
NumToFetch: numToFetch,
FetchSubcomments: fetchSubComments,
GetPostsForFollowFeed: getPostsForFollowFeed,
GetPostsForGlobalWhitelist: getPostsForGlobalWhitelist,
GetPostsByDESO: getPostsByDESO,
MediaRequired: mediaRequired,
PostsByDESOMinutesLookback: postsByDESOMinutesLookback,
AddGlobalFeedBool: addGlobalFeedBool
})
});
return await res;
} catch (error) {
console.log(error);
}
return null;
}
async getFrom(method, params = {}) {
let res;
switch (method) {
case 'get-posts':
/* for Posts, pass:
pk: reader's public key,
postHashHex: for paging, send last received post hash,
orderBy: newest|oldest|last_comment,
postContent: only return posts whose (body only?) matches the text,
numToFetch: non-zero,
fetchSubComments: return 1 level deep of comments? haven't tested yet,
getPostsForFollowFeed: follow feed for reader's pk,
getPostsForGlobalWhitelist: global posts, i guess this is node-agnostic?,
getPostsByDESO: kinda basically the hot feed i guess,
mediaRequired: false, or true but would be nice to specify image and/or video
postsByDESOMinutesLookback: must be <= 60, and only when doing getPostsByDESO - dunno why it doesn't work for all.. ,
addGlobalFeedBool: posts will contain a bool (but i kinda thought they already had an IsGlobal..?)
*/
try {
const batch = await this.getPosts({ pk: params.readerPk ? params.readerPk : undefined, postHashHex: params.postHashHex ? params.postHashHex : undefined, orderBy: params.orderBy ? params.orderBy : undefined, postContent: params.postContent ? params.postContent : undefined, numToFetch: params.numToFetch ? params.numToFetch : 10, mediaRequired: params.mediaRequired ? params.mediaRequired : false });
res = batch.PostsFound.filter(item => !blacklistedUsers.includes(item.PosterPublicKeyBase58Check));
} catch (error) {
res = [];
}
break;
case 'get-posts-all':
/* for Posts, pass:
pk: reader's public key,
postHashHex: for paging, send last received post hash,
orderBy: newest|oldest|last_comment,
postContent: only return posts whose (body only?) matches the text,
numToFetch: non-zero,
fetchSubComments: return 1 level deep of comments? haven't tested yet,
getPostsForFollowFeed: follow feed for reader's pk,
getPostsForGlobalWhitelist: global posts, i guess this is node-agnostic?,
getPostsByDESO: kinda basically the hot feed i guess,
mediaRequired: false, or true but would be nice to specify image and/or video
postsByDESOMinutesLookback: must be <= 60, and only when doing getPostsByDESO - dunno why it doesn't work for all.. ,
addGlobalFeedBool: posts will contain a bool (but i kinda thought they already had an IsGlobal..?)
*/
try {
let batch = null;
let results = [];
let ct = 0;
let lastPostHash = params.postHashHex ? params.postHashHex : undefined;
while (ct < 300 && (batch === null || batch.length)) {
ct++;
batch = await this.getPosts({ pk: params.readerPk ? params.readerPk : undefined, postHashHex: lastPostHash, orderBy: params.orderBy ? params.orderBy : undefined, postContent: params.postContent ? params.postContent : undefined, numToFetch: params.numToFetch ? params.numToFetch : 50, mediaRequired: params.mediaRequired ? params.mediaRequired : false });
batch = batch.PostsFound;
if (batch.length) {
const filteredBatch = batch.filter(item => !blacklistedUsers.includes(item.PosterPublicKeyBase58Check));
lastPostHash = '';
if (filteredBatch.length) {
results.push(...filteredBatch);
}
lastPostHash = batch[batch.length - 1].PostHashHex;
}
}
if (fs) {
fs.writeFile('./src/scripts/dataStore/' + lastPostHash + '.json', JSON.stringify(results), (err) => {
if (err) { console.error(err); return; };
console.log("File has been created");
});
}
res = results;
} catch (error) {
console.log(error);
res = [];
}
break;
}
return res;
}
}
module.exports = DesoLite;
and then with the way 11ty.js works, here’s my call to it
const DesoLite = require('../scripts/desolite.js');
module.exports = function() {
const desolite = new DesoLite({
pkey: '',
userName: 'kitty4d'
});
return desolite.getFrom('get-posts-all', {});
};
it’s just that easy~