Commit 4eadc7b5 authored by Antoine Millet's avatar Antoine Millet
Browse files

Rewrited sjRpc with low level channel multiplexage and gevent usage.

parent d63729bd
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
#!/usr/bin/env python
#coding:utf8

'''

@@ -11,14 +9,12 @@ The library is separated into four parts:

 * core library contains all common classes.
 * server library contains all the server side related stuff.
 * client library contains all the client side related stuff.
 * utils library contains some helpers used in previous libraries.

'''

import sjrpc.core
import sjrpc.server
import sjrpc.client
import sjrpc.utils

__version__ = 13
__version__ = '14~dev'

sjrpc/client/__init__.py

deleted100644 → 0
+0 −6
Original line number Diff line number Diff line
#!/usr/bin/env python
#coding:utf8

from sjrpc.client.simple import SimpleRpcClient

__all__ = ('SimpleRpcClient',)

sjrpc/client/simple.py

deleted100644 → 0
+0 −109
Original line number Diff line number Diff line
#!/usr/bin/env python
#coding=utf8

import select
import socket
import logging
from sjrpc.core import RpcConnection, ConnectionManager

class SimpleRpcClient(ConnectionManager):
    '''
    Create a new simple RPC client.
    
    :param connect: the :class:`RpcConnection` object to bind the client manager
    :param default_handler: the default handler to bind to the client connection
    :param on_disconnect: method on the handler to call when the client
        disconnects.
    '''

    def __init__(self, connection, default_handler=None, on_disconnect=None):
        super(SimpleRpcClient, self).__init__()
        
        self._on_disconnect = on_disconnect
        self._connection = connection
        self._connection.set_handler(default_handler)
        self.register(self._connection.get_fd(), self._handle_event)

    @classmethod
    def from_addr(cls, addr, port, enable_ssl=False, cert=None, timeout=None,
                  conn_timeout=30.0, default_handler=None, on_disconnect=None):
        '''
        Construct the instance of :class:`SimpleRpcClient` without providing
        the :class:`RpcConnection` object. The :class:`RpcConnection` is
        automatically created and passed to the standard constructor before to
        return the new instance.

        :param addr: the target ip address
        :param port: the target port
        :param ssl: enable SSL
        :param timeout: the global call timeout setting
        :param conn_timeout: the connection operation timeout
        :param cert: is SSL is enabled, profile the filename of certificate to
            check. If None, don't check certificate.
        :param default_handler: the default handler to bind to the
            client connection
        :param on_disconnect: method on the handler to call when the client
            disconnects.
        '''

        connection = RpcConnection.from_addr(addr, port, None, timeout=timeout,
                                             conn_timeout=conn_timeout,
                                             enable_ssl=enable_ssl, cert=cert)
        client = cls(connection, default_handler=default_handler,
                     on_disconnect=on_disconnect)
        connection._manager = client
        return client

    @classmethod
    def from_sock(cls, sock, default_handler=None, on_disconnect=None):
        '''
        Construct the instance of :class:`SimpleRpcClient` without providing
        the :class:`RpcConnection` object. The :class:`RpcConnection` is
        automatically created and passed to the standard constructor before to
        return the new instance

        :param sock: the socket object to wrap with :class:`RpcConnection`
            object.
        :param default_handler: the default handler to bind to the
            client connection
        :param on_disconnect: method on the handler to call when the client
            disconnects.
        '''
        
        connection = RpcConnection(sock, None)
        client = cls(connection, default_handler, on_disconnect)
        connection._manager = client
        return client

    def shutdown(self):
        super(SimpleRpcClient, self).shutdown()
        self._connection.shutdown(self._on_disconnect)

    def _handle_event(self, fd, events):
        if events & select.EPOLLIN:
            # Data are ready to be readed on socket
            try:
                self._connection.receive()
            except socket.error as err:
                logging.debug('Socket error while receiving from the client '
                              'fd/%s: %s', fd, err)
                self.shutdown()

        if events & select.EPOLLOUT:
            # Data are ready to be written on socket
            try:
                self._connection.send()
            except socket.error as err:
                logging.debug('Socket error while sending to the client '
                              'fd/%s: %s', fd, err)
                self.shutdown()

        if events & select.EPOLLHUP:
            logging.debug('Socket HUP fd/%s', fd)
            self.shutdown()

    def all_connections(self):
        return set((self._connection,))

    def call(self, *args, **kwargs):
        return self._connection.call(*args, **kwargs)
+3 −4
Original line number Diff line number Diff line
@@ -2,10 +2,9 @@
#coding:utf8

from sjrpc.core.rpcconnection import *
from sjrpc.core.connectionmanagers import *
from sjrpc.core.callers import *
from sjrpc.core.exceptions import *
from sjrpc.core.async import *

__all__ = ('ConnectionManager', 'RpcConnection', 'RpcCaller', 'RpcError', 
           'ThreadedRpcCaller', )
__all__ = ('RpcConnection', 'RpcCaller', 'ThreadedRpcCaller', 'RpcError',
           'AsyncWatcher')
+36 −21
Original line number Diff line number Diff line
#!/usr/bin/env python
#coding:utf8

import threading

from sjrpc.core.exceptions import RpcError

ERRMSG_RPCERR = ('Unable to send reply to the peer: %s (this error is usualy '
                 'raised when connection is lost while handler function '
                 'execution)')


class RpcCaller(object):
    '''
    A caller execute a callable (function, method, class which implement the
@@ -11,37 +15,47 @@ class RpcCaller(object):
    peer through it :class:`RpcConnection` object.
    '''

    def __init__(self, request, connection, func):
    def __init__(self, request, protocol, func):
        self._request = request
        self._connection = connection
        self._protocol = protocol
        self._func = func

        # Apply the request decorator
        #request_decorator = connection.request_decorator
        #if request_decorator is not None:
        #    self._func = request_decorator(self._func)

    def run(self):
        '''
        Run the callable and return the result (or the exception) to the peer.
        '''
        
        msg_id = self._request['id']
        args = self._request['args']
        kwargs = self._request['kwargs']

        if not getattr(self._func, '__pure__', False):
            args.insert(0, self._connection)

        if getattr(self._func, '__pass_rpc__', False):
            args.insert(0, self._protocol)
        if getattr(self._func, '__pass_connection__', False):
            args.insert(0, self._protocol.connection)
        try:
            returned = self._func(*args, **kwargs)
        except Exception as err:
            self._connection.error(msg_id, message=str(err),
            try:
                self._protocol.error(msg_id, message=str(err),
                                       error=err.__class__.__name__)
            except RpcError as err:
                self._protocol.connection.logger.error(ERRMSG_RPCERR, err)
        else:
            self._connection.response(msg_id, returned=returned)
            try:
                self._protocol.response(msg_id, returned=returned)
            except RpcError as err:
                self._protocol.connection.logger.error(ERRMSG_RPCERR, err)

    def start(self):
        '''
        Start execution of the callable, the most of time, it just call
        :meth:`run` method.
        '''
        
        self.run()


@@ -54,6 +68,7 @@ class ThreadedRpcCaller(RpcCaller):
    def __init__(self, *args, **kwargs):
        super(ThreadedRpcCaller, self).__init__(*args, **kwargs)
        self._thread = threading.Thread(target=self.run)
        self._thread.name = 'Processing of call: %s' % self._request['id']
        self._thread.daemon = True

    def start(self):
Loading