Example #1
0
class Session(object):
    LoggedIn = 0
    Exception = 2
    InvalidCredentials = 3
    session_limit = 30
    conn_timeout = 30.0 # limit of seconds to wait for a free connection
    
    def _create_connection(self):
        assert self.url, "Cannot create session connections before login"
        if len(self.connections) > self.session_limit:
            return None # but don't break the loop
        newconn = createConnection(self.url, self.allow_xmlrpc2)
        newconn.login(self.databaseName, self.userName, self.passwd)
        return newconn
        
    def _check_connection(self, conn):
        return conn.check()

    def __init__(self):
        self.open = False
        self.url = None
        #self.password = None
        self.uid = None
        self.context = {}
        self.userName = None
        self.passwd = None
        self.databaseName = None
        self.allow_xmlrpc2 = True
        self.threads = []
        self.server_options = []
        self.connections = Pool(iter(self._create_connection, NotImplemented),
                                self._check_connection)
        self._log = logging.getLogger('RPC.Session')

    ## @brief Calls the specified method
    # on the given object on the server. 
    #
    # If there is an error during the call it simply rises an exception. See 
    # execute() if you want exceptions to be handled by the notification mechanism.
    # @param obj Object name (string) that contains the method
    # @param method Method name (string) to call 
    # @param args Argument list for the given method
    def call(self, obj, method, *args):
        if not self.open:
            raise RpcException(_('Not logged in'))
        conn = self.connections.borrow(self.conn_timeout)
        try:
            value = conn.call(obj, method, args)
        finally:
            self.connections.free(conn)
        return value

    ## @brief Same as call() but uses the notify mechanism to notify
    # exceptions. 
    #
    # Note that you'll need to bind gettext as texts sent to
    # the notify module are localized.
    def execute(self, obj, method, *args):
        return self.call(obj, method, *args)


    def login(self, url):
        """Logs in the given server with specified name and password.
            @param url dictionary of connection parameters
            Returns Session.Exception, Session.InvalidCredentials or Session.LoggedIn
        """
        if self.url and url != self.url:
            # perhaps a different server, retry for XML-RPC v2
            self.allow_xmlrpc2 = True

        conn = createConnection(url, allow_xmlrpc2=self.allow_xmlrpc2 )
        user = url['user']
        password = url['passwd']
        db = url['dbname']

        for ttry in (1, 2):
            res = False
            try:
                res = conn.login(db, user, password)
                if res:
                    self._log.info('Logged into %s as %s', db, user)
                break
            except socket.error, e:
                return Session.Exception
            except tiny_socket.ProtocolError, e:
                if e.errcode == 404 and isinstance(conn, XmlRpc2Connection):
                    conn = createConnection(url, allow_xmlrpc2=False)
                    self.allow_xmlrpc2 = False
                    self._log.info("Server must be older, retrying with XML-RPC v.1")
                    continue
                self._log.error('Protocol error: %s', e)
                return Session.InvalidCredentials
            except Exception, e:
                self._log.exception("login call exception:")
                return Session.Exception