Commit 9d856cd5 authored by Antoine Millet's avatar Antoine Millet

Updated documentation for the new sjRpc version.

parent 09401231
sjRpc API
=========
.. automodule:: sjrpc
Core library
------------
.. automodule:: sjrpc.core
:members:
:inherited-members:
Client side library
-------------------
.. automodule:: sjrpc.client
:members:
:inherited-members:
Server side library
-------------------
.. automodule:: sjrpc.server
:members:
:inherited-members:
Utils
-----
.. automodule:: sjrpc.utils
:members:
:inherited-members:
Core library
------------
.. automodule:: sjrpc.core
:members:
:inherited-members:
sjRpc API
=========
.. automodule:: sjrpc
Sub-packages:
.. toctree::
:maxdepth: 2
core
server
utils
Server side library
-------------------
.. automodule:: sjrpc.server
:members:
:inherited-members:
Utils
-----
.. automodule:: sjrpc.utils
:members:
:inherited-members:
......@@ -22,7 +22,8 @@ sys.path.append(os.path.abspath('../'))
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig']
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo',
'sphinx.ext.pngmath', 'sphinx.ext.ifconfig', 'sphinx.ext.autosummary']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
......@@ -92,7 +93,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default'
html_theme = 'nature'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
......
Examples
========
Client example
--------------
.. literalinclude:: examples/client.py
:language: python
:linenos:
Server example
--------------
.. literalinclude:: examples/server.py
:language: python
:linenos:
#!/usr/bin/env python
'''
sjRpc client example.
'''
from __future__ import absolute_import
import sys
import random
import threading
import time
from sjrpc.core import RpcConnection
from sjrpc.utils import RpcHandler
class MyClientHandler(RpcHandler):
def client_random(self, min=0, max=100):
print 'Local call to client_random'
return random.randint(min, max)
# Get arguments from the command line:
if len(sys.argv) < 3:
print 'Usage: %s <listening address> <listening port>' % sys.argv[0]
sys.exit(2)
address = sys.argv[1]
port = int(sys.argv[2])
# Create the rpc connection:
conn = RpcConnection.from_addr(address, port, handler=MyClientHandler())
# Run the connection mainloop in another thread:
threading.Thread(target=conn.run).start()
time.sleep(0.1)
print 'Random = %s' % (conn.call('proxy', 'client_random'), )
conn.shutdown()
#!/usr/bin/env python
'''
Server mode using Gevent.
'''
from __future__ import absolute_import
import sys
import random
from sjrpc.server import GreenRpcServer
from sjrpc.utils import RpcHandler, pass_connection
class MyHandler(RpcHandler):
def random(self, min=0, max=100):
return random.randint(min, max)
@pass_connection
def proxy(self, conn, method, *args, **kwargs):
'''
Example of bidirectionnal RPC. When the peer call this method, the
server forward the call of the specified method the peer, and return
returned value.
'''
return conn.call(method, *args, **kwargs)
# Get arguments from the command line:
if len(sys.argv) < 3:
print 'Usage: %s <listening address> <listening port>' % sys.argv[0]
sys.exit(2)
address = sys.argv[1]
port = int(sys.argv[2])
# Create the server instance:
rpcserver = GreenRpcServer(address, port, conn_kw=dict(handler=MyHandler()))
# conn_kw (and conn_args) are arguments which are automatically passed on
# client RpcConnection instances.
rpcserver.run()
Fundamentals
============
sjRpc is a RPC (Remote Procedure Call) library written with Python. It was
originally created for the needs of CloudControl project but can be reused
in other projects.
Features
--------
* **Bidirectional:** remote function can be call by both side of the,
connection, so a client can connect to a server and export functions to it.
* **Use Gevent:** the server mode can use Gevent to take profits of
asynchronous io, but a threaded mode is also provided. The client mode can
be used without Gevent or Threading.
* **Multiplexed:** sjRpc can run many "protocols" on the same connection,
read more about protocols in `Multiplexing & protocols`_ section.
Multiplexing & protocols
------------------------
Protocol of sjRpc use channels to multiplexe many protocols on the
same connection. Each channel is binded to a protocol handler on each side, and
each channel have a label which identify it on the wire. Actually, the sjRpc
protocol look like this::
+------------+------------------------+---------------------------------+
| Label (2) | Payload size (4) | Payload (variable) |
+------------+------------------------+---------------------------------+
For the moment, two types of protocols are implemented:
* **Rpc:** protocol which allow to make remote function call easily.
* **Tunnel:** protocol which allow to tunnel a socket through the sjRpc
connection.
.. note::
A Rpc protocol is automatically created and binded to label 0 when a
:class:`RpcConnection` class is instantiated. This can't be changed or
removed.
Default rpc, aka Rpc0
---------------------
Rpc0 is an RpcProtocol binded by default with the "0" label. You can't
unregister this protocol, and you can't disable this feature. Rpc0 is used
internally by sjRpc to share special messages, and for compatibility with
olders sjRpc (see `Fallback mode`_ below).
However, you can use this rpc like any other, with your own rpc handler.
Fallback mode
-------------
The fallback mode makes the *sjrpc >= 14* compatible with olders version where
channels and protocols doesn't exists. Old and new protocols are very similar,
the new one just add a label field on each frame which allow multiplexing, but
the rpc protocol itself has not changed, and is always using json messaging.
The fallback mode is enabled by default when a connection is established (you
can disable this behavior with the `disable_fallback` parameter of the
:class:`RpcConnection` class constructor) and is automatically disabled when
a special rpc message "capabilities" is received.
.. note::
When the fallback mode is enabled, you can't use another protocols than the
default rpc. All calls to :meth:`RpcConnection.register_protocol`,
:meth:`RpcConnection.unregister_protocol`, :meth:`RpcConnection.create_rpc`
and :meth:`RpcConnection.create_tunnel`, will fail with a
:exc:`FallbackModeEnabledError`.
......@@ -6,7 +6,9 @@ Contents:
.. toctree::
:maxdepth: 2
api
fundamentals
examples
api/index
Indices and tables
==================
......
......@@ -5,11 +5,17 @@ This module implements a Remote Procedure Call system using socket objects as
transport. The main feature of this RPC is to be bidirectionnal: both client and
server can serve remote procedure for its peer.
The library is separated into four parts:
Features:
* core library contains all common classes.
* server library contains all the server side related stuff.
* utils library contains some helpers used in previous libraries.
* Multiplexed: you can run tunnels or many RPC through the same socket.
* Gevent: sjRpc is compatible with gevent and use it for server feature.
* Bidirectionnal: each peer can call remote function on other.
The library is separated into three parts:
* **core** package contains all common classes.
* **server** package contains all the server side related stuff.
* **utils** package contains some helpers used in previous libraries.
'''
......
#!/usr/bin/env python
#coding:utf8
'''
The **core** package contains all classes used by both client mode and server
mode.
This packages export following function/classes:
* :class:`RpcConnection` which handle the connection to the peer.
* :class:`RpcCaller`, :class:`ThreadedRpcCaller`: which are used internally
by rpc protocol to execute handlers' functions.
* :class:`RpcError` which is the exception raised by rpc to wrap remote-side
exceptions.
* :class:`AsyncWatcher` which allow to make asynchronous calls.
'''
from sjrpc.core.rpcconnection import *
from sjrpc.core.callers import *
......
......@@ -7,8 +7,7 @@ from Queue import Queue, Empty
class AsyncWatcher(object):
'''
Asynchronous call watcher -- Handle reception of asynchrone-request
responses.
Asynchronous call watcher -- Handle asynchronous calls and responses.
Usage example:
>>> watcher = AsyncWatcher()
......@@ -57,16 +56,16 @@ class AsyncWatcher(object):
def wait(self, timeout=None, max_wait=None):
'''
Wait messages registered on this :class:`AsyncWatcher` instance and
return them.
Wait responses for calls registered on this :class:`AsyncWatcher`
instance and return them.
:param timeout: timeout value or None to disable timeout (default: None)
:param max_wait: maximum waited messages
:param max_wait: maximum waited responses
:return: received messages in a list
.. note::
You can repeat call to this method on a single
:class:`AsyncWatcher`, for example, if you want to process the
:class:`AsyncWatcher`. For example, if you want to process the
first arrived message, then wait others for a minute, you can do:
>>> msgs = watcher.wait(max_wait=1)
......
......@@ -20,7 +20,7 @@ class RpcConnection(object):
This class manage a single peer connection.
:param sock: the socket object of this newly created :class:`RpcConnection`
:param *args, **kwargs: arguments to pass to the default rpc protocol
:param \*args,\*\*kwargs: arguments to pass to the default rpc protocol
automatically registered on label 0.
'''
......@@ -67,7 +67,7 @@ class RpcConnection(object):
:param addr: the target ip address
:param port: the target port
:param conn_timeout: the connection operation timeout
:param *args, **kwargs: extra argument to pass to the constructor (see
:param \*args,\*\*kwargs: extra argument to pass to the constructor (see
constructor doctring)
'''
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
......@@ -83,7 +83,7 @@ class RpcConnection(object):
Construct :class:`RpcConnection` instance like :meth:`from_addr`, but
enable ssl on socket.
:param cert: ssl certificate or None for ssl without certificat
:param cert: ssl client certificate or None for ssl without certificat
'''
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(conn_timeout)
......
#!/usr/bin/env python
#coding:utf8
from rpc.client import SimpleRpcClient
from rpc.utils import ConnectionProxy
import socket
import threading
# Initialization of the client socket:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.connect(('127.0.0.1', 1234))
# Create the client objet binded on the socket we create above:
client = SimpleRpcClient(sock)
# Launch the event loop in separated thread:
threading.Thread(target=client.run).start()
# Create the proxy object that allow us to call easily methods on the server:
proxy = ConnectionProxy(client)
print '42 + 42 = ', proxy.add(42, 42)
# You can start this script with -i argument of the python interpreter to call
# methods with proxy interactively.
#!/usr/bin/env python
#coding:utf8
from rpc.server import SimpleRpcServer
import socket
def add(op1, op2):
# This will be printed on server side:
print 'add %s + %s' % (op1, op2)
# This will be returned to the client:
return op1 + op2
handler = {
'add': add
}
# Initialization of the server socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 1234))
sock.listen(5)
# Create the server objet binded on the socket we create above:
server = SimpleRpcServer(sock, default_handler=handler)
# Launch the server's event loop with proper exit when exception is raised:
try:
server.run()
except Exception as err:
print err
server.shutdown()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment