# -*- coding: utf-8 -*- """ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . @author: mkaay """ SERVER_VERSION = "0.4.9" from time import sleep from uuid import uuid4 as uuid from PyQt4.QtCore import * from PyQt4.QtGui import * import socket from module.remote.thriftbackend.ThriftClient import ThriftClient, WrongLogin, NoSSL, NoConnection from thrift.Thrift import TException class Connector(QObject): """ manages the connection to the pyload core via thrift """ firstAttempt = True def __init__(self): QObject.__init__(self) self.mutex = QMutex() self.connectionID = None self.host = None self.port = None self.user = None self.password = None self.ssl = None self.running = True self.internal = False self.proxy = self.Dummy() def setConnectionData(self, host, port, user, password, ssl=False): """ set connection data for connection attempt, called from slotConnect """ self.host = host self.port = port self.user = user self.password = password self.ssl = ssl def connectProxy(self): """ initialize thrift rpc client, check for ssl, check auth, setup dispatcher, connect error signals, check server version """ if self.internal: return True err = None try: client = ThriftClient(self.host, self.port, self.user, self.password) except WrongLogin: err = _("bad login credentials") except NoSSL: err = _("no ssl support") except NoConnection: err = _("can't connect to host") if err: if not Connector.firstAttempt: self.emit(SIGNAL("errorBox"), err) Connector.firstAttempt = False return False self.proxy = DispatchRPC(self.mutex, client) self.connect(self.proxy, SIGNAL("connectionLost"), self, SIGNAL("connectionLost")) server_version = self.proxy.getServerVersion() self.connectionID = uuid().hex if not server_version == SERVER_VERSION: self.emit(SIGNAL("errorBox"), _("server is version %(new)s client accepts version %(current)s") % { "new": server_version, "current": SERVER_VERSION}) return False return True def __getattr__(self, attr): """ redirect rpc calls to dispatcher """ return getattr(self.proxy, attr) class Dummy(object): """ dummy rpc proxy, to prevent errors """ def __nonzero__(self): return False def __getattr__(self, attr): def dummy(*args, **kwargs): return None return dummy class DispatchRPC(QObject): """ wraps the thrift client, to catch critical exceptions (connection lost) adds thread safety """ def __init__(self, mutex, server): QObject.__init__(self) self.mutex = mutex self.server = server def __getattr__(self, attr): """ redirect and wrap call in Wrapper instance, locks dispatcher """ self.mutex.lock() self.fname = attr f = self.Wrapper(getattr(self.server, attr), self.mutex, self) return f class Wrapper(object): """ represents a rpc call """ def __init__(self, f, mutex, dispatcher): self.f = f self.mutex = mutex self.dispatcher = dispatcher def __call__(self, *args, **kwargs): """ instance is called, rpc is executed exceptions are processed finally dispatcher is unlocked """ lost = False try: return self.f(*args, **kwargs) except socket.error: #necessary? lost = True except TException: lost = True finally: self.mutex.unlock() if lost: from traceback import print_exc print_exc() self.dispatcher.emit(SIGNAL("connectionLost"))