Package node_manager_fkie
[frames] | no frames]

Source Code for Package node_manager_fkie

  1  #!/usr/bin/env python 
  2  # Software License Agreement (BSD License) 
  3  # 
  4  # Copyright (c) 2012, Fraunhofer FKIE/US, Alexander Tiderko 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions 
  9  # are met: 
 10  # 
 11  #  * Redistributions of source code must retain the above copyright 
 12  #    notice, this list of conditions and the following disclaimer. 
 13  #  * Redistributions in binary form must reproduce the above 
 14  #    copyright notice, this list of conditions and the following 
 15  #    disclaimer in the documentation and/or other materials provided 
 16  #    with the distribution. 
 17  #  * Neither the name of Fraunhofer nor the names of its 
 18  #    contributors may be used to endorse or promote products derived 
 19  #    from this software without specific prior written permission. 
 20  # 
 21  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 22  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 23  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 24  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 25  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 26  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 27  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 28  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 29  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 30  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 31  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 32  # POSSIBILITY OF SUCH DAMAGE. 
 33   
 34  __author__ = "Alexander Tiderko (Alexander.Tiderko@fkie.fraunhofer.de)" 
 35  __copyright__ = "Copyright (c) 2012 Alexander Tiderko, Fraunhofer FKIE/US" 
 36  __license__ = "BSD" 
 37  __version__ = "0.4.1" # git describe --tags --dirty --always 
 38  __date__ = "2015-04-28"    # git log -1 --date=iso 
 39   
 40  import os 
 41  import sys 
 42  import socket 
 43  import threading 
 44  import argparse 
 45   
 46  PKG_NAME = 'node_manager_fkie' 
 47   
 48  import roslib; roslib.load_manifest(PKG_NAME) 
 49  import rospy 
 50  import roslib.network 
 51   
 52  #PYTHONVER = (2, 7, 1) 
 53  #if sys.version_info < PYTHONVER: 
 54  #  print 'For full scope of operation this application requires python version > %s, current: %s' % (str(PYTHONVER), sys.version_info) 
 55   
 56  from settings import Settings 
 57  from start_handler import StartHandler, StartException, BinarySelectionRequest 
 58  from ssh_handler import SSHhandler, AuthenticationRequest 
 59  from screen_handler import ScreenHandler, ScreenSelectionRequest 
 60  from progress_queue import InteractionNeededError 
 61  from name_resolution import NameResolution 
 62  from history import History 
 63  from file_watcher import FileWatcher 
 64  from common import get_ros_home, masteruri_from_ros 
 65  from master_view_proxy import LaunchArgsSelectionRequest 
 66   
 67  HOSTS_CACHE = dict() 
 68  ''' 
 69  the cache directory to store the results of tests for local hosts. 
 70  @see: L{is_local()} 
 71  ''' 
 72   
 73  _lock = threading.RLock() 
 74   
 75  main_form = None 
 76  _settings = None 
 77  _ssh_handler = None 
 78  _screen_handler = None 
 79  _start_handler = None 
 80  _name_resolution = None 
 81  _history = None 
 82  _file_watcher = None 
 83  _file_watcher_param = None 
 84  app = None 
 85   
