'use strict'; const needle = require('needle'); const mylog = require('./mylog'); const config = require('./config'); const delay = () => new Promise(r => setTimeout(r, 2000 + Math.random() * 2000)); const maxattempts = 10; async function fetch(uri, meth, data, opts, ...rest) { if(uri.startsWith('/')) uri = config.root.trimEnd('/') + uri; meth = meth || 'get'; opts = opts || {}; opts.headers = opts.headers || {}; opts.headers.Authorization = `Bearer ${config.token}`; opts.headers.Referer = uri; opts.open_timeout = config.timeout * 1000; opts.read_timeout = config.timeout * 1000; opts.response_timeout = config.timeout * 1000; if(!opts.hasOwnProperty('follow_max')) opts.follow_max = 10; for(let attempt = 1; attempt <= maxattempts; attempt++) try { mylog(`# ${meth} ${uri}`); const resp = await needle(meth, uri, data, opts, ...rest); if(!/^[23]\d\d/.test(resp.statusCode.toString())) { const failure = { method: meth, uri, data, statusCode: resp.statusCode, statusMessage: resp.statusMessage, body: resp.body }; throw (Object.assign(new Error(JSON.stringify(failure)), failure)); } return resp; } catch (err) { if(attempt === maxattempts || err.statusCode && !/^(?:429|5\d\d)$/.test(err.statusCode.toString()) || !err.statusCode && !/remote end closed socket/i.test(err.message)) throw err; await delay(); } } module.exports = fetch;