UNPKG

edichain

Version:

Provides a basic integration for ipfs (storage/distribution) and ethereum blockchain (validation/authorization) based EDIfact message exchange.

293 lines (264 loc) 10.7 kB
(function($, undefined) { $.extend({ jsonRPC: { // RPC Version Number version: '2.0', // End point URL, sets default in requests if not // specified with the request call endPoint: null, // Default namespace for methods namespace: null, /* * Provides the RPC client with an optional default endpoint and namespace * * @param {object} The params object which can contain * endPoint {string} The default endpoint for RPC requests * namespace {string} The default namespace for RPC requests * cache {boolean} If set to false, it will force requested * pages not to be cached by the browser. Setting cache * to false also appends a query string parameter, * "_=[TIMESTAMP]", to the URL. (Default: true) */ setup: function(params) { this._validateConfigParams(params); this.endPoint = params.endPoint; this.namespace = params.namespace; this.cache = params.cache !== undefined ? params.cache : true; return this; }, /* * Convenience wrapper method to allow you to temporarily set a config parameter * (endPoint or namespace) and ensure it gets set back to what it was before * * @param {object} The params object which can contains * endPoint {string} The default endpoint for RPC requests * namespace {string} The default namespace for RPC requests * @param {function} callback The function to call with the new params in place */ withOptions: function(params, callback) { this._validateConfigParams(params); // No point in running if there isn't a callback received to run if(callback === undefined) throw("No callback specified"); origParams = {endPoint: this.endPoint, namespace: this.namespace}; this.setup(params); callback.call(this); this.setup(origParams); }, /* * Performas a single RPC request * * @param {string} method The name of the rpc method to be called * @param {object} options A collection of object which can contains * params {array} the params array to send along with the request * success {function} a function that will be executed if the request succeeds * error {function} a function that will be executed if the request fails * url {string} the url to send the request to * id {string} the provenance id for this request (defaults to 1) * cache {boolean} If set to false, it will force requested * pages not to be cached by the browser. Setting cache * to false also appends a query string parameter, * "_=[TIMESTAMP]", to the URL. (Default: cache value * set with the setup method) * @return {undefined} */ request: function(method, options) { if(options === undefined) { options = { id: 1 }; } if (options.id === undefined) { options.id = 1; } if (options.cache === undefined) { options.cache = this.cache; } // Validate method arguments this._validateRequestMethod(method); this._validateRequestParams(options.params); this._validateRequestCallbacks(options.success, options.error); // Perform the actual request this._doRequest(JSON.stringify(this._requestDataObj(method, options.params, options.id)), options); return true; }, /* * Submits multiple requests * Takes an array of objects that contain a method and params * * @params {array} requests an array of request object which can contain * method {string} the name of the method * param {object} the params object to be sent with the request * id {string} the provenance id for the request (defaults to an incrementer starting at 1) * @param {object} options A collection of object which can contains * success {function} a function that will be executed if the request succeeds * error {function} a function that will be executed if the request fails * url {string} the url to send the request to * @return {undefined} */ batchRequest: function(requests, options) { if(options === undefined) { options = {}; } // Ensure our requests come in as an array if(!$.isArray(requests) || requests.length === 0) throw("Invalid requests supplied for jsonRPC batchRequest. Must be an array object that contain at least a method attribute"); // Make sure each of our request objects are valid var _that = this; $.each(requests, function(i, req) { _that._validateRequestMethod(req.method); _that._validateRequestParams(req.params); if (req.id === undefined) { req.id = i + 1; } }); this._validateRequestCallbacks(options.success, options.error); var data = [], request; // Prepare our request object for(var i = 0; i<requests.length; i++) { request = requests[i]; data.push(this._requestDataObj(request.method, request.params, request.id)); } this._doRequest(JSON.stringify(data), options); }, // Validate a params hash _validateConfigParams: function(params) { if(params === undefined) { throw("No params specified"); } else { if(params.endPoint && typeof(params.endPoint) !== 'string'){ throw("endPoint must be a string"); } if(params.namespace && typeof(params.namespace) !== 'string'){ throw("namespace must be a string"); } } }, // Request method must be a string _validateRequestMethod: function(method) { if(typeof(method) !== 'string') throw("Invalid method supplied for jsonRPC request") return true; }, // Validate request params. Must be a) empty, b) an object (e.g. {}), or c) an array _validateRequestParams: function(params) { if(!(params === null || params === undefined || typeof(params) === 'object' || $.isArray(params))) { throw("Invalid params supplied for jsonRPC request. It must be empty, an object or an array."); } return true; }, _validateRequestCallbacks: function(success, error) { // Make sure callbacks are either empty or a function if(success !== undefined && typeof(success) !== 'function') throw("Invalid success callback supplied for jsonRPC request"); if(error !== undefined && typeof(error) !== 'function') throw("Invalid error callback supplied for jsonRPC request"); return true; }, // Internal method used for generic ajax requests _doRequest: function(data, options) { var _that = this; $.ajax({ type: 'POST', async: false !== options.async, dataType: 'json', contentType: 'application/json', url: this._requestUrl((options.endPoint || options.url), options.cache), data: data, cache: options.cache, headers: options.headers, processData: false, error: function(json) { _that._requestError.call(_that, json, options.error); }, success: function(json) { _that._requestSuccess.call(_that, json, options.success, options.error); } }) }, // Determines the appropriate request URL to call for a request _requestUrl: function(url, cache) { url = url || this.endPoint; if (!cache) { if (url.indexOf("?") < 0) { url += '?tm=' + new Date().getTime(); } else { url += "&tm=" + new Date().getTime(); } } return url; }, // Creates an RPC suitable request object _requestDataObj: function(method, params, id) { var dataObj = { jsonrpc: this.version, method: this.namespace ? this.namespace +'.'+ method : method, id: id } if(params !== undefined) { dataObj.params = params; } return dataObj; }, // Handles calling of error callback function _requestError: function(json, error) { if (error !== undefined && typeof(error) === 'function') { if(typeof(json.responseText) === 'string') { try { error(JSON.parse(json.responseText)); } catch(e) { error(this._response()); } } else { error(this._response()); } } }, // Handles calling of RPC success, calls error callback // if the response contains an error // TODO: Handle error checking for batch requests _requestSuccess: function(json, success, error) { var response = this._response(json); // If we've encountered an error in the response, trigger the error callback if it exists if(response.error && typeof(error) === 'function') { error(response); return; } // Otherwise, successful request, run the success request if it exists if(typeof(success) === 'function') { success(response); } }, // Returns a generic RPC 2.0 compatible response object _response: function(json) { if (json === undefined) { return { error: 'Internal server error', version: '2.0' }; } else { try { if(typeof(json) === 'string') { json = JSON.parse(json); } if (($.isArray(json) && json.length > 0 && json[0].jsonrpc !== '2.0') || (!$.isArray(json) && json.jsonrpc !== '2.0')) { throw 'Version error'; } return json; } catch (e) { return { error: 'Internal server error: ' + e, version: '2.0' } } } } } }); })(jQuery);