From 9d85c029f441092fcfdf5466d65a59151b2b63e5 Mon Sep 17 00:00:00 2001 From: fenwick67 Date: Fri, 2 Aug 2019 11:10:45 -0400 Subject: [PATCH] make promise chaining more sustainable --- lib/convertv2.js | 57 +++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/lib/convertv2.js b/lib/convertv2.js index 6388200..4e1ed1b 100644 --- a/lib/convertv2.js +++ b/lib/convertv2.js @@ -3,16 +3,25 @@ var fs = require('fs'); var template = ejs.compile(fs.readFileSync('./lib/template.ejs', 'utf8')); var timeAgo = require('timeago.js'); -// TODO try https://www.npmjs.com/package/request-promise-cache for the requests var request = require('request-promise-cache') const hour = 3600000; -// get JSON for an AP URL -// TODO make it reject on HTTP 4xx or 5xx +// get JSON for an AP URL, by either fetching it or grabbing it from a cache. + +// Honestly request-promise-cache should be good enough. Redis would be a nice upgrade but for +// a single process install it will be fine. + +// note: rejects on HTTP 4xx or 5xx async function apGet(url,ttl) { + return new Promise(function(resolve,reject){ + // fail early + if (!url){ + reject(new Error('URL is invalid')); + } + request( { uri:url, cacheKey:url, @@ -29,13 +38,24 @@ async function apGet(url,ttl) { } -// never rejects, instead it returns an object with a status, error and/or result. -async function apGetNoReject(...args){ - return new Promise(function(resolve,reject){ - apGet(...args) - .then(res=>resolve({status:true,result:res})) - .catch(e=>resolve({status:false,error:e})) - }); +// like Promise.all except returns null on error instead of failing all the promises +async function promiseSome(proms){ + + function noRejectWrap(prom){ + return new Promise(function(resolve,reject){ + + prom // it's already been called + .then(resolve) + .catch(e=>{ + // console.warn(e);// for debugging + resolve(null) + }) + + }) + } + + return await Promise.all(proms.map(noRejectWrap)) + } module.exports = async function (opts) { @@ -97,16 +117,15 @@ async function itemsForFeed(opts,user,feed) { var boostData = []; var boostUrls = feed.orderedItems.filter(i=>i.type=="Announce").map(i=>i.object); // console.log(boostUrls); - boostData = await Promise.all(boostUrls.map(apGetNoReject)); - boostData = boostData.map(d=>d.result||{}); + boostData = await promiseSome(boostUrls.map(apGet)); // now get user data for each of those - let userData = await Promise.all(boostData.map(d=>d.attributedTo||'').map(apGetNoReject)); + let userData = await promiseSome(boostData.map(d=>d?d.attributedTo||'':null).map(apGet)); - // put a ._userdata key on the item object if this is a boost etc + // put a ._userdata key on the item object if this is a boost for (var i = 0; i < boostData.length; i ++){ - if (userData[i].status){ - boostData[i]._userdata = userData[i].result; + if (userData[i] && boostData[i]){ + boostData[i]._userdata = userData[i]; } } @@ -116,8 +135,8 @@ async function itemsForFeed(opts,user,feed) { boostData.forEach((boostToot)=>{ - if (!boostToot.id){ - return;// case where it's a {} b/c the request failed or w/e + if (!boostToot){// failed request + return; } // inject in-place into items @@ -142,8 +161,6 @@ async function itemsForFeed(opts,user,feed) { return items.filter((item)=>{ - // this is temporary, don't handle boosts (TODO) - // return item.type == "Create" && item.object && item.object.type=="Note"; return typeof item.object == 'object';// handle weird cases }).map((item)=>{