mirror of
				https://github.com/Instadapp/Swap-Aggregator-Subgraph.git
				synced 2024-07-29 21:57:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			449 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			449 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 'use strict';
 | |
| 
 | |
| const compact = require('lodash/compact');
 | |
| const extend = require('lodash/extend');
 | |
| const isFunction = require('lodash/isFunction');
 | |
| const once = require('lodash/once');
 | |
| const partial = require('lodash/partial');
 | |
| const JSONStream = require('JSONStream');
 | |
| const JSONstringify = require('json-stringify-safe');
 | |
| const uuid = require('uuid/v4');
 | |
| 
 | |
| const generateRequest = require('./generateRequest');
 | |
| 
 | |
| /** * @namespace */
 | |
| const Utils = module.exports;
 | |
| 
 | |
| // same reference as other files use, for tidyness
 | |
| const utils = Utils;
 | |
| 
 | |
| Utils.request = generateRequest;
 | |
| 
 | |
| /**
 | |
|  *  Generates a JSON-RPC 1.0 or 2.0 response
 | |
|  *  @param {Object} error Error member
 | |
|  *  @param {Object} result Result member
 | |
|  *  @param {String|Number|null} id Id of request
 | |
|  *  @param {Number} version JSON-RPC version to use
 | |
|  *  @return {Object} A JSON-RPC 1.0 or 2.0 response
 | |
|  */
 | |
