Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for ES6 Proxy style client calls #107

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 43 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
43 changes: 43 additions & 0 deletions example/proxy_calls.js
Original file line number Diff line number Diff line change
@@ -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);
21 changes: 21 additions & 0 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
});
});
}

/**
Expand Down
45 changes: 45 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
@@ -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
};
79 changes: 43 additions & 36 deletions package.json
Original file line number Diff line number Diff line change
@@ -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 <[email protected]> (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 <[email protected]> (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"
}
]
}