class BEConnection( object ): """ This is the basic backend connection object. You probably don't want to use this directly. """ logmodule = 'Python Backend Connection' def __init__(self, backend, port, localname=None, blockshutdown=False, timeout=10.0): self.connected = False self.log = MythLog(self.logmodule) self._socklock = allocate_lock() self.host = backend self.port = port self.hostname = None self.deadline = timeout self.blockshutdown = blockshutdown self.localname = localname if self.localname is None: self.localname = socket.gethostname() try: self.connect() except socket.error, e: self.log.logTB(MythLog.SOCKET) self.connected = False self.log(MythLog.GENERAL, MythLog.CRIT, "Couldn't connect to backend [%s]:%d" \ % (self.host, self.port)) raise MythBEError(MythError.PROTO_CONNECTION, self.host, self.port) except:
class BEConnection(object): """ This is the basic backend connection object. You probably don't want to use this directly. """ logmodule = 'Python Backend Connection' def __init__(self, backend, port, localname=None, blockshutdown=False, timeout=10.0): self.connected = False self.log = MythLog(self.logmodule) self._socklock = allocate_lock() self.host = backend self.port = port self.hostname = None self.deadline = timeout self.blockshutdown = blockshutdown self.localname = localname if self.localname is None: self.localname = socket.gethostname() try: self.connect() except socket.error as e: self.log.logTB(MythLog.SOCKET) self.connected = False self.log(MythLog.GENERAL, MythLog.CRIT, "Couldn't connect to backend [%s]:%d" \ % (self.host, self.port)) raise MythBEError(MythError.PROTO_CONNECTION, self.host, self.port) except: raise def __del__(self): self.disconnect() def connect(self): if self.connected: return self.log(MythLog.SOCKET | MythLog.NETWORK, MythLog.INFO, "Connecting to backend [%s]:%d" % (self.host, self.port)) if ':' in self.host: self.socket = deadlinesocket(socket.AF_INET6, socket.SOCK_STREAM) else: self.socket = deadlinesocket(socket.AF_INET, socket.SOCK_STREAM) self.socket.log = self.log self.socket.connect((self.host, self.port)) self.socket.setdeadline(self.deadline) self.connected = True self.check_version() self.announce() def disconnect(self, hard=False): if not self.connected: return self.log(MythLog.SOCKET | MythLog.NETWORK, MythLog.INFO, "Terminating connection to [%s]:%d" % (self.host, self.port)) if not hard: self.backendCommand('DONE', 0) self.connected = False self.socket.shutdown(1) self.socket.close() def reconnect(self, hard=False): self.disconnect(hard) self.connect() def announce(self): # set type, 'Playback' blocks backend shutdown type = ('Monitor', 'Playback')[self.blockshutdown] res = self.backendCommand('ANN %s %s 0' % (type, self.localname)) if res != 'OK': self.log(MythLog.GENERAL, MythLog.ERR, "Unexpected answer to ANN", res) raise MythBEError(MythError.PROTO_ANNOUNCE, self.host, self.port, res) else: self.log(MythLog.SOCKET, MythLog.INFO, "Successfully connected to backend", "[%s]:%d" % (self.host, self.port)) self.hostname = self.backendCommand('QUERY_HOSTNAME') def check_version(self): res = self.backendCommand('MYTH_PROTO_VERSION %s %s' \ % (PROTO_VERSION, PROTO_TOKEN)).split(BACKEND_SEP) if res[0] == 'REJECT': self.log(MythLog.GENERAL, MythLog.ERR, "Backend has version %s, and we speak %s" %\ (res[1], PROTO_VERSION)) raise MythBEError(MythError.PROTO_MISMATCH, int(res[1]), PROTO_VERSION) def backendCommand(self, data, deadline=None): """ obj.backendCommand(data=None, timeout=None) -> response string Sends a formatted command via a socket to the mythbackend. 'timeout' will override the default timeout given when the object was created. If 'data' is None, the method will return any events in the receive buffer. """ # return if not connected if not self.connected: return u'' # pull default timeout if deadline is None: deadline = self.socket.getdeadline() if deadline < 1000: deadline += time() try: # lock socket access with self._socklock: # send command string self.socket.sendheader(data.encode("utf-8")) # wait timeout for data to be received on the socket t = time() timeout = (deadline - t) if (deadline - t > 0) else 0.0 if len(select([self.socket], [], [], timeout)[0]) == 0: # no data, return return u'' res = self.socket.recvheader(deadline=deadline) # convert to unicode try: res = str(''.join([res]), 'utf8') except: res = u''.join([res]) return res except MythError as e: if e.sockcode == 54: # remote has closed connection, attempt reconnect self.reconnect(True) return self.backendCommand(data, deadline) else: raise def blockShutdown(self): if not self.blockshutdown: self.backendCommand('BLOCK_SHUTDOWN') self.blockshutdown = True def unblockShutdown(self): if self.blockshutdown: self.backendCommand('ALLOW_SHUTDOWN') self.blockshutdown = False