38 if sys.version_info[0] == 3:
39 import _thread
as thread
49 import roslaunch.config
51 import roslaunch.parent
53 import roslaunch.xmlloader
55 import roslaunch.loader
56 from std_srvs.srv
import Empty, EmptyResponse
58 from .app
import AppDefinition, find_resource, load_AppDefinition_by_name
59 from .exceptions
import LaunchException, AppException, InvalidAppException, NotFoundException
60 from .master_sync
import MasterSync
61 from .msg
import App, AppList, StatusCodes, AppStatus, AppInstallationState, ExchangeApp
62 from .srv
import StartApp, StopApp, ListApps, ListAppsResponse, StartAppResponse, StopAppResponse, InstallApp, UninstallApp, GetInstallationState, UninstallAppResponse, InstallAppResponse, GetInstallationStateResponse, GetAppDetails, GetAppDetailsResponse
66 roslaunch_files, port, roslaunch_strs=
None, loader=
None, verbose=
False,
67 assign_machines=
True, ignore_unset_args=
False 69 config = roslaunch.config.ROSLaunchConfig()
71 config.master.uri = rosgraph.network.create_local_xmlrpc_uri(port)
73 loader = loader
or roslaunch.xmlloader.XmlLoader()
74 loader.ignore_unset_args = ignore_unset_args
79 roslaunch.config.load_roscore(loader, config, verbose=verbose)
82 for f
in roslaunch_files:
83 if isinstance(f, tuple):
88 rospy.loginfo(
'loading config file %s' % f)
89 loader.load(f, config, argv=args, verbose=verbose)
90 except roslaunch.xmlloader.XmlParseException
as e:
91 raise roslaunch.core.RLException(e)
92 except roslaunch.loader.LoadException
as e:
93 raise roslaunch.core.RLException(e)
97 for launch_str
in roslaunch_strs:
99 rospy.loginfo(
'loading config file from string')
100 loader.load_string(launch_str, config)
101 except roslaunch.xmlloader.XmlParseException
as e:
102 raise roslaunch.core.RLException(
103 'Launch string: %s\nException: %s' % (launch_str, e))
104 except roslaunch.loader.LoadException
as e:
105 raise roslaunch.core.RLException(
106 'Launch string: %s\nException: %s' % (launch_str, e))
109 config.assign_machines()
115 roslaunch.config.load_config_default = _load_config_default
121 self, robot_name, interface_master, app_list,
122 exchange, plugins=
None, enable_app_replacement=
True,
132 rospy.loginfo(
"Starting app manager for %s"%self.
_robot_name)
138 self.
scoped_name(
'application/app_status'), AppStatus,
139 latch=
True, queue_size=1)
142 latch=
True, queue_size=1)
162 local_service_names=service_names,
163 local_pub_names=pub_names)
174 roslaunch.pmon._init_signal_handlers()
177 self._exchange.update_local()
179 self._app_list.update()
185 self._api_sync.stop()
187 self._interface_sync.stop()
200 self._list_apps_pub.publish([app], self._app_list.get_app_list())
202 self._list_apps_pub.publish([], self._app_list.get_app_list())
205 return rosgraph.names.canonicalize_name(
'/%s/%s'%(self.
_robot_name, rospy.remap_name(name)))
208 return GetAppDetailsResponse(app=self._exchange.get_app_details(req.name))
213 if (req.remote_update):
214 rospy.loginfo(
"UPDATE")
215 if (
not self._exchange.update()):
217 i_apps = self._exchange.get_installed_apps()
218 a_apps = self._exchange.get_available_apps()
219 return GetInstallationStateResponse(installed_apps=i_apps, available_apps=a_apps)
223 self._list_apps_pub.publish([self.
_current_app], self._app_list.get_app_list())
225 self._list_apps_pub.publish([], self._app_list.get_app_list())
230 i_apps = self._exchange.get_installed_apps()
231 a_apps = self._exchange.get_available_apps()
232 self._exchange_list_apps_pub.publish(i_apps, a_apps)
236 if (self._exchange.install_app(appname)):
237 self._app_list.update()
240 return InstallAppResponse(installed=
True, message=
"app [%s] installed"%(appname))
242 return InstallAppResponse(installed=
False, message=
"app [%s] could not be installed"%(appname))
246 if (self._exchange.uninstall_app(appname)):
247 self._app_list.update()
250 return UninstallAppResponse(uninstalled=
True, message=
"app [%s] uninstalled"%(appname))
252 return UninstallAppResponse(uninstalled=
False, message=
"app [%s] could not be uninstalled"%(appname))
255 rospy.loginfo(
"Listing apps")
258 running_apps = [current]
261 self._app_list.update()
262 rospy.loginfo(
"done listing apps")
263 return ListAppsResponse(running_apps=running_apps, available_apps=self._app_list.get_app_list())
266 rospy.loginfo(
"start_app: %s"%(req.name))
268 if self._current_app_definition.name == req.name:
269 return StartAppResponse(started=
True, message=
"app [%s] already started"%(req.name), namespace=self.
_app_interface)
271 return StartAppResponse(
273 message=
"app [%s] is denied because app [%s] is already running." 274 % (req.name, self._current_app_definition.name),
276 error_code=StatusCodes.MULTIAPP_NOT_SUPPORTED)
278 self.
stop_app(self._current_app_definition.name)
283 rospy.loginfo(
"Loading app: %s"%(appname))
286 except ValueError
as e:
287 return StartAppResponse(started=
False, message=str(e), error_code=StatusCodes.BAD_REQUEST)
288 except InvalidAppException
as e:
289 return StartAppResponse(started=
False, message=str(e), error_code=StatusCodes.INTERNAL_ERROR)
290 except NotFoundException
as e:
291 return StartAppResponse(started=
False, message=str(e), error_code=StatusCodes.NOT_FOUND)
296 rospy.loginfo(
"Launching: %s"%(app.launch))
297 self._status_pub.publish(AppStatus(AppStatus.INFO,
'launching %s'%(app.display_name)))
299 plugin_launch_files = []
302 if 'start_plugin_order' in app.plugin_order:
303 plugin_names = [p[
'name']
for p
in app.plugins]
304 plugin_order = app.plugin_order[
'start_plugin_order']
305 if len(set(plugin_names) - set(plugin_order)) > 0:
307 "Some plugins are defined in plugins but not written in start_plugin_order: {}" 308 .format(set(plugin_names) - set(plugin_order)))
310 for plugin_name
in plugin_order:
311 if plugin_name
not in plugin_names:
312 rospy.logerr(
"app plugin '{}' not found in app file.".format(plugin_name))
315 app.plugins[plugin_names.index(plugin_name)])
317 app_plugins = app.plugins
318 for app_plugin
in app_plugins:
319 app_plugin_type = app_plugin[
'type']
322 p
for p
in self.
_plugins if p[
'name'] == app_plugin_type)
323 self._current_plugins.append((app_plugin, plugin))
324 if 'launch' in plugin
and plugin[
'launch']:
327 if 'launch_args' in app_plugin:
328 launch_args.update(app_plugin[
'launch_args'])
329 if 'launch_arg_yaml' in app_plugin:
330 with open(app_plugin[
'launch_arg_yaml'])
as yaml_f:
331 yaml_launch_args = yaml.load(yaml_f)
332 for k, v
in yaml_launch_args.items():
334 rospy.logwarn(
"'{}' is set both in launch_args and launch_arg_yaml".format(k))
335 rospy.logwarn(
"'{}' is overwritten: {} -> {}".format(k, launch_args[k], v))
337 plugin_launch_args = []
338 for k, v
in launch_args.items():
339 if isinstance(v, list):
340 v =
" ".join(map(str, v))
341 plugin_launch_args.append(
"{}:={}".format(k, v))
343 "Launching plugin: {} {}".format(
344 plugin_launch_file, plugin_launch_args))
345 plugin_launch_files.append(
346 (plugin_launch_file, plugin_launch_args))
347 except StopIteration:
349 'There is no available app_manager plugin: {}' 350 .format(app_plugin_type))
353 self.
_launch = roslaunch.parent.ROSLaunchParent(
354 rospy.get_param(
"/run_id"), [app.launch],
355 is_core=
False, process_listeners=())
356 if len(plugin_launch_files) > 0:
358 rospy.get_param(
"/run_id"), plugin_launch_files,
359 is_core=
False, process_listeners=())
361 self._launch._load_config()
363 self._plugin_launch._load_config()
366 for N
in self._launch.config.nodes:
367 for t
in app.interface.published_topics.keys():
369 for t
in app.interface.subscribed_topics.keys():
376 if 'module' in plugin
and plugin[
'module']:
378 start_plugin_args = {}
379 if 'plugin_args' in app_plugin:
380 plugin_args.update(app_plugin[
'plugin_args'])
381 if 'plugin_arg_yaml' in app_plugin:
382 with open(app_plugin[
'plugin_arg_yaml'])
as yaml_f:
383 yaml_plugin_args = yaml.load(yaml_f)
384 for k, v
in yaml_plugin_args.items():
386 rospy.logwarn(
"'{}' is set both in plugin_args and plugin_arg_yaml".format(k))
387 rospy.logwarn(
"'{}' is overwritten: {} -> {}".format(k, plugin_args[k], v))
389 if 'start_plugin_args' in app_plugin:
390 start_plugin_args.update(app_plugin[
'start_plugin_args'])
391 if 'start_plugin_arg_yaml' in app_plugin:
392 with open(app_plugin[
'start_plugin_arg_yaml'])
as yaml_f:
393 yaml_plugin_args = yaml.load(yaml_f)
394 for k, v
in yaml_plugin_args.items():
395 if k
in start_plugin_args:
396 rospy.logwarn(
"'{}' is set both in start_plugin_args and start_plugin_arg_yaml".format(k))
397 rospy.logwarn(
"'{}' is overwritten: {} -> {}".format(k, start_plugin_args[k], v))
398 start_plugin_args[k] = v
399 plugin_args.update(start_plugin_args)
400 mod = __import__(plugin[
'module'].split(
'.')[0])
401 for sub_mod
in plugin[
'module'].split(
'.')[1:]:
402 mod = getattr(mod, sub_mod)
403 start_plugin_attr = getattr(
404 mod,
'app_manager_start_plugin')
409 self._plugin_launch.start()
413 if app.timeout
is not None:
416 fp = [self.
_app_interface +
'/' + x
for x
in app.interface.subscribed_topics.keys()]
417 lp = [self.
_app_interface +
'/' + x
for x
in app.interface.published_topics.keys()]
423 return StartAppResponse(started=
True, message=
"app [%s] started"%(appname), namespace=self.
_app_interface)
425 except Exception
as e:
431 self._status_pub.publish(AppStatus(AppStatus.INFO,
'app start failed'))
432 rospy.logerr(
"app start failed")
433 return StartAppResponse(started=
False, message=
"internal error [%s]"%(str(e)), error_code=StatusCodes.INTERNAL_ERROR)
447 self._interface_sync.stop()
453 self._api_sync.stop()
455 self._launch.shutdown()
457 and len(self._launch.pm.dead_list) > 0):
458 self.
_exit_code = self._launch.pm.dead_list[0].exit_code
461 "App stopped with exit code: {}".format(self.
_exit_code))
463 self._plugin_launch.shutdown()
467 if 'stop_plugin_order' in self._current_app_definition.plugin_order:
468 plugin_names = [p[
'name']
for p
in self._current_app_definition.plugins]
469 plugin_order = self._current_app_definition.plugin_order[
'stop_plugin_order']
470 if len(set(plugin_names) - set(plugin_order)) > 0:
472 "Some plugins are defined in plugins but not written in stop_plugin_order: {}" 473 .format(set(plugin_names) - set(plugin_order)))
475 for plugin_name
in plugin_order:
476 if plugin_name
not in plugin_names:
477 rospy.logerr(
"app plugin '{}' not found in app file.".format(plugin_name))
480 if plugin_name
not in current_plugin_names:
481 rospy.logwarn(
"app plugin '{}' is not running, so skip stopping".format(plugin_name))
483 current_plugins.append(
487 for app_plugin, plugin
in current_plugins:
488 if 'module' in plugin
and plugin[
'module']:
490 stop_plugin_args = {}
491 if 'plugin_args' in app_plugin:
492 plugin_args.update(app_plugin[
'plugin_args'])
493 if 'plugin_arg_yaml' in app_plugin:
494 with open(app_plugin[
'plugin_arg_yaml'])
as yaml_f:
495 yaml_plugin_args = yaml.load(yaml_f)
496 for k, v
in yaml_plugin_args.items():
498 rospy.logwarn(
"'{}' is set both in plugin_args and plugin_arg_yaml".format(k))
499 rospy.logwarn(
"'{}' is overwritten: {} -> {}".format(k, plugin_args[k], v))
501 if 'stop_plugin_args' in app_plugin:
502 stop_plugin_args.update(app_plugin[
'stop_plugin_args'])
503 if 'stop_plugin_arg_yaml' in app_plugin:
504 with open(app_plugin[
'stop_plugin_arg_yaml'])
as yaml_f:
505 yaml_plugin_args = yaml.load(yaml_f)
506 for k, v
in yaml_plugin_args.items():
507 if k
in stop_plugin_args:
508 rospy.logwarn(
"'{}' is set both in stop_plugin_args and stop_plugin_arg_yaml".format(k))
509 rospy.logwarn(
"'{}' is overwritten: {} -> {}".format(k, stop_plugin_args[k], v))
510 stop_plugin_args[k] = v
511 plugin_args.update(stop_plugin_args)
512 mod = __import__(plugin[
'module'].split(
'.')[0])
513 for sub_mod
in plugin[
'module'].split(
'.')[1:]:
514 mod = getattr(mod, sub_mod)
515 stop_plugin_attr = getattr(mod,
'app_manager_stop_plugin')
521 rospy.loginfo(
"handle stop app: %s"%(req.name))
527 self._app_list.update()
530 rospy.loginfo(
"app list is reloaded")
531 except Exception
as e:
532 rospy.logerr(
"Failed to reload app list: %s" % e)
533 return EmptyResponse()
539 timeout = self._current_app_definition.timeout
540 appname = self._current_app_definition.name
541 now = rospy.Time.now()
547 if any([p.required
for p
in procs]):
549 p.exit_code
for p
in procs
if p.required]
555 if (timeout
is not None and 560 'app {} is stopped because of timeout: {}s'.format(
567 resp = StopAppResponse(stopped=
False)
572 if app
is not None and appname ==
'*':
575 if app
is None or app.name != appname:
576 rospy.loginfo(
"handle stop app: app [%s] is not running [x]"%(appname))
577 resp.error_code = StatusCodes.NOT_RUNNING
578 resp.message =
"app %s is not running"%(appname)
582 rospy.loginfo(
"handle stop app: stopping app [%s]"%(appname))
583 self._status_pub.publish(AppStatus(AppStatus.INFO,
'stopping %s'%(app.display_name)))
585 rospy.loginfo(
"handle stop app: app [%s] stopped"%(appname))
587 resp.message =
"%s stopped"%(appname)
589 rospy.loginfo(
"handle stop app: app [%s] is not running"%(appname))
590 resp.message =
"app [%s] is not running"%(appname)
591 resp.error_code = StatusCodes.NOT_RUNNING
596 except Exception
as e:
597 rospy.logerr(
"handle stop app: internal error %s"%(e))
598 resp.error_code = StatusCodes.INTERNAL_ERROR
599 resp.message =
"internal error: %s"%(str(e))
def handle_list_apps(self, req)
def find_resource(resource)
def handle_install_app(self, req)
def handle_stop_app(self, req)
def handle_list_exchange_apps(self, req)
def handle_uninstall_app(self, req)
def publish_list_apps(self)
def scoped_name(self, name)
def _set_current_app(self, app, app_definition)
def _get_current_app(self)
def publish_exchange_list_apps(self)
def _load_config_default(roslaunch_files, port, roslaunch_strs=None, loader=None, verbose=False, assign_machines=True, ignore_unset_args=False)
def handle_reload_app_list(self, req=None)
def __init__(self, robot_name, interface_master, app_list, exchange, plugins=None, enable_app_replacement=True)
def load_AppDefinition_by_name(appname)
def handle_start_app(self, req)
def stop_app(self, appname)
def handle_get_app_details(self, req)