river-of-ebooks/assets/js/lib/Ajax.js

175 lines
5.3 KiB
JavaScript
Raw Normal View History

2018-10-29 23:23:46 +00:00
/* global XMLHttpRequest FormData */
2018-11-07 20:06:36 +00:00
'use strict'
2018-10-29 23:23:46 +00:00
2018-11-07 20:06:36 +00:00
let ajaxcfg = {}
2018-10-29 23:23:46 +00:00
class AjaxError extends Error {
constructor (reason, data, xhr) {
2018-11-07 20:06:36 +00:00
super(reason)
this.data = data
this.xhr = xhr
2018-10-29 23:23:46 +00:00
}
}
export default class Ajax {
static async get (opts) {
2018-11-12 22:12:16 +00:00
if (!opts) opts = {}
opts.method = 'get'
return Ajax.ajax(opts)
2018-10-29 23:23:46 +00:00
}
static async post (opts) {
2018-11-12 22:12:16 +00:00
if (!opts) opts = {}
opts.method = 'post'
return Ajax.ajax(opts)
2018-10-29 23:23:46 +00:00
}
static async put (opts) {
2018-11-12 22:12:16 +00:00
if (!opts) opts = {}
opts.method = 'put'
return Ajax.ajax(opts)
2018-10-29 23:23:46 +00:00
}
static async patch (opts) {
2018-11-12 22:12:16 +00:00
if (!opts) opts = {}
opts.method = 'patch'
return Ajax.ajax(opts)
2018-10-29 23:23:46 +00:00
}
static async delete (opts) {
2018-11-12 22:12:16 +00:00
if (!opts) opts = {}
opts.method = 'delete'
return Ajax.ajax(opts)
2018-10-29 23:23:46 +00:00
}
static async head (opts) {
2018-11-12 22:12:16 +00:00
if (!opts) opts = {}
opts.method = 'head'
return Ajax.ajax(opts)
2018-10-29 23:23:46 +00:00
}
static async options (opts) {
2018-11-12 22:12:16 +00:00
if (!opts) opts = {}
opts.method = 'options'
return Ajax.ajax(opts)
2018-10-29 23:23:46 +00:00
}
static ajax (opts) {
return new Promise((resolve, reject) => {
2018-11-12 22:12:16 +00:00
if (!opts) reject(new Error('Missing required options parameter.'))
2018-10-29 23:23:46 +00:00
if (opts.method) {
2018-11-12 22:12:16 +00:00
if (!['get', 'post', 'put', 'patch', 'delete', 'head', 'options'].includes(opts.method.toLowerCase())) reject(new Error('opts.method must be one of: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS.'))
2018-11-07 20:06:36 +00:00
opts.method = opts.method.toUpperCase()
2018-10-29 23:23:46 +00:00
}
2018-11-07 20:06:36 +00:00
var xhr = opts.xhr || new XMLHttpRequest()
2018-10-29 23:23:46 +00:00
2018-11-07 20:06:36 +00:00
var fd = null
var qs = ''
2019-02-26 03:29:18 +00:00
if (!opts.noProcess && opts.data && opts.method.toLowerCase() !== 'get') {
2018-11-07 20:06:36 +00:00
fd = new FormData()
2018-10-29 23:23:46 +00:00
for (let key in opts.data) {
2018-11-07 20:06:36 +00:00
fd.append(key, opts.data[key])
2018-10-29 23:23:46 +00:00
}
2019-02-26 03:29:18 +00:00
} else if (!opts.noProcess && opts.data) {
2018-11-07 20:06:36 +00:00
qs += '?'
let params = []
2018-10-29 23:23:46 +00:00
for (let key in opts.data) {
2018-11-07 20:06:36 +00:00
params.push([key, opts.data[key]].join('='))
2018-10-29 23:23:46 +00:00
}
2018-11-07 20:06:36 +00:00
qs += params.join('&')
2018-10-29 23:23:46 +00:00
}
2019-02-26 03:29:18 +00:00
if (opts.noProcess) {
opts.headers = {
'Content-Type': 'application/json',
...opts.headers
}
try { fd = JSON.stringify(opts.data) } catch (e) { console.warn(e) }
}
2018-10-29 23:23:46 +00:00
xhr.onload = () => {
2018-11-15 23:28:11 +00:00
if (!('' + xhr.status).startsWith('2')) { return xhr.onerror() }
2018-11-07 20:06:36 +00:00
var data = xhr.response
try {
data = JSON.parse(data)
} catch (e) {}
2018-10-29 23:23:46 +00:00
resolve({
data,
xhr
2018-11-07 20:06:36 +00:00
})
}
2018-10-29 23:23:46 +00:00
xhr.onerror = () => {
2018-11-07 20:06:36 +00:00
var data = xhr.response
try { data = JSON.parse(data) } catch (e) {}
2018-10-29 23:23:46 +00:00
// method not allowed
if (xhr.status === 405) {
reject(new AjaxError('405 Method Not Allowed', data.error || data, xhr))
2018-11-07 20:06:36 +00:00
return
2018-10-29 23:35:27 +00:00
} else if (xhr.status === 404) {
reject(new AjaxError('404 Not Found', data.error || data, xhr))
2018-11-07 20:06:36 +00:00
return
2018-10-29 23:23:46 +00:00
}
try {
// if the access token is invalid, try to use the refresh token
var json = data
2018-10-29 23:23:46 +00:00
if (json.error === 'access_denied' && json.hint.includes('token') && json.hint.includes('invalid') && ajaxcfg.refresh_token) {
2018-11-07 20:06:36 +00:00
return Ajax.refresh(opts)
2018-10-29 23:23:46 +00:00
} else if (json.error === 'access_denied' && json.hint.includes('token') && json.hint.includes('revoked')) {
2018-11-07 20:06:36 +00:00
reject(new AjaxError('token revoked', data, xhr))
2018-10-29 23:23:46 +00:00
}
} catch (e) {
reject(new AjaxError(e.toString(), data.error || data, xhr))
2018-10-29 23:23:46 +00:00
} finally {
reject(new AjaxError(data.error || data, xhr.status, xhr))
2018-10-29 23:23:46 +00:00
}
2018-11-07 20:06:36 +00:00
}
2018-10-29 23:23:46 +00:00
2018-11-07 20:06:36 +00:00
xhr.open(opts.method || 'GET', opts.url + qs || window.location.href)
2018-10-29 23:23:46 +00:00
if (opts.headers) {
2018-11-12 22:12:16 +00:00
for (let key in opts.headers) xhr.setRequestHeader(key, opts.headers[key])
2018-10-29 23:23:46 +00:00
}
2018-11-12 22:12:16 +00:00
if (ajaxcfg.access_token && !(opts.headers || {}).Authorization) xhr.setRequestHeader('Authorization', 'Bearer ' + ajaxcfg.access_token)
2018-11-07 20:06:36 +00:00
xhr.send(fd)
})
2018-10-29 23:23:46 +00:00
}
static refresh (opts) {
return new Promise((resolve, reject) => {
2018-11-07 20:06:36 +00:00
var xhr = new XMLHttpRequest()
2018-10-29 23:23:46 +00:00
2018-11-07 20:06:36 +00:00
var fd = new FormData()
2018-10-29 23:23:46 +00:00
const OAUTH_TOKEN_REQUEST = {
grant_type: 'refresh_token',
refresh_token: ajaxcfg.refresh_token,
client_id: 'foxfile',
client_secret: 1
2018-11-07 20:06:36 +00:00
}
2018-10-29 23:23:46 +00:00
for (var key in OAUTH_TOKEN_REQUEST) {
2018-11-07 20:06:36 +00:00
fd.append(key, OAUTH_TOKEN_REQUEST[key])
2018-10-29 23:23:46 +00:00
}
// try original request
xhr.onload = () => {
2018-11-12 22:12:16 +00:00
if (xhr.status !== 200) return xhr.onerror()
if (ajaxcfg.refresh) ajaxcfg.refresh(xhr.response)
2018-11-07 20:06:36 +00:00
var json = JSON.parse(xhr.response)
ajaxcfg.access_token = json.access_token
ajaxcfg.refresh_token = json.refresh_token
return Ajax.ajax(opts)
}
2018-10-29 23:23:46 +00:00
// if this fails, dont try again
xhr.onerror = () => {
2018-11-07 20:06:36 +00:00
var data = xhr.response
reject(new AjaxError(xhr.status, data, xhr))
}
xhr.open('POST', ajaxcfg.refresh_url)
xhr.send(fd)
})
2018-10-29 23:23:46 +00:00
}
static setTokenData (tokens) {
2018-11-12 22:12:16 +00:00
if (!tokens) throw new Error('Missing tokens.')
if (!tokens.access_token && !tokens.refresh_token && !tokens.refresh_url) throw new Error('Missing at least one of: access_token, refresh_token, refresh_url.')
if (tokens.access_token) ajaxcfg.access_token = tokens.access_token
if (tokens.refresh_token) ajaxcfg.refresh_token = tokens.refresh_token
if (tokens.refresh_url) ajaxcfg.refresh_url = tokens.refresh_url
2018-11-07 20:06:36 +00:00
return true
2018-10-29 23:23:46 +00:00
}
static onRefresh (func) {
2018-11-07 20:06:36 +00:00
ajaxcfg.refresh = func
2018-10-29 23:23:46 +00:00
}
}