86 -def settings():
87 ''' 88 @return: The global settings 89 @rtype: L{Settings} 90 ''' 91 global _settings 92 return _settings
93
94 -def ssh():
95 ''' 96 @return: The SSH handler to handle the SSH connections 97 @rtype: L{SSHhandler} 98 ''' 99 global _ssh_handler 100 return _ssh_handler
101
102 -def screen():
103 ''' 104 @return: The screen handler to the screens. 105 @rtype: L{ScreenHandler} 106 @see: U{http://linuxwiki.de/screen} 107 ''' 108 global _screen_handler 109 return _screen_handler
110
111 -def starter():
112 ''' 113 @return: The start handler to handle the start of new ROS nodes on local or 114 remote machines. 115 @rtype: L{StartHandler} 116 ''' 117 global _start_handler 118 return _start_handler
119
120 -def nameres():
121 ''' 122 @return: The name resolution object translate the the name to the host or 123 ROS master URI. 124 @rtype: L{NameResolution} 125 ''' 126 global _name_resolution 127 return _name_resolution
128
129 -def history():
130 ''' 131 @return: The history of entered parameter. 132 @rtype: L{History} 133 ''' 134 global _history 135 return _history
136
137 -def file_watcher():
138 ''' 139 @return: The file watcher object with all loaded configuration files. 140 @rtype: L{FileWatcher} 141 ''' 142 global _file_watcher 143 return _file_watcher
144
145 -def file_watcher_param():
146 ''' 147 @return: The file watcher object with all configuration files referenced by parameter value. 148 @rtype: L{FileWatcher} 149 ''' 150 global _file_watcher_param 151 return _file_watcher_param
152 153
154 -def is_local(hostname, wait=False):
155 ''' 156 Test whether the given host name is the name of the local host or not. 157 @param hostname: the name or IP of the host 158 @type hostname: C{str} 159 @return: C{True} if the hostname is local or None 160 @rtype: C{bool} 161 @raise Exception: on errors while resolving host 162 ''' 163 if (hostname is None): 164 return True 165 with _lock: 166 if hostname in HOSTS_CACHE: 167 if isinstance(HOSTS_CACHE[hostname], threading.Thread): 168 return False 169 return HOSTS_CACHE[hostname] 170 171 try: 172 socket.inet_aton(hostname) 173 local_addresses = ['localhost'] + roslib.network.get_local_addresses() 174 # check 127/8 and local addresses 175 result = hostname.startswith('127.') or hostname in local_addresses 176 with _lock: 177 HOSTS_CACHE[hostname] = result 178 return result 179 except socket.error: 180 # the hostname must be resolved => do it in a thread 181 if wait: 182 result = __is_local(hostname) 183 return result 184 else: 185 thread = threading.Thread(target=__is_local, args=((hostname,))) 186 thread.daemon = True 187 with _lock: 188 HOSTS_CACHE[hostname] = thread 189 thread.start() 190 return False
191
192 -def __is_local(hostname):
193 try: 194 machine_addr = socket.gethostbyname(hostname) 195 except socket.gaierror: 196 import traceback 197 print traceback.format_exc() 198 with _lock: 199 HOSTS_CACHE[hostname] = False 200 return False 201 local_addresses = ['localhost'] + roslib.network.get_local_addresses() 202 # check 127/8 and local addresses 203 result = machine_addr.startswith('127.') or machine_addr in local_addresses 204 with _lock: 205 HOSTS_CACHE[hostname] = result 206 return result
207
208 -def finish(*arg):
209 ''' 210 Callback called on exit of the ros node. 211 ''' 212 # close all ssh sessions 213 global _ssh_handler 214 if not _ssh_handler is None: 215 _ssh_handler.close() 216 global _history 217 if not _history is None: 218 try: 219 _history.storeAll() 220 except Exception as e: 221 print >> sys.stderr, "Error while store history: %s"%e 222 global main_form 223 import main_window 224 if isinstance(main_form, main_window.MainWindow): 225 main_form.finish() 226 global app 227 if not app is None: 228 app.exit()
229 230
231 -def setTerminalName(name):
232 ''' 233 Change the terminal name. 234 @param name: New name of the terminal 235 @type name: C{str} 236 ''' 237 sys.stdout.write("\x1b]2;%s\x07"%name)
238
239 -def setProcessName(name):
240 ''' 241 Change the process name. 242 @param name: New process name 243 @type name: C{str} 244 ''' 245 try: 246 from ctypes import cdll, byref, create_string_buffer 247 libc = cdll.LoadLibrary('libc.so.6') 248 buff = create_string_buffer(len(name)+1) 249 buff.value = name 250 libc.prctl(15, byref(buff), 0, 0, 0) 251 except: 252 pass
253
254 -def init_settings():
255 global _settings 256 _settings = Settings()
257
258 -def init_globals(masteruri):
259 # initialize the global handler 260 global _ssh_handler 261 global _screen_handler 262 global _start_handler 263 global _name_resolution 264 global _history 265 global _file_watcher 266 global _file_watcher_param 267 _ssh_handler = SSHhandler() 268 _screen_handler = ScreenHandler() 269 _start_handler = StartHandler() 270 _name_resolution = NameResolution() 271 _history = History() 272 _file_watcher = FileWatcher() 273 _file_watcher_param = FileWatcher() 274 275 # test where the roscore is running (local or remote) 276 __is_local('localhost') ## fill cache 277 return __is_local(_name_resolution.getHostname(masteruri)) ## fill cache
278
279 -def init_arg_parser():
280 parser = argparse.ArgumentParser() 281 parser.add_argument("--version", action="version", version="%s %s" % ( "%(prog)s", __version__)) 282 parser.add_argument("-f", "--file", nargs=1, help="loads the given file as default on start") 283 284 group = parser.add_argument_group('echo') 285 group.add_argument("--echo", nargs=2, help="starts an echo dialog instead of node manager", metavar=('name', 'type')) 286 group.add_argument("--hz", action="store_true", help="shows only the Hz value instead of topic content in echo dialog") 287 group.add_argument("--ssh", action="store_true", help="connects via SSH") 288 289 return parser
290
291 -def init_echo_dialog(prog_name, masteruri, topic_name, topic_type, hz=False, use_ssh=False):
292 # start ROS-Master, if not currently running 293 StartHandler._prepareROSMaster(masteruri) 294 name = ''.join([prog_name, '_echo']) 295 rospy.init_node(name, anonymous=True, log_level=rospy.INFO) 296 setTerminalName(name) 297 setProcessName(name) 298 import echo_dialog 299 global _ssh_handler 300 _ssh_handler = SSHhandler() 301 return echo_dialog.EchoDialog(topic_name, topic_type, hz, masteruri, use_ssh=use_ssh)
302
303 -def init_main_window(prog_name, masteruri, launch_files=[]):
304 # start ROS-Master, if not currently running 305 StartHandler._prepareROSMaster(masteruri) 306 # setup the loglevel 307 try: 308 log_level = getattr(rospy, rospy.get_param('/%s/log_level'%prog_name, "INFO")) 309 except Exception as e: 310 print "Error while set the log level: %s\n->INFO level will be used!"%e 311 log_level = rospy.INFO 312 rospy.init_node(prog_name, anonymous=False, log_level=log_level) 313 setTerminalName(prog_name) 314 setProcessName(prog_name) 315 import main_window 316 local_master = init_globals(masteruri) 317 return main_window.MainWindow(launch_files, not local_master, launch_files)
318 319 #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 320 #%%%%%%%%%%%%% MAIN %%%%%%%% 321 #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 322
323 -def main(name):
324 try: 325 from python_qt_binding import QtGui 326 except: 327 print >> sys.stderr, "please install 'python_qt_binding' package!!" 328 sys.exit(-1) 329 330 init_settings() 331 masteruri = settings().masteruri() 332 parser = init_arg_parser() 333 args = rospy.myargv(argv=sys.argv) 334 parsed_args = parser.parse_args(args[1:]) 335 # Initialize Qt 336 global app 337 app = QtGui.QApplication(sys.argv) 338 339 # decide to show main or echo dialog 340 global main_form 341 try: 342 if parsed_args.echo: 343 main_form = init_echo_dialog(name, masteruri, parsed_args.echo[0], parsed_args.echo[1], parsed_args.hz, parsed_args.ssh) 344 else: 345 main_form = init_main_window(name, masteruri, parsed_args.file) 346 except Exception as e: 347 sys.exit("%s"%e) 348 349 exit_code = 0 350 # resize and show the qt window 351 if not rospy.is_shutdown(): 352 os.chdir(settings().PACKAGE_DIR) # change path to be able to the images of descriptions 353 # main_form.resize(1024, 720) 354 screen_size = QtGui.QApplication.desktop().availableGeometry() 355 if main_form.size().width() >= screen_size.width() or main_form.size().height() >= screen_size.height()-24: 356 main_form.showMaximized() 357 else: 358 main_form.show() 359 exit_code = -1 360 rospy.on_shutdown(finish) 361 exit_code = app.exec_() 362 return exit_code
363