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  from node_manager_fkie.common import utf8 
 50   
 51   
52 -class NetworkDiscoveryDialog(QDialog, threading.Thread):
53 54 TIMEOUT = 0.1 55 56 display_clear_signal = Signal() 57 display_append_signal = Signal(str) 58 status_text_signal = Signal(str) 59 network_join_request = Signal(int) 60
61 - def __init__(self, default_mcast_group, default_port, networks_count, parent=None):
62 ''' 63 Creates an input dialog. 64 @param default_port: the default discovery port 65 @type default_port: C{int} 66 @param networks_count: the count of discovering ports 67 @type networks_count: C{int} 68 ''' 69 QDialog.__init__(self, parent=parent) 70 threading.Thread.__init__(self) 71 self.default_port = default_port 72 self.setObjectName('NetworkDiscoveryDialog') 73 self.setAttribute(Qt.WA_DeleteOnClose, True) 74 self.setWindowFlags(Qt.Window) 75 self.setWindowTitle('Network Discovery') 76 self.resize(728, 512) 77 self.verticalLayout = QVBoxLayout(self) 78 self.verticalLayout.setObjectName("verticalLayout") 79 self.verticalLayout.setContentsMargins(1, 1, 1, 1) 80 81 self.display = QTextBrowser(self) 82 self.display.setReadOnly(True) 83 self.verticalLayout.addWidget(self.display) 84 self.display_clear_signal.connect(self.display.clear) 85 self.display_append_signal.connect(self.display.append) 86 self.display.anchorClicked.connect(self.on_anchorClicked) 87 88 self.status_label = QLabel('0 messages', self) 89 self.verticalLayout.addWidget(self.status_label) 90 self.status_text_signal.connect(self.status_label.setText) 91 self._msg_counts = dict() 92 93 self._networks_count = networks_count 94 self._running = True 95 self._received_msgs = 0 96 self._discovered = dict() 97 self._hosts = dict() # resolution for hostname and address 98 self.mutex = threading.RLock() 99 self.sockets = [] 100 with self.mutex: 101 try: 102 for p in range(networks_count): 103 msock = DiscoverSocket(default_port + p, default_mcast_group) 104 self.sockets.append(msock) 105 msock.settimeout(self.TIMEOUT) 106 except Exception as e: 107 self.display.setText(utf8(e)) 108 self.setDaemon(True) 109 self.start()
110
111 - def on_heartbeat_received(self, msg, address, is_multicast):
112 force_update = False 113 with self.mutex: 114 try: 115 hostname = self._hosts[address[0]] 116 except: 117 self.status_text_signal.emit("resolve %s" % address[0]) 118 hostname = nm.nameres().hostname(utf8(address[0]), resolve=True) 119 self._hosts[address[0]] = hostname 120 try: 121 (_version, _msg_tuple) = Discoverer.msg2masterState(msg, address) 122 index = address[1] - self.default_port 123 if index not in self._discovered: 124 self._discovered[index] = dict() 125 self._discovered[index][address] = (hostname, time.time()) 126 if hostname not in self._msg_counts: 127 self._msg_counts[hostname] = 0 128 self._msg_counts[hostname] += 1 129 self._received_msgs += 1 130 force_update = True 131 except: 132 print traceback.format_exc(1) 133 if force_update: 134 self._updateDisplay()
135
136 - def run(self):
137 self.parent().masterlist_service.refresh(self.parent().getMasteruri(), False) 138 while (not rospy.is_shutdown()) and self._running: 139 with self.mutex: 140 for msock in self.sockets: 141 received = True 142 while received: 143 try: 144 recv_item = msock.receive_queue.get(False) 145 self._received_msgs += 1 146 self.on_heartbeat_received(recv_item.msg, recv_item.sender_addr, (recv_item.via == QueueReceiveItem.MULTICAST)) 147 except Queue.Empty: 148 received = False 149 status_text = 'received messages: %d' % (self._received_msgs) 150 self.status_text_signal.emit(status_text) 151 # self.parent().masterlist_service.refresh(self.parent().getMasteruri(), False) 152 time.sleep(3)
153
154 - def closeEvent(self, event):
155 self.stop() 156 QDialog.closeEvent(self, event)
157
158 - def stop(self):
159 self._running = False 160 with self.mutex: 161 for p in range(len(self.sockets)): 162 try: 163 self.sockets[p].close() 164 except: 165 pass
166
167 - def _updateDisplay(self):
168 self.display_clear_signal.emit() 169 text = '<div style="font-family:Fixedsys,Courier,monospace; padding:10px;">\n' 170 for index, addr_dict in self._discovered.items(): 171 text = ''.join([text, 'Network <b>', utf8(index), '</b>: <a href="', utf8(index), '">join</a><dl>']) 172 for addr, (hostname, ts) in addr_dict.items(): 173 text = ''.join([text, '<dt>', self._getTsStr(ts), ' <b><u>', utf8(hostname), '</u></b> ', utf8(addr), ', received messages: ', str(self._msg_counts[hostname]), '</dt>\n']) 174 text = ''.join([text, '</dl><br>']) 175 text = ''.join([text, '</div>']) 176 self.display_append_signal.emit(text)
177
178 - def _getTsStr(self, timestamp):
179 dt = datetime.fromtimestamp(timestamp) 180 diff = time.time() - timestamp 181 diff_dt = datetime.fromtimestamp(diff) 182 before = '0 sec' 183 if (diff < 60): 184 before = diff_dt.strftime('%S sec') 185 elif (diff < 3600): 186 before = diff_dt.strftime('%M:%S min') 187 elif (diff < 86400): 188 before = diff_dt.strftime('%H:%M:%S std') 189 else: 190 before = diff_dt.strftime('%d Day(s) %H:%M:%S') 191 return ''.join([dt.strftime('%H:%M:%S'), ' (', before, ')'])
192
193 - def on_anchorClicked(self, url):
194 self._updateDisplay() 195 try: 196 self.network_join_request.emit(int(url.toString())) 197 except: 198 print traceback.format_exc(1)
199