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

201 lines
5.1 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
interceptors = []
use (fn) {
this.interceptors.push(fn)
}
/**
* 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()
for (const key in params) {
if (params[key] != null) {
urlParams.set(key, params[key])
}
}
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)
for (const fn of this.interceptors) {
config = fn(config)
}
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 err = new JsonException()
err.statusCode = request.status
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
} else {
err.message = request.statusText
}
throw err
}
} catch (e) {
data = null
error = e
}
if (error) {
this.emit('error', error)
reject(error)
} else {
resolve(data)
}
}
}