hedera-web/src/js/vn/json-connection.js

180 lines
4.3 KiB
JavaScript

import { VnObject } from './object'
import { JsonException } from './json-exception'
/**
* Handler for JSON rest connections.
*/
export class JsonConnection extends VnObject {
_connected = false
_requestsCount = 0
token = null
/**
* Executes the specified REST service with the given params and calls
* the callback when response is received.
*
* @param {String} url The service path
* @param {Object} params The params to pass to the service
* @return {Object} The parsed JSON response
*/
async send (url, params) {
if (!params) params = {}
params.srv = `json:${url}`
return this.sendWithUrl('POST', '.', params)
}
async sendForm (form) {
const params = {}
const elements = form.elements
for (let i = 0; i < elements.length; i++) {
if (elements[i].name) { params[elements[i].name] = elements[i].value }
}
return this.sendWithUrl('POST', form.action, params)
}
async sendFormMultipart (form) {
return this.request({
method: 'POST',
url: form.action,
data: new FormData(form)
})
}
async sendFormData (formData) {
return this.request({
method: 'POST',
url: '',
data: formData
})
}
/*
* Called when REST response is received.
*/
async sendWithUrl (method, url, params) {
const urlParams = new URLSearchParams(params)
return this.request({
method,
url,
data: urlParams.toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
}
async request (config) {
const request = new XMLHttpRequest()
request.open(config.method, config.url, true)
const token = localStorage.getItem('vnToken')
if (token) { request.setRequestHeader('Authorization', token) }
const headers = config.headers
if (headers) {
for (const header in headers) { request.setRequestHeader(header, headers[header]) }
}
const promise = new Promise((resolve, reject) => {
request.onreadystatechange =
() => this._onStateChange(request, resolve, reject)
})
request.send(config.data)
this._requestsCount++
if (this._requestsCount === 1) { this.emit('loading-changed', true) }
return promise
}
_onStateChange (request, resolve, reject) {
if (request.readyState !== 4) { return }
this._requestsCount--
if (this._requestsCount === 0) { this.emit('loading-changed', false) }
let data = null
let error = null
try {
if (request.status === 0) {
const err = new JsonException()
err.message = 'The server does not respond, please check your Internet connection'
err.statusCode = request.status
throw err
}
let contentType = null
try {
contentType = request
.getResponseHeader('Content-Type')
.split(';')[0]
.trim()
} catch (err) {
console.warn(err)
}
if (contentType !== 'application/json') {
const err = new JsonException()
err.message = request.statusText
err.statusCode = request.status
throw err
}
let json
let jsData
if (request.responseText) { json = JSON.parse(request.responseText) }
if (json) { jsData = json.data || json }
if (request.status >= 200 && request.status < 300) {
data = jsData
} else {
let exception = jsData.exception
const error = jsData.error
const err = new JsonException()
if (exception) {
exception = exception
.replace(/\\/g, '.')
.replace(/Exception$/, '')
.replace(/^Vn\.Web\./, '')
err.exception = exception
err.message = jsData.message
err.code = jsData.code
err.file = jsData.file
err.line = jsData.line
err.trace = jsData.trace
err.statusCode = request.status
} else if (error) {
err.message = error.message
err.code = error.code
err.statusCode = request.status
} else {
err.message = request.statusText
err.statusCode = request.status
}
throw err
}
} catch (e) {
data = null
error = e
}
if (error) {
if (error.exception === 'SessionExpired') { this.clearToken() }
this.emit('error', error)
reject(error)
} else { resolve(data) }
}
}