You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mymonero-core-js/hostAPI/net_service_utils.js

157 lines
5.3 KiB

// Copyright (c) 2014-2019, MyMonero.com
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
"use strict";
//
const response_parser_utils = require("./response_parser_utils");
const JSBigInt = require("../cryptonote_utils/biginteger").BigInteger; // important: grab defined export
//
function New_ParametersForWalletRequest(address, view_key__private) {
return {
address: address,
view_key: view_key__private,
};
}
exports.New_ParametersForWalletRequest = New_ParametersForWalletRequest;
//
function AddUserAgentParamters(
parameters,
appUserAgent_product,
appUserAgent_version,
) {
// setting these on params instead of as header field User-Agent so as to retain all info found in User-Agent, such as platform… and these are set so server has option to control delivery
parameters["app_name"] = appUserAgent_product;
parameters["app_version"] = appUserAgent_version;
}
exports.AddUserAgentParamters = AddUserAgentParamters;
//
function HTTPRequest(
request_conformant_module, // such as 'request' or 'xhr' .. TODO: consider switching to 'fetch'
apiAddress_authority, // authority means [subdomain.]host.…[:…] with no trailing slash
endpointPath,
final_parameters,
fn,
) {
// fn: (err?, data?) -> new Request
if (typeof final_parameters == "undefined" || final_parameters == null) {
throw "final_parameters must not be nil";
// return null
}
const completeURL =
_new_APIAddress_baseURLString(apiAddress_authority) + endpointPath;
console.log("📡 " + completeURL);
//
const request_options = _new_requestOptions_base(
"POST",
completeURL,
final_parameters,
);
const requestHandle = request_conformant_module(request_options, function(
err_orProgressEvent,
res,
body,
) {
_new_HTTPRequestHandlerFunctionCallingFn(fn)(
// <- called manually instead of directly passed to request_conformant_module call to enable passing completeURL
completeURL,
err_orProgressEvent,
res,
body,
);
});
//
return requestHandle;
}
exports.HTTPRequest = HTTPRequest;
//
function _new_APIAddress_baseURLString(
apiAddress_authority, // authority means [subdomain.]host.…[:…]
) {
return "https" + "://" + apiAddress_authority + "/";
}
function _new_requestOptions_base(methodName, completeURL, json_parameters) {
return {
method: methodName,
url: completeURL,
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
json: json_parameters,
useXDR: true, // CORS
withCredentials: true, // CORS
};
}
function _new_HTTPRequestHandlerFunctionCallingFn(fn) {
return function(completeURL, err_orProgressEvent, res, body) {
// err appears to actually be a ProgressEvent
var err = null;
const statusCode = typeof res !== "undefined" ? res.statusCode : -1;
if (statusCode == 0 || statusCode == -1) {
// we'll treat 0 as a lack of internet connection.. unless there's a better way to make use of err_orProgressEvent which is apparently going to be typeof ProgressEvent here
err = new Error("Connection Failure");
} else if (statusCode !== 200) {
const body_Error =
body && typeof body == "object" ? body.Error : undefined;
const statusMessage =
res && res.statusMessage ? res.statusMessage : undefined;
if (typeof body_Error !== "undefined" && body_Error) {
err = new Error(body_Error);
} else if (typeof statusMessage !== "undefined" && statusMessage) {
err = new Error(statusMessage);
} else {
err = new Error("Unknown " + statusCode + " error");
}
}
if (err) {
console.error("❌ " + err);
// console.error("Body:", body)
fn(err, null);
return;
}
var json;
if (typeof body === "string") {
try {
json = JSON.parse(body);
} catch (e) {
console.error(
"❌ HostedMoneroAPIClient Error: Unable to parse json with exception:",
e,
"\nbody:",
body,
);
fn(e, null);
}
} else {
json = body;
}
console.log("✅ " + completeURL + " " + statusCode);
fn(null, json);
};
}