quip-export
Version:
Export all folders and documents from Quip
169 lines (142 loc) • 4.98 kB
JavaScript
const fetch = require('node-fetch');
const LoggerAdapter = require('./common/LoggerAdapter');
const TIMES_LIMIT_503 = 10;
class QuipService {
constructor(accessToken, apiURL='https://platform.quip.com:443/1') {
this.accessToken = accessToken;
this.apiURL = apiURL;
this.logger = new LoggerAdapter();
this.querries503 = new Map();
this.waitingMs = 1000;
this.stats = {
query_count: 0,
getThread_count: 0,
getThreads_count: 0,
getFolder_count: 0,
getFolders_count: 0,
getBlob_count: 0,
getPdf_count: 0,
getXlsx_count: 0,
getDocx_count: 0,
getCurrentUser_count: 0,
getThreadMessages_count: 0,
getUser_count: 0
};
}
setLogger(logger) {
this.logger = logger;
}
async checkUser() {
this.stats.getCurrentUser_count++;
const res = await fetch(`${this.apiURL}/users/current`, this._getOptions('GET'));
if(res.ok) return true;
return false;
}
async getUser(userIds) {
this.stats.getUser_count++;
return this._apiCallJson(`/users/${userIds}`);
}
async getCurrentUser() {
this.stats.getCurrentUser_count++;
return this._apiCallJson('/users/current');
}
async getFolder(folderId) {
this.stats.getFolder_count++;
return this._apiCallJson(`/folders/${folderId}`);
}
async getThread(threadId) {
this.stats.getThread_count++;
return this._apiCallJson(`/threads/${threadId}`);
}
async getThreadMessages(threadId) {
this.stats.getThreadMessages_count++;
return this._apiCallJson(`/messages/${threadId}`);
}
async getThreads(threadIds) {
this.stats.getThreads_count++;
return this._apiCallJson(`/threads/?ids=${threadIds}`);
}
async getFolders(threadIds) {
this.stats.getFolders_count++;
return this._apiCallJson(`/folders/?ids=${threadIds}`);
}
async getBlob(threadId, blobId) {
//const random = (Math.random() > 0.8) ? 'random' : '';
this.stats.getBlob_count++;
return this._apiCallBlob(`/blob/${threadId}/${blobId}`);
}
async getPdf(threadId) {
this.stats.getPdf_count++;
return this._apiCallBlob(`/threads/${threadId}/export/pdf`);
}
async getDocx(threadId) {
this.stats.getDocx_count++;
return this._apiCallBlob(`/threads/${threadId}/export/docx`);
}
async getXlsx(threadId) {
this.stats.getXlsx_count++;
return this._apiCallBlob(`/threads/${threadId}/export/xlsx`);
}
async _apiCallBlob(url, method = 'GET') {
return this._apiCall(url, method, true);
}
async _apiCallJson(url, method = 'GET') {
return this._apiCall(url, method, false);
}
async _apiCall(url, method, blob) {
this.stats.query_count++;
try {
const res = await fetch(`${this.apiURL}${url}`, this._getOptions(method));
if(!res.ok) {
if(res.status === 503) {
const currentTime = new Date().getTime();
const rateLimitReset = +res.headers.get('x-ratelimit-reset')*1000;
let waitingInMs = this.waitingMs;
if(rateLimitReset > currentTime) {
waitingInMs = rateLimitReset - currentTime;
}
this.logger.debug(`HTTP 503: for ${url}, waiting in ms: ${waitingInMs}`);
if(this._check503Query(url)) {
return new Promise(resolve => setTimeout(() => {
resolve(this._apiCall(url, method, blob));
}, waitingInMs));
} else {
this.logger.error(`Couldn't fetch ${url}, tryed to get it ${TIMES_LIMIT_503} times`);
return;
}
} else {
this.logger.debug(`Couldn't fetch ${url}, received ${res.status}`);
return;
}
}
if(blob) {
return res.blob();
} else {
return res.json();
}
} catch (e) {
this.logger.error(`Couldn't fetch ${url}, `, e);
}
}
_check503Query(url) {
let count = this.querries503.get(url);
if(!count) {
count = 0;
}
this.querries503.set(url, ++count);
if(count > TIMES_LIMIT_503) {
return false;
}
return true;
}
_getOptions(method) {
return {
method: method,
headers: {
'Authorization': 'Bearer ' + this.accessToken,
'Content-Type': 'application/json'
}
};
}
}
module.exports = QuipService;