| Utils.response = function(error, result, id, version) {
 | |
|   id = typeof(id) === 'undefined' || id === null ? null : id;
 | |
|   error = typeof(error) === 'undefined' || error === null ? null : error;
 | |
|   version = typeof(version) === 'undefined' || version === null ? 2 : version;
 | |
|   const response = (version === 2) ? { jsonrpc: "2.0", id: id } : { id: id };
 | |
| 
 | |
|   // errors are always included in version 1
 | |
|   if(version === 1) {
 | |
|     response.error = error;
 | |
|   }
 | |
| 
 | |
|   // one or the other with precedence for errors
 | |
|   if(error) {
 | |
|     response.error = error;
 | |
|   } else {
 | |
|     response.result = result;
 | |
|   }
 | |
|   return response;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  *  Generates a random UUID
 | |
|  *  @return {String}
 | |
|  */
 | |
| Utils.generateId = function() {
 | |
|   return uuid();
 | |
| };
 | |
| 
 | |
| /**
 | |
|  *  Merges properties of object b into object a
 | |
|  *  @param {...Object} Objects to be merged
 | |
|  *  @return {Object}
 | |
|  *  @private
 | |
|  */
 | |
| Utils.merge = function() {
 | |
|   return extend.apply(null, arguments);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Parses an incoming stream for requests using JSONStream
 | |
|  * @param {Stream} stream
 | |
|  * @param {Object} options
 | |
|  * @param {Function} onRequest - Called once for stream errors and an unlimited amount of times for valid requests
 | |
|  */
 | |
| Utils.parseStream = function(stream, options, onRequest) {
 | |
| 
 | |
|   const onError = once(onRequest);
 | |
|   const onSuccess = partial(onRequest, null);
 | |
| 
 | |
|   const result = JSONStream.parse();
 | |
| 
 | |
|   result.on('data', function(data) {
 | |
| 
 | |
|     // apply reviver walk function to prevent stringify/parse again
 | |
|     if(isFunction(options.reviver)) {
 | |
|       data = Utils.walk({'': data}, '', options.reviver);
 | |
|     }
 | |
| 
 | |
|     onSuccess(data);
 | |
|   });
 | |
| 
 | |
|   result.on('error', onError);
 | |
|   stream.on('error', onError);
 | |
| 
 | |
|   stream.pipe(result);
 | |
| 
 | |
| };
 | |
| 
 | |
| /**
 | |
|  *  Helper to parse a stream and interpret it as JSON
 | |
|  *  @param {Stream} stream Stream instance
 | |
|  *  @param {Function} [options] Optional options for JSON.parse
 | |
|  *  @param {Function} callback
 | |
|  */
 | |
| Utils.parseBody = function(stream, options, callback) {
 | |
| 
 | |
|   callback = once(callback);
 | |
|   let data = '';
 | |
| 
 | |
|   stream.setEncoding('utf8');
 | |
| 
 | |
|   stream.on('data', function(str) {
 | |
|     data += str;
 | |
|   });
 | |
| 
 | |
|   stream.on('error', function(err) {
 | |
|     callback(err);
 | |
|   });
 | |
| 
 | |
|   stream.on('end', function() {
 | |
|     utils.JSON.parse(data, options, function(err, request) {
 | |
|       if(err) {
 | |
|         return callback(err);
 | |
|       }
 | |
|       callback(null, request);
 | |
|     });
 | |
|   });
 | |
| 
 | |
| };
 | |
| 
 | |
| /**
 | |
|  *  Returns a HTTP request listener bound to the server in the argument.
 | |
|  *  @param {http.Server} self Instance of a HTTP server
 | |
|  *  @param {JaysonServer} server Instance of JaysonServer (typically jayson.Server)
 | |
|  *  @return {Function}
 | |
|  *  @private
 | |
|  */
 | |
| Utils.getHttpListener = function(self, server) {
 | |
|   return function(req, res) {
 | |
|     const options = self.options || {};
 | |
| 
 | |
|     server.emit('http request', req);
 | |
| 
 | |
|     //  405 method not allowed if not POST
 | |
|     if(!Utils.isMethod(req, 'POST')) {
 | |
|       return respond('Method Not Allowed', 405, {'allow': 'POST'});
 | |
|     }
 | |
| 
 | |
|     // 415 unsupported media type if Content-Type is not correct
 | |
|     if(!Utils.isContentType(req, 'application/json')) {
 | |
|       return respond('Unsupported Media Type', 415);
 | |
|     }
 | |
| 
 | |
|     Utils.parseBody(req, options, function(err, request) {
 | |
|       if(err) {
 | |
|         return respond(err, 400);
 | |
|       }
 | |
| 
 | |
|       server.call(request, function(error, success) {
 | |
|         const response = error || success;
 | |
|         if(!response) {
 | |
|           // no response received at all, must be a notification
 | |
|           return respond('', 204);
 | |
|         }
 | |
| 
 | |
|         utils.JSON.stringify(response, options, function(err, body) {
 | |
|           if(err) {
 | |
|             return respond(err, 500);
 | |
|           }
 | |
| 
 | |
|           const headers = {
 | |
|             'content-length': Buffer.byteLength(body, options.encoding),
 | |
|             'content-type': 'application/json; charset=utf-8'
 | |
|           };
 | |
| 
 | |
|           respond(body, 200, headers);
 | |
|         });
 | |
| 
 | |
|       });
 | |
| 
 | |
|     });
 | |
| 
 | |
|     function respond(response, code, headers) {
 | |
|       const body = response instanceof Error ? response.toString() : response;
 | |
|       server.emit('http response', res, req);
 | |
|       res.writeHead(code, headers || {});
 | |
|       res.end(body);
 | |
|     }
 | |
| 
 | |
|   };
 | |
| };
 | |
| 
 | |
| /**
 | |
|  *  Determines if a HTTP Request comes with a specific Content-Type
 | |
|  *  @param {ServerRequest} request
 | |
|  *  @param {String} type
 | |
|  *  @return {Boolean}
 | |
|  *  @private
 | |
|  */
 | |
| Utils.isContentType = function(request, type) {
 | |
|   request = request || {headers: {}};
 | |
|   const contentType = request.headers['content-type'] || '';
 | |
|   return RegExp(type, 'i').test(contentType);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  *  Determines if a HTTP Request is of a specific method
 | |
|  *  @param {ServerRequest} request
 | |
|  *  @param {String} method
 | |
|  *  @return {Boolean}
 | |
|  *  @private
 | |
|  */
 | |
| Utils.isMethod = function(request, method) {
 | |
|   method = (method || '').toUpperCase();
 | |
|   return (request.method || '') === method;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Recursively walk an object and apply a function on its members
 | |
|  * @param {Object} holder The object to walk
 | |
|  * @param {String} key The key to look at
 | |
|  * @param {Function} fn The function to apply to members
 | |
|  * @return {Object}
 | |
|  */
 | |
| Utils.walk = function(holder, key, fn) {
 | |
|   let k, v, value = holder[key];
 | |
|   if (value && typeof value === 'object') {
 | |
|     for (k in value) {
 | |
|       if (Object.prototype.hasOwnProperty.call(value, k)) {
 | |
|         v = Utils.walk(value, k, fn);
 | |
|         if (v !== undefined) {
 | |
|           value[k] = v;
 | |
|         } else {
 | |
|           delete value[k];
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   return fn.call(holder, key, value);
 | |
| };
 | |
| 
 | |
| /** * @namespace */
 | |
| Utils.JSON = {};
 | |
| 
 | |
| /**
 | |
|  * Parses a JSON string and then invokes the given callback
 | |
|  * @param {String} str The string to parse
 | |
|  * @param {Object} options Object with options, possibly holding a "reviver" function
 | |
|  * @param {Function} callback
 | |
|  */
 | |
| Utils.JSON.parse = function(str, options, callback) {
 | |
|   let reviver = null;
 | |
|   let obj = null;
 | |
|   options = options || {};
 | |
| 
 | |
|   if(isFunction(options.reviver)) {
 | |
|     reviver = options.reviver;
 | |
|   }
 | |
| 
 | |
|   try {
 | |
|     obj = JSON.parse.apply(JSON, compact([str, reviver]));
 | |
|   } catch(err) {
 | |
|     return callback(err);
 | |
|   }
 | |
| 
 | |
|   callback(null, obj);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Stringifies JSON and then invokes the given callback
 | |
|  * @param {Object} obj The object to stringify
 | |
|  * @param {Object} options Object with options, possibly holding a "replacer" function
 | |
|  * @param {Function} callback
 | |
|  */
 | |
| Utils.JSON.stringify = function(obj, options, callback) {
 | |
|   let replacer = null;
 | |
|   let str = null;
 | |
|   options = options || {};
 | |
| 
 | |
|   if(isFunction(options.replacer)) {
 | |
|     replacer = options.replacer;
 | |
|   }
 | |
| 
 | |
|   try {
 | |
|     str = JSONstringify.apply(JSON, compact([obj, replacer]));
 | |
|   } catch(err) {
 | |
|     return callback(err);
 | |
|   }
 | |
| 
 | |
|   callback(null, str);
 | |
| };
 | |
| 
 | |
| /** * @namespace */
 | |
| Utils.Request = {};
 | |
| 
 | |
| /**
 | |
|  * Determines if the passed request is a batch request
 | |
|  * @param {Object} request The request
 | |
|  * @return {Boolean}
 | |
|  */
 | |
| Utils.Request.isBatch = function(request) {
 | |
|   return Array.isArray(request);
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Determines if the passed request is a notification request
 | |
|  * @param {Object} request The request
 | |
|  * @return {Boolean}
 | |
|  */
 | |
| Utils.Request.isNotification = function(request) {
 | |
|   return Boolean(
 | |
|     request
 | |
|     && !Utils.Request.isBatch(request)
 | |
|     && (typeof(request.id) === 'undefined'
 | |
|          || request.id === null)
 | |
|   );
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Determines if the passed request is a valid JSON-RPC 2.0 Request
 | |
|  * @param {Object} request The request
 | |
|  * @return {Boolean}
 | |
|  */
 | |
| Utils.Request.isValidVersionTwoRequest = function(request) {
 | |
|   return Boolean(
 | |
|     request
 | |
|     && typeof(request) === 'object'
 | |
|     && request.jsonrpc === '2.0'
 | |
|     && typeof(request.method) === 'string'
 | |
|     && (
 | |
|       typeof(request.params) === 'undefined'
 | |
|       || Array.isArray(request.params)
 | |
|       || (request.params && typeof(request.params) === 'object')
 | |
|     )
 | |
|     && (
 | |
|       typeof(request.id) === 'undefined'
 | |
|       || typeof(request.id) === 'string'
 | |
|       || typeof(request.id) === 'number'
 | |
|       || request.id === null
 | |
|     )
 | |
|   );
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Determines if the passed request is a valid JSON-RPC 1.0 Request
 | |
|  * @param {Object} request The request
 | |
|  * @return {Boolean}
 | |
|  */
 | |
| Utils.Request.isValidVersionOneRequest = function(request) {
 | |
|   return Boolean(
 | |
|     request
 | |
|     && typeof(request) === 'object'
 | |
|     && typeof(request.method) === 'string'
 | |
|     && Array.isArray(request.params)
 | |
|     && typeof(request.id) !== 'undefined'
 | |
|   );
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Determines if the passed request is a valid JSON-RPC Request
 | |
|  * @param {Object} request The request
 | |
|  * @param {Number} [version=2] JSON-RPC version 1 or 2
 | |
|  * @return {Boolean}
 | |
|  */
 | |
| Utils.Request.isValidRequest = function(request, version) {
 | |
|   version = version === 1 ? 1 : 2;
 | |
|   return Boolean(
 | |
|     request
 | |
|     && (
 | |
|       (version === 1 && Utils.Request.isValidVersionOneRequest(request)) ||
 | |
|       (version === 2 && Utils.Request.isValidVersionTwoRequest(request))
 | |
|     )
 | |
|   );
 | |
| };
 | |
| 
 | |
| /** * @namespace */
 | |
| Utils.Response = {};
 | |
| 
 | |
| /**
 | |
|  * Determines if the passed error is a valid JSON-RPC error response
 | |
|  * @param {Object} error The error
 | |
|  * @param {Number} [version=2] JSON-RPC version 1 or 2
 | |
|  * @return {Boolean}
 | |
|  */
 | |
| Utils.Response.isValidError = function(error, version) {
 | |
|   version = version === 1 ? 1 : 2;
 | |
|   return Boolean(
 | |
|     version === 1 && (
 | |
|       typeof(error) !== 'undefined'
 | |
|       && error !== null
 | |
|     )
 | |
|     || version === 2 && (
 | |
|       error
 | |
|       && typeof(error.code) === 'number'
 | |
|       && parseInt(error.code, 10) === error.code
 | |
|       && typeof(error.message) === 'string'
 | |
|     )
 | |
|   );
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Determines if the passed object is a valid JSON-RPC response
 | |
|  * @param {Object} response The response
 | |
|  * @param {Number} [version=2] JSON-RPC version 1 or 2
 | |
|  * @return {Boolean}
 | |
|  */
 | |
| Utils.Response.isValidResponse = function(response, version) {
 | |
|   version = version === 1 ? 1 : 2;
 | |
|   return Boolean(
 | |
|     response !== null
 | |
|     && typeof response === 'object'
 | |
|     && (version === 2 && (
 | |
|       // check version
 | |
|       response.jsonrpc === '2.0'
 | |
|       && (
 | |
|         // check id
 | |
|         response.id === null
 | |
|         || typeof response.id === 'string'
 | |
|         || typeof response.id === 'number'
 | |
|       )
 | |
|       && (
 | |
|         // result and error do not exist at the same time
 | |
|         (typeof response.result === 'undefined' && typeof response.error !== 'undefined')
 | |
|         || (typeof response.result !== 'undefined' && typeof response.error === 'undefined')
 | |
|       )
 | |
|       && (
 | |
|         // check result
 | |
|         (typeof response.result !== 'undefined')
 | |
|         // check error object
 | |
|         || (
 | |
|           response.error !== null
 | |
|           && typeof response.error === 'object'
 | |
|           && typeof response.error.code === 'number'
 | |
|           // check error.code is integer
 | |
|           && ((response.error.code | 0) === response.error.code)
 | |
|           && typeof response.error.message === 'string'
 | |
|         )
 | |
|       )
 | |
|     )
 | |
|       || version === 1 && (
 | |
|         typeof response.id !== 'undefined'
 | |
|         && (
 | |
|           // result and error relation (the other null if one is not)
 | |
|           (typeof response.result !== 'undefined' && response.error === null)
 | |
|           || (typeof response.error !== 'undefined' && response.result === null)
 | |
|         )
 | |
|       ))
 | |
|   );
 | |
| };
 | 
