From dfcbaa8c2884049c187dcd2b6105529d342cd526 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Thu, 16 Oct 2014 19:28:51 -0700 Subject: [PATCH] Add socket timer for lost connections --- openlp/core/lib/projector/pjlink1.py | 56 +++++++++++++++++----------- openlp/core/ui/projector/manager.py | 10 +++++ 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index 8c05d7b06..e82212215 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -150,6 +150,7 @@ class PJLink1(QTcpSocket): self.timer = None # Timer that calls the poll_loop self.send_queue = [] self.send_busy = False + self.socket_timer = None # Test for send_busy and brain-dead projectors # Map command returned to function self.PJLINK1_FUNC = {'AVMT': self.process_avmt, 'CLSS': self.process_clss, @@ -166,6 +167,7 @@ class PJLink1(QTcpSocket): } def reset_information(self): + log.debug('(%s) reset_information() connect status is %s' % (self.ip, self.state())) self.power = S_OFF self.pjlink_name = None self.manufacturer = None @@ -179,6 +181,10 @@ class PJLink1(QTcpSocket): self.other_info = None if hasattr(self, 'timer'): self.timer.stop() + if hasattr(self, 'socket_timer'): + self.socket_timer.stop() + self.send_queue = [] + self.send_busy = False def thread_started(self): """ @@ -215,6 +221,13 @@ class PJLink1(QTcpSocket): self.deleteLater() self.i_am_running = False + def socket_abort(self): + """ + Aborts connection and closes socket in case of brain-dead projectors. + """ + log.debug('(%s) socket_abort() - Killing connection' % self.ip) + self.disconnect_from_host(abort=True) + def poll_loop(self): """ Called by QTimer in ProjectorManager.ProjectorItem. @@ -362,10 +375,6 @@ class PJLink1(QTcpSocket): @pyqtSlot() def get_data(self): - log.debug('(%s) get_data() Received readyRead signal' % self.ip) - return self._get_data() - - def _get_data(self): """ Socket interface to retrieve data. """ @@ -379,6 +388,7 @@ class PJLink1(QTcpSocket): log.debug('(%s) get_data(): No data available (-1)' % self.ip) self.projectorReceivedData.emit() return + self.socket_timer.stop() self.projectorNetwork.emit(S_NETWORK_RECEIVED) data_in = decode(read, 'ascii') data = data_in.strip() @@ -432,6 +442,9 @@ class PJLink1(QTcpSocket): else: self.change_status(E_NETWORK, self.errorString()) self.projectorUpdateIcons.emit() + if self.status_connect == E_NOT_CONNECTED: + self.abort() + self.reset_information() return def send_command(self, cmd, opts='?', salt=None, queue=False): @@ -455,24 +468,18 @@ class PJLink1(QTcpSocket): # Already there, so don't add log.debug('(%s) send_command(out="%s") Already in queue - skipping' % (self.ip, out.strip())) elif not queue and len(self.send_queue) == 0: - - return self._send_string(out) + return self._send_command(data=out) else: log.debug('(%s) send_command(out="%s") adding to queue' % (self.ip, out.strip())) self.send_queue.append(out) - if not self.send_busy: - self.projectorReceivedData.emit() + self.projectorReceivedData.emit() log.debug('(%s) send_command(): send_busy is %s' % (self.ip, self.send_busy)) if not self.send_busy: log.debug('(%s) send_command() calling _send_string()') - self._send_string() + self._send_command() @pyqtSlot() - def _send_command(self): - log.debug('Received projectorReceivedData signal') - return self._send_string() - - def _send_string(self, data=None): + def _send_command(self, data=None): """ Socket interface to send data. If data=None, then check queue. @@ -480,6 +487,7 @@ class PJLink1(QTcpSocket): :returns: None """ log.debug('(%s) _send_string()' % self.ip) + log.debug('(%s) _send_string(): Connection status: %s' % (self.ip, self.state())) if self.state() != self.ConnectedState: log.debug('(%s) _send_string() Not connected - abort' % self.ip) self.send_queue = [] @@ -502,6 +510,7 @@ class PJLink1(QTcpSocket): self.send_busy = True log.debug('(%s) _send_string(): Sending "%s"' % (self.ip, out.strip())) log.debug('(%s) _send_string(): Queue = %s' % (self.ip, self.send_queue)) + self.socket_timer.start() try: self.projectorNetwork.emit(S_NETWORK_SENDING) sent = self.write(out) @@ -511,7 +520,7 @@ class PJLink1(QTcpSocket): self.change_status(E_NETWORK, translate('OpenLP.PJLink1', 'Error while sending data to projector')) except SocketError as e: - self.disconnect_from_host() + self.disconnect_from_host(abort=True) self.changeStatus(E_NETWORK, '%s : %s' % (e.error(), e.errorString())) def process_command(self, cmd, data): @@ -734,20 +743,25 @@ class PJLink1(QTcpSocket): self.connectToHost(self.ip, self.port if type(self.port) is int else int(self.port)) @pyqtSlot() - def disconnect_from_host(self): + def disconnect_from_host(self, abort=False): """ Close socket and cleanup. """ - if self.state() != self.ConnectedState: - log.warn('(%s) disconnect_from_host(): Not connected - returning' % self.ip) - self.projectorUpdateIcons.emit() - return + if abort or self.state() != self.ConnectedState: + if abort: + log.warn('(%s) disconnect_from_host(): Aborting connection' % self.ip) + else: + log.warn('(%s) disconnect_from_host(): Not connected - returning' % self.ip) + self.reset_information() self.disconnectFromHost() try: self.readyRead.disconnect(self.get_data) except TypeError: pass - self.change_status(S_NOT_CONNECTED) + if abort: + self.change_status(E_NOT_CONNECTED) + else: + self.change_status(S_NOT_CONNECTED) self.reset_information() self.projectorUpdateIcons.emit() diff --git a/openlp/core/ui/projector/manager.py b/openlp/core/ui/projector/manager.py index 5b35baf21..330d530d8 100644 --- a/openlp/core/ui/projector/manager.py +++ b/openlp/core/ui/projector/manager.py @@ -487,6 +487,11 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ProjectorMa projector.timer.timeout.disconnect(projector.link.poll_loop) except (AttributeError, TypeError): pass + try: + projector.socket_timer.stop() + projector.socket_timer.timeout.disconnect(projector.link.socket_abort) + except (AttributeError, TypeError): + pass projector.thread.quit() new_list = [] for item in self.projector_list: @@ -727,9 +732,14 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ProjectorMa timer.setInterval(self.poll_time) timer.timeout.connect(item.link.poll_loop) item.timer = timer + socket_timer = QtCore.QTimer(self) + socket_timer.setInterval(5000) # % second timer in case of brain-dead projectors + socket_timer.timeout.connect(item.link.socket_abort) + item.socket_timer = socket_timer thread.start() item.thread = thread item.link.timer = timer + item.link.socket_timer = socket_timer item.link.widget = item.widget self.projector_list.append(item) if self.autostart: