// 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 ) ;
} ;
}