From 7db49d14f412dd43a8c64d8cb14b42582a565113 Mon Sep 17 00:00:00 2001 From: Ondrej Zdych Date: Fri, 1 May 2015 18:35:36 +0200 Subject: [PATCH 1/2] add ability to call methods from client using ES6 Proxy API if available --- README.md | 70 ++++++++++++++++++++++--------------- example/proxy_calls.js | 43 +++++++++++++++++++++++ lib/client.js | 21 +++++++++++ lib/utils.js | 45 ++++++++++++++++++++++++ package.json | 79 +++++++++++++++++++++++------------------- 5 files changed, 195 insertions(+), 63 deletions(-) create mode 100644 example/proxy_calls.js create mode 100644 lib/utils.js diff --git a/README.md b/README.md index 07328d0..84c23e6 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ method responses, or as both. npm install xmlrpc ``` +**NOTE**: If you want to make method calls using ES6 Proxy API, you need to run your app with flag turning Proxy API on `node --harmony-proxies example/proxy_calls.js`. + +ES6 Proxy calls also require `Promise` support (`Client#methodCallPromise` method). + ### To Use The file client_server.js in the example directory has a nicely commented @@ -27,47 +31,59 @@ other!). A brief example: ```javascript -var xmlrpc = require('xmlrpc') +var xmlrpc = require('../lib/xmlrpc'); + +function logError (error) { + console.log('An error occured: ' + error.message); +} // Creates an XML-RPC server to listen to XML-RPC method calls -var server = xmlrpc.createServer({ host: 'localhost', port: 9090 }) -// Handle methods not found -server.on('NotFound', function(method, params) { - console.log('Method ' + method + ' does not exist'); -}) -// Handle method calls by listening for events with the method call name -server.on('anAction', function (err, params, callback) { - console.log('Method call params for \'anAction\': ' + params) - - // ...perform an action... - - // Send a method response with a value - callback(null, 'aResult') -}) +xmlrpc.createServer({ host: 'localhost', port: 9090 }) + // Handle methods not found + .on('NotFound', function (method, params) { + console.log('Method ' + method + ' does not exist'); + }) + // Handle method calls by listening for events with the method call name + .on('company.employees.list', function (err, params, callback) { + console.log('Method call params for \'company.employees.list\': ', params); + + callback(null, []); + }) + .on('company.employees.getDetail', function (err, params, callback) { + console.log('Method call params for \'company.employees.getDetail\': ', params); + + callback(null, { id: params[0], name: 'Ondrej' }); + }); + console.log('XML-RPC server listening on port 9091') -// Waits briefly to give the XML-RPC server time to start up and start -// listening + setTimeout(function () { // Creates an XML-RPC client. Passes the host information on where to // make the XML-RPC calls. - var client = xmlrpc.createClient({ host: 'localhost', port: 9090, path: '/'}) + var client = xmlrpc.createClient({ host: 'localhost', port: 9090, path: '/'}); - // Sends a method call to the XML-RPC server - client.methodCall('anAction', ['aParam'], function (error, value) { - // Results of the method response - console.log('Method response for \'anAction\': ' + value) - }) + client.$.company.employees.list() + .then(function (value) { + console.log('Method response for \'company.employees.list\': ', value); + }).catch(logError); + + client.$.company.employees.getDetail(1, true) + .then(function (value) { + console.log('Method response for \'company.employees.getDetail\': ', value); + }).catch(logError); -}, 1000) +}, 1000); ``` Output from the example: ``` -XML-RPC server listening on port 9090 -Method call params for 'anAction': aParam -Method response for 'anAction': aResult +XML-RPC server listening on port 9091 +Method call params for 'company.employees.list': [] +Method response for 'company.employees.list': [] +Method call params for 'company.employees.getDetail': [ 1, true ] +Method response for 'company.employees.getDetail': { id: 1, name: 'Ondrej' } ``` ### Date/Time Formatting diff --git a/example/proxy_calls.js b/example/proxy_calls.js new file mode 100644 index 0000000..55c800d --- /dev/null +++ b/example/proxy_calls.js @@ -0,0 +1,43 @@ +var xmlrpc = require('../lib/xmlrpc'); + +function logError (error) { + console.log('An error occured: ' + error.message); +} + +// Creates an XML-RPC server to listen to XML-RPC method calls +xmlrpc.createServer({ host: 'localhost', port: 9090 }) + // Handle methods not found + .on('NotFound', function (method, params) { + console.log('Method ' + method + ' does not exist'); + }) + // Handle method calls by listening for events with the method call name + .on('company.employees.list', function (err, params, callback) { + console.log('Method call params for \'company.employees.list\': ', params); + + callback(null, []); + }) + .on('company.employees.getDetail', function (err, params, callback) { + console.log('Method call params for \'company.employees.getDetail\': ', params); + + callback(null, { id: params[0], name: 'Ondrej' }); + }); + +console.log('XML-RPC server listening on port 9091') + + +setTimeout(function () { + // Creates an XML-RPC client. Passes the host information on where to + // make the XML-RPC calls. + var client = xmlrpc.createClient({ host: 'localhost', port: 9090, path: '/'}); + + client.$.company.employees.list() + .then(function (value) { + console.log('Method response for \'company.employees.list\': ', value); + }).catch(logError); + + client.$.company.employees.getDetail(1, true) + .then(function (value) { + console.log('Method response for \'company.employees.getDetail\': ', value); + }).catch(logError); + +}, 1000); \ No newline at end of file diff --git a/lib/client.js b/lib/client.js index 6341b7e..18198b8 100644 --- a/lib/client.js +++ b/lib/client.js @@ -4,6 +4,7 @@ var http = require('http') , Serializer = require('./serializer') , Deserializer = require('./deserializer') , Cookies = require('./cookies') + , utils = require('./utils') /** * Creates a Client object for making XML-RPC method calls. @@ -85,6 +86,26 @@ function Client(options, isSecure) { this.cookies = new Cookies(); this.headersProcessors.processors.unshift(this.cookies); } + + // create proxy object for method calls using ES6 Proxy API, + // only when Proxy is available + if (utils.isProxyAPIAvailable()) { + this.$ = utils.createProxy(this.methodCallPromise.bind(this)); + } +} + +Client.prototype.methodCallPromise = function methodCallPromise(method, params) { + var self = this; + + return new Promise(function(resolve, reject) { + self.methodCall(method, params, function(err, result) { + if (err) { + return reject(err); + } + + resolve(result); + }); + }); } /** diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..a132f88 --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,45 @@ +function isProxyAPIAvailable () { + return global.Proxy !== void 0; +} + +if (isProxyAPIAvailable()) { + // require Proxy API normalization polyfill because current V8's implementation doesn't support standardized API (2015-05-01) + require('harmony-reflect'); +} +else { + console.info('ES6 Proxy API is not available. Run node with flag `--harmony-proxies` to make calls using this API.'); +} + +module.exports = { + // https://gist.github.com/zdychacek/00d4853ab6856f3c6912 + createProxy: function (action) { + // create the callable proxy + function _createCallableProxy (name) { + var methodNames = [ name ]; + + return new Proxy(function () {}, { + get: function (target, name, receiver) { + // push a name of the method into the accumulator + methodNames.push(name); + + return receiver; + }, + apply: function (target, name, args) { + // call the method finally + var result = action(methodNames.join('.'), args); + + return result; + } + }); + } + + // create the main proxy object + return new Proxy({}, { + get: function (target, name) { + return _createCallableProxy(name); + } + }); + }, + + isProxyAPIAvailable: isProxyAPIAvailable +}; \ No newline at end of file diff --git a/package.json b/package.json index d515771..247127d 100644 --- a/package.json +++ b/package.json @@ -1,39 +1,46 @@ -{ "name" : "xmlrpc" -, "description" : "A pure JavaScript XML-RPC client and server." -, "keywords" : [ "xml-rpc", "xmlrpc", "xml", "rpc" ] -, "version" : "1.3.0" -, "preferGlobal" : false -, "homepage" : "https://github.com/baalexander/node-xmlrpc" -, "author" : "Brandon Alexander (https://github.com/baalexander)" -, "repository" : { - "type" : "git" - , "url" : "git://github.com/baalexander/node-xmlrpc.git" - } -, "bugs" : { - "url" : "https://github.com/baalexander/node-xmlrpc/issues" - } -, "directories" : { - "lib" : "./lib" - } -, "main" : "./lib/xmlrpc.js" -, "dependencies" : { - "sax" : "0.6.x" - , "xmlbuilder" : "2.6.x" - } -, "devDependencies" : { - "vows" : "0.7.x" - } -, "scripts" : { - "test" : "make test" - } -, "engines" : { - "node" : ">=0.8", - "npm" : ">=1.0.0" - } -, "licenses" : [ { - "type" : "MIT" - , "url" : "https://github.com/baalexander/node-xmlrpc/raw/master/LICENSE" +{ + "name": "xmlrpc", + "description": "A pure JavaScript XML-RPC client and server.", + "keywords": [ + "xml-rpc", + "xmlrpc", + "xml", + "rpc" + ], + "version": "1.3.0", + "preferGlobal": false, + "homepage": "https://github.com/baalexander/node-xmlrpc", + "author": "Brandon Alexander (https://github.com/baalexander)", + "repository": { + "type": "git", + "url": "git://github.com/baalexander/node-xmlrpc.git" + }, + "bugs": { + "url": "https://github.com/baalexander/node-xmlrpc/issues" + }, + "directories": { + "lib": "./lib" + }, + "main": "./lib/xmlrpc.js", + "dependencies": { + "harmony-reflect": "^1.1.3", + "sax": "0.6.x", + "xmlbuilder": "2.6.x" + }, + "devDependencies": { + "vows": "0.7.x" + }, + "scripts": { + "test": "make test" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.0.0" + }, + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/baalexander/node-xmlrpc/raw/master/LICENSE" } ] } - From 0943efcb92263c87a52ec857e1bcef7c469755fe Mon Sep 17 00:00:00 2001 From: Ondrej Zdych Date: Fri, 1 May 2015 18:40:58 +0200 Subject: [PATCH 2/2] add missing EOLs --- example/proxy_calls.js | 2 +- lib/utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/proxy_calls.js b/example/proxy_calls.js index 55c800d..c7717be 100644 --- a/example/proxy_calls.js +++ b/example/proxy_calls.js @@ -40,4 +40,4 @@ setTimeout(function () { console.log('Method response for \'company.employees.getDetail\': ', value); }).catch(logError); -}, 1000); \ No newline at end of file +}, 1000); diff --git a/lib/utils.js b/lib/utils.js index a132f88..5e032ce 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -42,4 +42,4 @@ module.exports = { }, isProxyAPIAvailable: isProxyAPIAvailable -}; \ No newline at end of file +};