My favorites | Sign in
Project Home Wiki Issues Source
READ-ONLY: This project has been archived. For more information see this post.
Search
for
TwistedNetstring  
Updated Jan 8, 2012 by duncan.m...@gmail.com

JSON-RPC over TCP

Dependencies

  • Twisted
  • simplejson
  • setuptools

Notes

This version was built from the adytum.twisted.web2.jsonrpc code by essentially replacing the HTTP-related code with twisted.protocols.basic.NetstringReceiver code.

One of the benefits of using Netstrings for this are string-length checks. There is a default maximum length that can be sent to the server. If you are sending large JSON strings to the server, you may need to override the default (1024 bytes).

The tests for adytum.twisted.web2.jsonrpc were also included/adapted and pass successfully.

Import

This is a stand-alone package that uses the adytum namespace, so if you have any other adytum code installed, you'll need to use setuptools' pkg_resource module:

>>> from pkg_resources import require
>>> require('Twisted-JSONRPC')
>>> from adytum.twisted import jsonrpc

If not, then you can simply use the standard import:

>>> from adytum.twisted import jsonrpc

Note that these imports are at the adytum.twisted level (unlike the others two, which are at adytum.twisted.web and adytum.twisted.web2).

Usage

Server

The server setup is a little different than with the HTTP versions. In particular, the manner of setting up subhandlers has changed. But first, let's look at a server example:

from twisted.application import service, internet

from adytum.twisted import jsonrpc

class Example(jsonrpc.JSONRPC):
    """An example object to be published."""

    def jsonrpc_echo(self, x):
        """Return all passed args."""
        return x

class Testing(jsonrpc.JSONRPC):

    def jsonrpc_getList(self):
        """Return a list."""
        return [1,2,3,4,'a','b','c','d']

class Math(jsonrpc.JSONRPC):

    def jsonrpc_add(self, a, b):
        """Return sum of arguments."""
        return a + b

# Setup the subhandlers for our RPC API
factory = jsonrpc.RPCFactory(Example)
factory.putSubHandler('math', Math)
factory.putSubHandler('testing', Testing)

# Let's add introspection, just for fun
factory.addIntrospection()

application = service.Application("Example JSON-RPC Server")
jsonrpcServer = internet.TCPServer(7080, factory)
jsonrpcServer.setServiceParent(application)

With the HTTP versions, you create instances of your JSONRPC subclasses when adding them as subhandlers:

top = Example()
top.addSubHandler('math', Math())
top.addSubHandler('testing', Testing())

But for the TCP version, you can see that we add the JSONRPC subclasses to the factory instead:

factory = jsonrpc.RPCFactory(Example)
factory.putSubHandler('math', Math)
factory.putSubHandler('testing', Testing)

As for adding the introspection, there are two ways to do it with the TCP version. One way is how we did it in the example server above. The other way is similar to the HTTP RPC servers:

addIntrospection(factory)

But note that you are passing the factory and not the parent instance.

Save the server code from above as server_subhandled.tac and run with the following command:

$ twistd -noy server_subhandled.tac

Client

Here is example client code for the server above:

from twisted.internet import reactor
from twisted.internet import defer

from adytum.twisted.jsonrpc import Proxy

def printValue(value):
    print "Result: %s" % str(value)

def printError(error):
    print 'error', error

def shutDown(data):
    print "Shutting down reactor..."
    reactor.stop()

print "Making remote calls..."
proxy = Proxy('127.0.0.1', 7080)
dl = []

d = proxy.callRemote('system.listMethods')
d.addCallbacks(printValue, printError)
dl.append(d)

d = proxy.callRemote('echo', 'bite me')
d.addCallbacks(printValue, printError)
dl.append(d)

d = proxy.callRemote('testing.getList')
d.addCallbacks(printValue, printError)
dl.append(d)

d = proxy.callRemote('math.add', 3, 5)
d.addCallbacks(printValue, printError)
dl.append(d)

dl = defer.DeferredList(dl)
dl.addCallback(shutDown)
reactor.run()

Save this file as client_subhandled.py and run it from the command line. You should see output something like this:

Making remote calls...
Result: [u'echo', u'math.add', u'system.listMethods', u'system.methodHelp', u'system.methodSignature', u'testing.getList']
Result: [1, 2, 3, 4, u'a', u'b', u'c', u'd']
Result: 8
Result: bite me
Shutting down reactor...

Powered by Google Project Hosting