mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-06 15:52:47 +00:00
594 lines
15 KiB
JavaScript
Executable File
594 lines
15 KiB
JavaScript
Executable File
// Use strict
|
|
"use strict";
|
|
|
|
|
|
// Classes
|
|
|
|
// JSON-RPC class
|
|
class JsonRpc {
|
|
|
|
// Public
|
|
|
|
// Send request
|
|
static sendRequest(urlOrUrls, method, parameters = [], headers = {}, numberOfAttempts = JsonRpc.DEFAULT_NUMBER_OF_ATTEMPTS, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Set current attempt
|
|
var currentAttempt = new Promise(function(resolve, reject) {
|
|
|
|
// Resolve invalid response
|
|
resolve(JsonRpc.INVALID_RESPONSE);
|
|
});
|
|
|
|
// Initiaize attempts
|
|
var attempts = [currentAttempt];
|
|
|
|
// Go through all attempts or URLs
|
|
for(let i = 0; i < Math.max(numberOfAttempts, (Array.isArray(urlOrUrls) === true) ? urlOrUrls["length"] : [urlOrUrls]["length"]); ++i) {
|
|
|
|
// Set attempt that runs after the current attempt
|
|
currentAttempt = currentAttempt.then(function(response) {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if response isn't invalid
|
|
if(response !== JsonRpc.INVALID_RESPONSE) {
|
|
|
|
// Resolve response
|
|
resolve(response);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Get current URL
|
|
var currentUrl = (Array.isArray(urlOrUrls) === true) ? urlOrUrls[i % urlOrUrls["length"]] : urlOrUrls;
|
|
|
|
// Return sending data
|
|
return JsonRpc.sendData(currentUrl, method, parameters, headers, JsonRpc.DEFAULT_ID, cancelOccurred).then(function(currentResponse) {
|
|
|
|
// Resolve current response
|
|
resolve(currentResponse);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check if at the last attempt, the error's response had an ok, bad request, unauthorized, forbidden, not found, unsupported media type, or payload too large status, or the response is a JSON-RPC error
|
|
if(i === Math.max(numberOfAttempts, (Array.isArray(urlOrUrls) === true) ? urlOrUrls["length"] : [urlOrUrls]["length"]) - 1 || error === Common.HTTP_OK_STATUS || error === Common.HTTP_BAD_REQUEST_STATUS || error === Common.HTTP_UNAUTHORIZED_STATUS || error === Common.HTTP_FORBIDDEN_STATUS || error === Common.HTTP_NOT_FOUND_STATUS || error === Common.HTTP_UNSUPPORTED_MEDIA_TYPE_STATUS || error === Common.HTTP_PAYLOAD_TOO_LARGE_STATUS || Object.isObject(error) === true) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Resolve invalid response
|
|
resolve(JsonRpc.INVALID_RESPONSE);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
});
|
|
|
|
// Append current attempt to list
|
|
attempts.push(currentAttempt);
|
|
}
|
|
|
|
// Return trying all attempts
|
|
return Promise.all(attempts).then(function(responses) {
|
|
|
|
// Resolve response
|
|
resolve(responses[responses["length"] - 1]);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Send notification
|
|
static sendNotification(urlOrUrls, method, parameters = [], headers = {}, numberOfAttempts = JsonRpc.DEFAULT_NUMBER_OF_ATTEMPTS, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Set current attempt
|
|
var currentAttempt = new Promise(function(resolve, reject) {
|
|
|
|
// Resolve invalid response
|
|
resolve(JsonRpc.INVALID_RESPONSE);
|
|
});
|
|
|
|
// Initiaize attempts
|
|
var attempts = [currentAttempt];
|
|
|
|
// Go through all attempts or URLs
|
|
for(let i = 0; i < Math.max(numberOfAttempts, (Array.isArray(urlOrUrls) === true) ? urlOrUrls["length"] : [urlOrUrls]["length"]); ++i) {
|
|
|
|
// Set attempt that runs after the current attempt
|
|
currentAttempt = currentAttempt.then(function(response) {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if response isn't invalid
|
|
if(response !== JsonRpc.INVALID_RESPONSE) {
|
|
|
|
// Resolve response
|
|
resolve(response);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Get current URL
|
|
var currentUrl = (Array.isArray(urlOrUrls) === true) ? urlOrUrls[i % urlOrUrls["length"]] : urlOrUrls;
|
|
|
|
// Return sending data
|
|
return JsonRpc.sendData(currentUrl, method, parameters, headers, JsonRpc.NO_ID, cancelOccurred).then(function(currentResponse) {
|
|
|
|
// Resolve current response
|
|
resolve(currentResponse);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Check if at the last attempt, the error's response had an ok, bad request, unauthorized, forbidden, not found, unsupported media type, or payload too large status, or the response is a JSON-RPC error
|
|
if(i === Math.max(numberOfAttempts, (Array.isArray(urlOrUrls) === true) ? urlOrUrls["length"] : [urlOrUrls]["length"]) - 1 || error === Common.HTTP_OK_STATUS || error === Common.HTTP_BAD_REQUEST_STATUS || error === Common.HTTP_UNAUTHORIZED_STATUS || error === Common.HTTP_FORBIDDEN_STATUS || error === Common.HTTP_NOT_FOUND_STATUS || error === Common.HTTP_UNSUPPORTED_MEDIA_TYPE_STATUS || error === Common.HTTP_PAYLOAD_TOO_LARGE_STATUS || Object.isObject(error) === true) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Resolve invalid response
|
|
resolve(JsonRpc.INVALID_RESPONSE);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
});
|
|
|
|
// Append current attempt to list
|
|
attempts.push(currentAttempt);
|
|
}
|
|
|
|
// Return trying all attempts
|
|
return Promise.all(attempts).then(function(responses) {
|
|
|
|
// Resolve response
|
|
resolve(responses[responses["length"] - 1]);
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Reject error
|
|
reject(error);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Create response
|
|
static createResponse(response, requestOrNotification, isError = false) {
|
|
|
|
// Check if a request is provided
|
|
if(Object.isObject(requestOrNotification) === true && "id" in requestOrNotification === true) {
|
|
|
|
// Check if not error
|
|
if(isError === false) {
|
|
|
|
// Return response
|
|
return {
|
|
|
|
// Version
|
|
"jsonrpc": JsonRpc.VERSION,
|
|
|
|
// ID
|
|
"id": requestOrNotification["id"],
|
|
|
|
// Result
|
|
"result": response
|
|
};
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return response
|
|
return {
|
|
|
|
// Version
|
|
"jsonrpc": JsonRpc.VERSION,
|
|
|
|
// ID
|
|
"id": requestOrNotification["id"],
|
|
|
|
// Error
|
|
"error": response
|
|
};
|
|
}
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Return no response
|
|
return JsonRpc.NO_RESPONSE;
|
|
}
|
|
}
|
|
|
|
// Create error response
|
|
static createErrorResponse(error, requestOrNotification, message = JsonRpc.DEFAULT_MESSAGE) {
|
|
|
|
// Check if message is default message
|
|
if(message === JsonRpc.DEFAULT_MESSAGE) {
|
|
|
|
// Check error
|
|
switch(error) {
|
|
|
|
// Invalid request error
|
|
case JsonRpc.INVALID_REQUEST_ERROR:
|
|
|
|
// Set message
|
|
message = Language.getDefaultTranslation('Invalid request');
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Method not found error
|
|
case JsonRpc.METHOD_NOT_FOUND_ERROR:
|
|
|
|
// Set message
|
|
message = Language.getDefaultTranslation('Method not found');
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Invalid parameters error
|
|
case JsonRpc.INVALID_PARAMETERS_ERROR:
|
|
|
|
// Set message
|
|
message = Language.getDefaultTranslation('Invalid parameters');
|
|
|
|
// Break
|
|
break;
|
|
|
|
// Internal error error
|
|
case JsonRpc.INTERNAL_ERROR_ERROR:
|
|
|
|
// Set message
|
|
message = Language.getDefaultTranslation('Internal error');
|
|
|
|
// Break
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Return create response
|
|
return JsonRpc.createResponse({
|
|
|
|
// Code
|
|
"code": error,
|
|
|
|
// Message
|
|
"message": message
|
|
|
|
}, requestOrNotification, true);
|
|
}
|
|
|
|
// Is request
|
|
static isRequest(data) {
|
|
|
|
// Return if data is a request
|
|
return Object.isObject(data) === true && "jsonrpc" in data === true && data["jsonrpc"] === JsonRpc.VERSION && "id" in data === true && data["id"] instanceof BigNumber === true && data["id"].isInteger() === true && data["id"].isPositive() === true && "method" in data === true && "params" in data === true;
|
|
}
|
|
|
|
// Is notification
|
|
static isNotification(data) {
|
|
|
|
// Return if data is a notification
|
|
return Object.isObject(data) === true && "jsonrpc" in data === true && data["jsonrpc"] === JsonRpc.VERSION && "id" in data === false && "method" in data === true && "params" in data === true;
|
|
}
|
|
|
|
// Is error response
|
|
static isErrorResponse(response) {
|
|
|
|
// Return if response is an error
|
|
return Object.isObject(response) === true && "jsonrpc" in response === true && response["jsonrpc"] === JsonRpc.VERSION && "id" in response === true && response["id"] instanceof BigNumber === true && response["id"].isInteger() === true && response["id"].isPositive() === true && "error" in response === true && Object.isObject(response["error"]) === true && "code" in response["error"] === true;
|
|
}
|
|
|
|
// No response
|
|
static get NO_RESPONSE() {
|
|
|
|
// Return no response
|
|
return null;
|
|
}
|
|
|
|
// Invalid request error
|
|
static get INVALID_REQUEST_ERROR() {
|
|
|
|
// Return invalid request error
|
|
return -32600;
|
|
}
|
|
|
|
// Method not found error
|
|
static get METHOD_NOT_FOUND_ERROR() {
|
|
|
|
// Return method not found error
|
|
return -32601;
|
|
}
|
|
|
|
// Invalid parameters error
|
|
static get INVALID_PARAMETERS_ERROR() {
|
|
|
|
// Return invalid parameters error
|
|
return -32602;
|
|
}
|
|
|
|
// Internal error error
|
|
static get INTERNAL_ERROR_ERROR() {
|
|
|
|
// Return internal error error
|
|
return -32603;
|
|
}
|
|
|
|
// Default message
|
|
static get DEFAULT_MESSAGE() {
|
|
|
|
// Return default message
|
|
return null;
|
|
}
|
|
|
|
// Private
|
|
|
|
// Send data
|
|
static sendData(url, method, parameters, headers, id, cancelOccurred = Common.NO_CANCEL_OCCURRED) {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if cancel didn't occur
|
|
if(cancelOccurred === Common.NO_CANCEL_OCCURRED || cancelOccurred() === false) {
|
|
|
|
// Set data
|
|
var data = {
|
|
|
|
// Version
|
|
"jsonrpc": JsonRpc.VERSION,
|
|
|
|
// Method
|
|
"method": method,
|
|
|
|
// Parameters
|
|
"params": parameters
|
|
};
|
|
|
|
// Check if an ID is provided
|
|
if(id !== JsonRpc.NO_ID)
|
|
|
|
// Set data's ID
|
|
data["id"] = id;
|
|
|
|
// Get AJAX request
|
|
var ajaxRequest = $.ajax(url, {
|
|
|
|
// Data
|
|
"data": JSONBigNumber.stringify(data),
|
|
|
|
// Content type
|
|
"contentType": "application/json",
|
|
|
|
// Data type
|
|
"dataType": "text",
|
|
|
|
// Type
|
|
"type": "POST",
|
|
|
|
// Headers
|
|
"headers": headers
|
|
});
|
|
|
|
// Initialize cancel allowed
|
|
var cancelAllowed = true;
|
|
|
|
// Abort if canceled
|
|
var abortIfCanceled = function() {
|
|
|
|
// Check if cancel is allowed
|
|
if(cancelAllowed === true) {
|
|
|
|
// Check if cancel occurred
|
|
if(cancelOccurred !== Common.NO_CANCEL_OCCURRED && cancelOccurred() === true) {
|
|
|
|
// Abort AJAX request
|
|
ajaxRequest.abort();
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Set timeout
|
|
setTimeout(function() {
|
|
|
|
// Abort if canceled
|
|
abortIfCanceled();
|
|
|
|
}, JsonRpc.AJAX_REQUEST_CANCELED_CHECK_INTERVAL_MILLISECONDS);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Abort if canceled
|
|
abortIfCanceled();
|
|
|
|
// Return sending AJAX request
|
|
return ajaxRequest.then(function(response, status, request) {
|
|
|
|
// Clear cancel allowed
|
|
cancelAllowed = false;
|
|
|
|
// Check if a response was expected
|
|
if(id !== JsonRpc.NO_ID) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Parse response as JSON
|
|
response = JSONBigNumber.parse(response);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Reject request's status
|
|
reject(request["status"]);
|
|
|
|
// Return
|
|
return;
|
|
}
|
|
|
|
// Check if response is invalid
|
|
if(Object.isObject(response) === false)
|
|
|
|
// Reject request's status
|
|
reject(request["status"]);
|
|
|
|
// Otherwise check if response contains an invalid version
|
|
else if("jsonrpc" in response === false || response["jsonrpc"] !== JsonRpc.VERSION)
|
|
|
|
// Reject request's status
|
|
reject(request["status"]);
|
|
|
|
// Otherwise check if response contains an invalid ID
|
|
else if("id" in response === false || response["id"] instanceof BigNumber === false || response["id"].isInteger() === false || response["id"].isPositive() === false)
|
|
|
|
// Reject request's status
|
|
reject(request["status"]);
|
|
|
|
// Otherwise check if response contains an invalid result
|
|
else if("error" in response === true || "result" in response === false)
|
|
|
|
// Reject response's error or request's status
|
|
reject(("error" in response === true) ? response["error"] : request["status"]);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Resolve response's result
|
|
resolve(response["result"]);
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Check if a response exists
|
|
if(response["length"] !== 0)
|
|
|
|
// Reject request's status
|
|
reject(request["status"]);
|
|
|
|
// Otherwise
|
|
else
|
|
|
|
// Resolve
|
|
resolve();
|
|
}
|
|
|
|
// Catch errors
|
|
}).catch(function(request) {
|
|
|
|
// Clear cancel allowed
|
|
cancelAllowed = false;
|
|
|
|
// Reject request's status
|
|
reject(request["status"]);
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Reject HTTP no response status
|
|
reject(Common.HTTP_NO_RESPONSE_STATUS);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Version
|
|
static get VERSION() {
|
|
|
|
// Return version
|
|
return "2.0";
|
|
}
|
|
|
|
// Default ID
|
|
static get DEFAULT_ID() {
|
|
|
|
// Return default ID
|
|
return 1;
|
|
}
|
|
|
|
// Default number of attempts
|
|
static get DEFAULT_NUMBER_OF_ATTEMPTS() {
|
|
|
|
// Return default number of attempts
|
|
return 5;
|
|
}
|
|
|
|
// Invalid response
|
|
static get INVALID_RESPONSE() {
|
|
|
|
// Return invalid response
|
|
return undefined;
|
|
}
|
|
|
|
// No ID
|
|
static get NO_ID() {
|
|
|
|
// Return no ID
|
|
return null;
|
|
}
|
|
|
|
// AJAX request canceled check interval milliseconds
|
|
static get AJAX_REQUEST_CANCELED_CHECK_INTERVAL_MILLISECONDS() {
|
|
|
|
// Return AJAX request canceled check interval milliseconds
|
|
return 50;
|
|
}
|
|
}
|
|
|
|
|
|
// Main function
|
|
|
|
// Set global object's JSON-RPC
|
|
globalThis["JsonRpc"] = JsonRpc;
|