Package node_manager_fkie :: Module network_discovery_dialog
[frames] | no frames]

Source Code for Module node_manager_fkie.network_discovery_dialog

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2012, Fraunhofer FKIE/US, Alexander Tiderko 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Fraunhofer nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32   
 33  import Queue 
 34  from datetime import datetime 
 35  from python_qt_binding.QtCore import Qt, Signal 
 36  try: 
 37      from python_qt_binding.QtGui import QDialog, QLabel, QTextBrowser, QVBoxLayout 
 38  except: 
 39      from python_qt_binding.QtWidgets import QDialog, QLabel, QTextBrowser, QVBoxLayout 
 40  import threading 
 41  import time 
 42  import traceback 
 43   
 44  import rospy 
 45   
 46  from master_discovery_fkie.master_discovery import Discoverer 
 47  from master_discovery_fkie.udp import DiscoverSocket, QueueReceiveItem 
 48  import node_manager_fkie as nm 
 49   
 50   
51 -class NetworkDiscoveryDialog(QDialog, threading.Thread):
52 53 TIMEOUT = 0.1 54 55 display_clear_signal = Signal() 56 display_append_signal = Signal(str) 57 status_text_signal = Signal(str) 58 network_join_request = Signal(int) 59
60 - def __init__(self, default_mcast_group, default_port, networks_count, parent=None):
61 ''' 62 Creates an input dialog. 63 @param default_port: the default discovery port 64 @type default_port: C{int} 65 @param networks_count: the count of discovering ports 66 @type networks_count: C{int} 67 ''' 68 QDialog.__init__(self, parent=parent) 69 threading.Thread.__init__(self) 70 self.default_port = default_port 71 self.setObjectName('NetworkDiscoveryDialog') 72 self.setAttribute(Qt.WA_DeleteOnClose, True) 73 self.setWindowFlags(Qt.Window) 74 self.setWindowTitle('Network Discovery') 75 self.resize(728, 512) 76 self.verticalLayout = QVBoxLayout(self) 77 self.verticalLayout.setObjectName("verticalLayout") 78 self.verticalLayout.setContentsMargins(1, 1, 1, 1) 79 80 self.display = QTextBrowser(self) 81 self.display.setReadOnly(True) 82 self.verticalLayout.addWidget(self.display) 83 self.display_clear_signal.connect(self.display.clear) 84 self.display_append_signal.connect(self.display.append) 85 self.display.anchorClicked.connect(self.on_anchorClicked) 86 87 self.status_label = QLabel('0 messages', self) 88 self.verticalLayout.addWidget(self.status_label) 89 self.status_text_signal.connect(self.status_label.setText) 90 self._msg_counts = dict() 91 92 self._networks_count = networks_count 93 self._running = True 94 self._received_msgs = 0 95 self._discovered = dict() 96 self._hosts = dict() # resolution for hostname and address 97 self.mutex = threading.RLock() 98 self.sockets = [] 99 with self.mutex: 100 for p in range(networks_count): 101 msock = DiscoverSocket(default_port + p, default_mcast_group) 102 self.sockets.append(msock) 103 msock.settimeout(self.TIMEOUT) 104 self.setDaemon(True) 105 self.start()
106
107 - def on_heartbeat_received(self, msg, address, is_multicast):
108 force_update = False 109 with self.mutex: 110 try: 111 hostname = self._hosts[address[0]] 112 except: 113 self.status_text_signal.emit("resolve %s" % address[0]) 114 hostname = nm.nameres().hostname(str(address[0]), resolve=True) 115 self._hosts[address[0]] = hostname 116 try: 117 (_version, _msg_tuple) = Discoverer.msg2masterState(msg, address) 118 index = address[1] - self.default_port 119 if index not in self._discovered: 120 self._discovered[index] = dict() 121 self._discovered[index][address] = (hostname, time.time()) 122 if hostname not in self._msg_counts: 123 self._msg_counts[hostname] = 0 124 self._msg_counts[hostname] += 1 125 self._received_msgs += 1 126 force_update = True 127 except: 128 print traceback.format_exc(1) 129 if force_update: 130 self._updateDisplay()
131
132 - def run(self):
133 self.parent().masterlist_service.refresh(self.parent().getMasteruri(), False) 134 while (not rospy.is_shutdown()) and self._running: 135 with self.mutex: 136 for msock in self.sockets: 137 received = True 138 while received: 139 try: 140 recv_item = msock.receive_queue.get(False) 141 self._received_msgs += 1 142 self.on_heartbeat_received(recv_item.msg, recv_item.sender_addr, (recv_item.via == QueueReceiveItem.MULTICAST)) 143 except Queue.Empty: 144 received = False 145 status_text = 'received messages: %d' % (self._received_msgs) 146 self.status_text_signal.emit(status_text) 147 # self.parent().masterlist_service.refresh(self.parent().getMasteruri(), False) 148 time.sleep(3)
149
150 - def closeEvent(self, event):
151 self.stop() 152 QDialog.closeEvent(self, event)
153
154 - def stop(self):
155 self._running = False 156 with self.mutex: 157 for p in range(len(self.sockets)): 158 try: 159 self.sockets[p].close() 160 except: 161 pass
162
163 - def _updateDisplay(self):
164 self.display_clear_signal.emit() 165 text = '<div style="font-family:Fixedsys,Courier,monospace; padding:10px;">\n' 166 for index, addr_dict in self._discovered.items(): 167 text = ''.join([text, 'Network <b>', str(index), '</b>: <a href="', str(index), '">join</a><dl>']) 168 for addr, (hostname, ts) in addr_dict.items(): 169 text = ''.join([text, '<dt>', self._getTsStr(ts), ' <b><u>', str(hostname), '</u></b> ', str(addr), ', received messages: ', str(self._msg_counts[hostname]), '</dt>\n']) 170 text = ''.join([text, '</dl><br>']) 171 text = ''.join([text, '</div>']) 172 self.display_append_signal.emit(text)
173
174 - def _getTsStr(self, timestamp):
175 dt = datetime.fromtimestamp(timestamp) 176 diff = time.time() - timestamp 177 diff_dt = datetime.fromtimestamp(diff) 178 before = '0 sec' 179 if (diff < 60): 180 before = diff_dt.strftime('%S sec') 181 elif (diff < 3600): 182 before = diff_dt.strftime('%M:%S min') 183 elif (diff < 86400): 184 before = diff_dt.strftime('%H:%M:%S std') 185 else: 186 before = diff_dt.strftime('%d Day(s) %H:%M:%S') 187 return ''.join([dt.strftime('%H:%M:%S'), ' (', before, ')'])
188
189 - def on_anchorClicked(self, url):
190 self._updateDisplay() 191 try: 192 self.network_join_request.emit(int(url.toString())) 193 except: 194 print traceback.format_exc(1)
195