PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/rosservice/src/rosservice/__init__.py

https://gitlab.com/F34140r/ros_comm
Python | 763 lines | 669 code | 19 blank | 75 comment | 26 complexity | ab70647aed7c6baabfb1d92eaf3c7d90 MD5 | raw file
Possible License(s): LGPL-2.1
  1. # Software License Agreement (BSD License)
  2. #
  3. # Copyright (c) 2008, Willow Garage, Inc.
  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 Willow Garage, Inc. 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. # Revision $Id: rosservice.py 3813 2009-02-11 21:16:34Z sfkwc $
  34. """
  35. Command-line utility for querying ROS services, along with library
  36. calls for similar functionality. The main benefit of the rosservice
  37. Python library over the rospy ServiceProxy library is that rosservice
  38. supports type-introspection on ROS Services. This allows for both
  39. introspecting information about services, as well as using this
  40. introspection to dynamically call services.
  41. """
  42. from __future__ import print_function
  43. NAME='rosservice'
  44. import os
  45. import sys
  46. import socket
  47. try:
  48. from cStringIO import StringIO # Python 2.x
  49. except ImportError:
  50. from io import StringIO # Python 3.x
  51. import genpy
  52. import roslib.message
  53. import rospy
  54. import rosmsg
  55. import rosgraph
  56. import rosgraph.names
  57. import rosgraph.network
  58. from optparse import OptionParser
  59. class ROSServiceException(Exception):
  60. """Base class for rosservice-related exceptions"""
  61. pass
  62. class ROSServiceIOException(ROSServiceException):
  63. """rosservice related to network I/O failure"""
  64. pass
  65. def _get_master():
  66. return rosgraph.Master('/rosservice')
  67. def _succeed(args):
  68. """
  69. Utility that raises a ROSServiceException if ROS XMLRPC command fails
  70. @param args: (code, msg, val) ROS XMLRPC call return args
  71. @type args: (int, str, XmlRpcValue)
  72. @return: value argument from ROS XMLRPC call (third arg of tuple)
  73. @rtype: XmlRpcLegal value
  74. @raise ROSServiceException: if XMLRPC command does not return a SUCCESS code
  75. """
  76. code, msg, val = args
  77. if code != 1:
  78. raise ROSServiceException("remote call failed: %s"%msg)
  79. return val
  80. def get_service_headers(service_name, service_uri):
  81. """
  82. Utility for connecting to a service and retrieving the TCPROS
  83. headers. Services currently do not declare their type with the
  84. master, so instead we probe the service for its headers.
  85. @param service_name: name of service
  86. @type service_name: str
  87. @param service_uri: ROSRPC URI of service
  88. @type service_uri: str
  89. @return: map of header fields
  90. @rtype: dict
  91. @raise ROSServiceException: if service has invalid information
  92. @raise ROSServiceIOException: if unable to communicate with service
  93. """
  94. try:
  95. dest_addr, dest_port = rospy.parse_rosrpc_uri(service_uri)
  96. except:
  97. raise ROSServiceException("service [%s] has an invalid RPC URI [%s]"%(service_name, service_uri))
  98. if rosgraph.network.use_ipv6():
  99. s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
  100. else:
  101. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  102. try:
  103. try:
  104. # connect to service and probe it to get the headers
  105. s.settimeout(5.0)
  106. s.connect((dest_addr, dest_port))
  107. header = { 'probe':'1', 'md5sum':'*',
  108. 'callerid':'/rosservice', 'service':service_name}
  109. rosgraph.network.write_ros_handshake_header(s, header)
  110. return rosgraph.network.read_ros_handshake_header(s, StringIO(), 2048)
  111. except socket.error:
  112. raise ROSServiceIOException("Unable to communicate with service [%s], address [%s]"%(service_name, service_uri))
  113. finally:
  114. if s is not None:
  115. s.close()
  116. def get_service_type(service_name):
  117. """
  118. Get the type of the specified service_name. May print errors to stderr.
  119. :param service_name: name of service, ``str``
  120. :returns: type of service or ``None``, ``str``
  121. :raises: :exc:`ROSServiceIOException` If unable to communicate with service
  122. """
  123. master = _get_master()
  124. try:
  125. service_uri = master.lookupService(service_name)
  126. except socket.error:
  127. raise ROSServiceIOException("Unable to communicate with master!")
  128. except rosgraph.MasterError:
  129. return None
  130. try:
  131. return get_service_headers(service_name, service_uri).get('type', None)
  132. except socket.error:
  133. raise ROSServiceIOException("Unable to communicate with service [%s]! Service address is [%s]"%(service_name, service_uri))
  134. def _rosservice_type(service_name):
  135. """
  136. Implements 'type' command. Prints service type to stdout. Will
  137. system exit with error if service_name is unknown.
  138. :param service_name: name of service, ``str``
  139. """
  140. service_type = get_service_type(service_name)
  141. if service_type is None:
  142. print("Unknown service [%s]"%service_name, file=sys.stderr)
  143. sys.exit(1)
  144. else:
  145. print(service_type)
  146. def get_service_uri(service_name):
  147. """
  148. Retrieve ROSRPC URI of service.
  149. :param service_name: name of service to lookup, ``str``
  150. :returns: ROSRPC URI for service_name, ``str``
  151. """
  152. try:
  153. master = _get_master()
  154. try:
  155. return master.lookupService(service_name)
  156. except rosgraph.MasterException:
  157. return None
  158. except socket.error:
  159. raise ROSServiceIOException("Unable to communicate with master!")
  160. def _rosservice_uri(service_name):
  161. """
  162. Implements rosservice uri command. Will cause system exit with
  163. error if service_name is unknown.
  164. :param service_name: name of service to lookup, ``str``
  165. :raises: :exc:`ROSServiceIOException` If the I/O issues prevent retrieving service information
  166. """
  167. uri = get_service_uri(service_name)
  168. if uri:
  169. print(uri)
  170. else:
  171. print("Unknown service: %s"%service_name, file=sys.stderr)
  172. sys.exit(1)
  173. def get_service_node(service_name):
  174. """
  175. @return: name of node that implements service, or None
  176. @rtype: str
  177. """
  178. srvs = get_service_list(include_nodes=True)
  179. s = [s for s in srvs if s[0] == service_name]
  180. if s:
  181. if s[0][1]:
  182. return s[0][1][0]
  183. return None
  184. def _rosservice_node(service_name):
  185. """
  186. Implements rosservice node command. Will cause system exit with error if service is unknown.
  187. @param service_name: name of service to lookup
  188. @type service_name: str
  189. @raise ROSServiceIOException: if the I/O issues prevent retrieving service information
  190. """
  191. n = get_service_node(service_name)
  192. if n:
  193. print(n)
  194. else:
  195. print("Unknown service: %s"%service_name, file=sys.stderr)
  196. sys.exit(1)
  197. def get_service_list(node=None, namespace=None, include_nodes=False):
  198. """
  199. Get the list of services
  200. @param node: Name of node to get services for or None to return all services
  201. @type node: str
  202. @param namespace: Namespace to scope services to or None
  203. @type namespace: str
  204. @param include_nodes: If True, return list will be [service_name, [node]]
  205. @type include_nodes: bool
  206. @return: if include_nodes, services is service_name,
  207. [node]. Otherwise, it is just the service_name
  208. @rtype: [services]
  209. @raise ROSServiceIOException: if the I/O issues prevent retrieving service information
  210. """
  211. try:
  212. master = _get_master()
  213. state = master.getSystemState()
  214. srvs = state[2]
  215. # filter srvs to namespace
  216. if namespace:
  217. g_ns = rosgraph.names.make_global_ns(namespace)
  218. srvs = [x for x in srvs if x[0] == namespace or x[0].startswith(g_ns)]
  219. if include_nodes:
  220. if node is None:
  221. return srvs
  222. else:
  223. return [(s, nodelist) for s, nodelist in srvs if node in nodelist]
  224. else:
  225. if node is None:
  226. return [s for s,_ in srvs]
  227. else:
  228. return [s for s,nodelist in srvs if node in nodelist]
  229. except socket.error:
  230. raise ROSServiceIOException("Unable to communicate with master!")
  231. def _rosservice_list(namespace=None, print_nodes=False):
  232. """
  233. Implements 'rosservice list'
  234. @param namespace: Namespace to limit listing to or None
  235. @type namespace: str
  236. @param print_nodes: If True, also print nodes providing service
  237. @type print_nodes: bool
  238. @raise ROSServiceIOException: if the I/O issues prevent retrieving service information
  239. """
  240. srvs = get_service_list(namespace=namespace, include_nodes=print_nodes)
  241. # print in sorted order
  242. if print_nodes:
  243. import operator
  244. srvs.sort(key=operator.itemgetter(0))
  245. else:
  246. srvs.sort()
  247. for s in srvs:
  248. if print_nodes:
  249. print(s[0]+' '+','.join(s[1]))
  250. else:
  251. print(s)
  252. def _rosservice_info(service_name):
  253. """
  254. Implements 'rosservice info'. Prints information about a service.
  255. @param service_name: name of service to get info for
  256. @type service_name: str
  257. @raise ROSServiceIOException: if the I/O issues prevent retrieving service information
  258. """
  259. n = get_service_node(service_name)
  260. if not n:
  261. print("ERROR: unknown service", file=sys.stderr)
  262. sys.exit(1)
  263. print("Node: %s"%n)
  264. uri = get_service_uri(service_name)
  265. if not uri:
  266. print("ERROR: service is no longer available", file=sys.stderr)
  267. return
  268. print("URI: %s"%uri)
  269. t = get_service_type(service_name)
  270. if not t:
  271. print("ERROR: service is no longer available", file=sys.stderr)
  272. return
  273. print("Type: %s"%t)
  274. args = get_service_args(service_name)
  275. if args is None:
  276. print("ERROR: service is no longer available", file=sys.stderr)
  277. return
  278. print("Args: %s"%args)
  279. def rosservice_find(service_type):
  280. """
  281. Lookup services by service_type
  282. @param service_type: type of service to find
  283. @type service_type: str
  284. @return: list of service names that use service_type
  285. @rtype: [str]
  286. """
  287. master = _get_master()
  288. matches = []
  289. try:
  290. _, _, services = master.getSystemState()
  291. for s, l in services:
  292. t = get_service_type(s)
  293. if t == service_type:
  294. matches.append(s)
  295. except socket.error:
  296. raise ROSServiceIOException("Unable to communicate with master!")
  297. return matches
  298. def _rosservice_cmd_find(argv=sys.argv):
  299. """
  300. Implements 'rosservice type'
  301. @param argv: command-line args
  302. @type argv: [str]
  303. """
  304. args = argv[2:]
  305. parser = OptionParser(usage="usage: %prog find msg-type", prog=NAME)
  306. options, args = parser.parse_args(args)
  307. if not len(args):
  308. parser.error("please specify a message type")
  309. if len(args) > 1:
  310. parser.error("you may only specify one message type")
  311. print('\n'.join(rosservice_find(args[0])))
  312. def _resource_name_package(name):
  313. """
  314. pkg/typeName -> pkg, typeName -> None
  315. :param name: package resource name, e.g. 'std_msgs/String', ``str``
  316. :returns: package name of resource, ``str``
  317. """
  318. if not '/' in name:
  319. return None
  320. return name[:name.find('/')]
  321. def get_service_class_by_name(service_name):
  322. """
  323. Get the service class using the name of the service. NOTE: this
  324. call results in a probe call to the service.
  325. @param service_name: fully-resolved name of service to call
  326. @type service_name: str
  327. @return: service class
  328. @rtype: ServiceDefinition: service class
  329. @raise ROSServiceException: if service class cannot be retrieved
  330. """
  331. # lookup the service type
  332. service_type = get_service_type(service_name)
  333. if not service_type:
  334. # diagnose error
  335. srvs = get_service_list()
  336. if service_name not in srvs:
  337. raise ROSServiceException("Service [%s] is not available."%service_name)
  338. else:
  339. raise ROSServiceException("Unable to determine type of service [%s]."%service_name)
  340. # get the Service class so we can populate the request
  341. service_class = roslib.message.get_service_class(service_type)
  342. # #1083: roscpp services are currently returning the wrong type
  343. if service_class and service_type.endswith('Request') and \
  344. not hasattr(service_class, "_request_class"):
  345. service_type = service_type[:-7]
  346. service_class = roslib.message.get_service_class(service_type)
  347. if service_class is None:
  348. pkg = _resource_name_package(service_type)
  349. raise ROSServiceException("Unable to load type [%s].\n"%service_type+
  350. "Have you typed 'make' in [%s]?"%pkg)
  351. return service_class
  352. def call_service(service_name, service_args, service_class=None):
  353. """
  354. Call the specified service_name
  355. @param service_name: fully-resolved name of service to call
  356. @type service_name: str
  357. @param service_args: args to pass to service
  358. @type service_args: [any]
  359. @param service_class: (optional) service type class. If this
  360. argument is provided, it saves a probe call against the service
  361. @type service_class: Message class
  362. @return: service request, service response
  363. @rtype: Message, Message
  364. @raise ROSServiceException: if call command cannot be executed
  365. """
  366. # can't use time w/o being a node. We could optimize this by
  367. # search for the now/auto keywords first
  368. import std_msgs.msg
  369. rospy.init_node('rosservice', anonymous=True)
  370. if service_class is None:
  371. service_class = get_service_class_by_name(service_name)
  372. request = service_class._request_class()
  373. try:
  374. now = rospy.get_rostime()
  375. keys = { 'now': now, 'auto': std_msgs.msg.Header(stamp=now) }
  376. genpy.message.fill_message_args(request, service_args, keys=keys)
  377. except genpy.MessageException as e:
  378. def argsummary(args):
  379. if type(args) in [tuple, list]:
  380. return '\n'.join([' * %s (type %s)'%(a, type(a).__name__) for a in args])
  381. else:
  382. return ' * %s (type %s)'%(args, type(args).__name__)
  383. raise ROSServiceException("Incompatible arguments to call service:\n%s\nProvided arguments are:\n%s\n\nService arguments are: [%s]"%(e, argsummary(service_args), genpy.message.get_printable_message_args(request)))
  384. try:
  385. return request, rospy.ServiceProxy(service_name, service_class)(request)
  386. except rospy.ServiceException as e:
  387. raise ROSServiceException(str(e))
  388. except genpy.SerializationError as e:
  389. raise ROSServiceException("Unable to send request. One of the fields has an incorrect type:\n"+\
  390. " %s\n\nsrv file:\n%s"%(e, rosmsg.get_srv_text(service_class._type)))
  391. except rospy.ROSSerializationException as e:
  392. raise ROSServiceException("Unable to send request. One of the fields has an incorrect type:\n"+\
  393. " %s\n\nsrv file:\n%s"%(e, rosmsg.get_srv_text(service_class._type)))
  394. def _rosservice_call(service_name, service_args, verbose=False, service_class=None):
  395. """
  396. Implements 'rosservice call'
  397. @param service_name: name of service to call
  398. @type service_name: str
  399. @param service_args: arguments to call service with
  400. @type service_args: [args]
  401. @param verbose: if True, print extra output
  402. @type verbose: bool
  403. @param service_class Message class: (optional) service type
  404. class. If this argument is provided, it saves a probe call against
  405. the service
  406. @type service_class: Message class
  407. @raise ROSServiceException: if call command cannot be executed
  408. """
  409. service_name = rosgraph.names.script_resolve_name('rosservice', service_name)
  410. request, response = call_service(service_name, service_args, service_class=service_class)
  411. if verbose:
  412. print(str(request))
  413. print('---')
  414. print(str(response))
  415. def has_service_args(service_name, service_class=None):
  416. """
  417. Check if service requires arguments
  418. @param service_name: name of service being called
  419. @type service_name: str
  420. @param service_class: (optional) service type class. If this
  421. argument is provided, it saves a probe call against the service
  422. @type service_class: Message class
  423. @return: True if service_name has request arguments
  424. @rtype: bool
  425. """
  426. service_name = rosgraph.names.script_resolve_name('rosservice', service_name)
  427. if service_class is None:
  428. service_class = get_service_class_by_name(service_name)
  429. return len(service_class._request_class.__slots__) > 0
  430. def _rosservice_args(service_name):
  431. """
  432. Implements 'rosservice args'
  433. @param service_name: name of service to get arguments for
  434. @type service_name: str
  435. @raise ROSServiceException: if call command cannot be executed
  436. """
  437. print(get_service_args(service_name))
  438. def get_service_args(service_name):
  439. """
  440. Implements 'get service args'
  441. @param service_name: name of service to get arguments for
  442. @type service_name: str
  443. @raise ROSServiceException: if call command cannot be executed
  444. """
  445. service_name = rosgraph.names.script_resolve_name('rosservice', service_name)
  446. service_class = get_service_class_by_name(service_name)
  447. return genpy.message.get_printable_message_args(service_class._request_class)
  448. ##########################################################################################
  449. # COMMAND PROCESSING #####################################################################
  450. def _optparse_service_only(cmd, argv=sys.argv):
  451. """
  452. Parse command-line arguments for commands that take a service name
  453. only. Will cause a system exit if command-line argument parsing
  454. fails.
  455. @param cmd: command name, e.g. 'type'
  456. @type cmd: str
  457. @param argv: command-line arguments
  458. @type argv: [str]
  459. """
  460. args = argv[2:]
  461. parser = OptionParser(usage="usage: %%prog %s /service"%cmd, prog=NAME)
  462. (options, args) = parser.parse_args(args)
  463. if len(args) == 0:
  464. parser.error("service must be specified")
  465. if len(args) > 1:
  466. parser.error("you may only specify one input service")
  467. return rosgraph.names.script_resolve_name('rosservice', args[0])
  468. def _rosservice_cmd_type(argv):
  469. """
  470. Parse 'type' command arguments and run command Will cause a system
  471. exit if command-line argument parsing fails.
  472. @param argv: command-line arguments
  473. @type argv: [str]
  474. @raise ROSServiceException: if type command cannot be executed
  475. """
  476. _rosservice_type(_optparse_service_only('type', argv=argv))
  477. def _rosservice_cmd_uri(argv, ):
  478. """
  479. Parse 'uri' command arguments and run command. Will cause a system
  480. exit if command-line argument parsing fails.
  481. @param argv: command-line arguments
  482. @type argv: [str]
  483. @raise ROSServiceException: if uri command cannot be executed
  484. """
  485. _rosservice_uri(_optparse_service_only('uri', argv=argv))
  486. def _rosservice_cmd_node(argv, ):
  487. """
  488. Parse 'node' command arguments and run command. Will cause a system
  489. exit if command-line argument parsing fails.
  490. @param argv: command-line arguments
  491. @type argv: [str]
  492. @raise ROSServiceException: if node command cannot be executed
  493. """
  494. _rosservice_node(_optparse_service_only('node', argv=argv))
  495. def _rosservice_cmd_args(argv, ):
  496. """
  497. Parse 'args' command arguments and run command. Will cause a system
  498. exit if command-line argument parsing fails.
  499. @param argv: command-line arguments
  500. @type argv: [str]
  501. @raise ROSServiceException: if args command cannot be executed
  502. """
  503. _rosservice_args(_optparse_service_only('args', argv=argv))
  504. def _rosservice_cmd_call(argv):
  505. """
  506. Parse 'call' command arguments and run command. Will cause a system
  507. exit if command-line argument parsing fails.
  508. @param argv: command-line arguments
  509. @type argv: [str]
  510. @raise ROSServiceException: if call command cannot be executed
  511. """
  512. try:
  513. import yaml
  514. except ImportError as e:
  515. raise ROSServiceException("Cannot import yaml. Please make sure the pyyaml system dependency is installed")
  516. args = argv[2:]
  517. parser = OptionParser(usage="usage: %prog call /service [args...]", prog=NAME)
  518. parser.add_option("-v", dest="verbose", default=False,
  519. action="store_true",
  520. help="print verbose output")
  521. parser.add_option("--wait", dest="wait", default=False,
  522. action="store_true",
  523. help="wait for service to be advertised")
  524. (options, args) = parser.parse_args(args)
  525. if len(args) == 0:
  526. parser.error("service must be specified")
  527. service_name = args[0]
  528. if options.wait:
  529. # have to make sure there is at least a master as the error
  530. # behavior of all ros online tools is to fail if there is no
  531. # master
  532. master = _get_master()
  533. try:
  534. service_uri = master.getPid()
  535. except socket.error:
  536. raise ROSServiceIOException("Unable to communicate with master!")
  537. rospy.wait_for_service(service_name)
  538. # optimization: in order to prevent multiple probe calls against a service, lookup the service_class
  539. service_name = rosgraph.names.script_resolve_name('rosservice', args[0])
  540. service_class = get_service_class_by_name(service_name)
  541. # type-case using YAML
  542. service_args = []
  543. for arg in args[1:]:
  544. # convert empty args to YAML-empty strings
  545. if arg == '':
  546. arg = "''"
  547. service_args.append(yaml.load(arg))
  548. if not service_args and has_service_args(service_name, service_class=service_class):
  549. if sys.stdin.isatty():
  550. parser.error("Please specify service arguments")
  551. import rostopic
  552. for service_args in rostopic.stdin_yaml_arg():
  553. if service_args:
  554. # #2080: argument to _rosservice_call must be a list
  555. if type(service_args) != list:
  556. service_args = [service_args]
  557. try:
  558. _rosservice_call(service_name, service_args, verbose=options.verbose, service_class=service_class)
  559. except ValueError as e:
  560. print(str(e), file=sys.stderr)
  561. break
  562. else:
  563. _rosservice_call(service_name, service_args, verbose=options.verbose, service_class=service_class)
  564. def _stdin_yaml_arg():
  565. """
  566. @return: iterator for next set of service args on stdin. Iterator returns a list of args for each call.
  567. @rtype: iterator
  568. """
  569. import yaml
  570. import select
  571. loaded = None
  572. poll = select.poll()
  573. poll.register(sys.stdin, select.POLLIN)
  574. try:
  575. arg = 'x'
  576. while not rospy.is_shutdown() and arg != '\n':
  577. buff = ''
  578. while arg != '\n' and arg.strip() != '---':
  579. val = poll.poll(1.0)
  580. if not val:
  581. continue
  582. arg = sys.stdin.readline() + '\n'
  583. if arg.startswith('... logging'):
  584. # temporary, until we fix rospy logging
  585. continue
  586. elif arg.strip() != '---':
  587. buff = buff + arg
  588. try:
  589. loaded = yaml.load(buff.rstrip())
  590. except Exception as e:
  591. print("Invalid YAML: %s"%str(e), file=sys.stderr)
  592. if loaded is not None:
  593. yield loaded
  594. else:
  595. # EOF reached, this will raise GeneratorExit
  596. return
  597. # reset arg
  598. arg = 'x'
  599. except select.error:
  600. return # most likely ctrl-c interrupt
  601. def _rosservice_cmd_list(argv):
  602. """
  603. Parse 'list' command arguments and run command
  604. Will cause a system exit if command-line argument parsing fails.
  605. @param argv: command-line arguments
  606. @type argv: [str]
  607. @raise ROSServiceException: if list command cannot be executed
  608. """
  609. args = argv[2:]
  610. parser = OptionParser(usage="usage: %prog list [/namespace]", prog=NAME)
  611. parser.add_option("-n", "--nodes",
  612. dest="print_nodes", default=False, action="store_true",
  613. help="print nodes that provide service(s)")
  614. (options, args) = parser.parse_args(args)
  615. namespace = None
  616. if len(args) == 1:
  617. namespace = rosgraph.names.script_resolve_name('rosservice', args[0])
  618. elif len(args) > 1:
  619. parser.error("you may only specify one input namespace")
  620. _rosservice_list(namespace, print_nodes=options.print_nodes)
  621. def _rosservice_cmd_info(argv):
  622. """
  623. Parse 'info' command arguments and run command
  624. Will cause a system exit if command-line argument parsing fails.
  625. @param argv: command-line arguments
  626. @type argv: [str]
  627. @raise ROSServiceException: if list command cannot be executed
  628. """
  629. args = argv[2:]
  630. parser = OptionParser(usage="usage: %prog info /service", prog=NAME)
  631. (options, args) = parser.parse_args(args)
  632. name = None
  633. if len(args) == 1:
  634. name = rosgraph.names.script_resolve_name('rosservice', args[0])
  635. elif len(args) > 1:
  636. parser.error("you may only specify one service")
  637. elif not len(args):
  638. parser.error("you must specify a service name")
  639. _rosservice_info(name)
  640. def _fullusage():
  641. """Print generic usage for rosservice"""
  642. print("""Commands:
  643. \trosservice args\tprint service arguments
  644. \trosservice call\tcall the service with the provided args
  645. \trosservice find\tfind services by service type
  646. \trosservice info\tprint information about service
  647. \trosservice list\tlist active services
  648. \trosservice type\tprint service type
  649. \trosservice uri\tprint service ROSRPC uri
  650. Type rosservice <command> -h for more detailed usage, e.g. 'rosservice call -h'
  651. """)
  652. sys.exit(getattr(os, 'EX_USAGE', 1))
  653. def rosservicemain(argv=sys.argv):
  654. """
  655. main entry point for rosservice command-line tool
  656. @param argv: command-line args
  657. @type argv: [str]
  658. """
  659. if len(argv) == 1:
  660. _fullusage()
  661. try:
  662. # filter remapping args, #3433
  663. argv = [a for a in argv if not rosgraph.names.REMAP in a]
  664. command = argv[1]
  665. if command in 'list':
  666. _rosservice_cmd_list(argv)
  667. elif command == 'info':
  668. _rosservice_cmd_info(argv)
  669. elif command == 'type':
  670. _rosservice_cmd_type(argv)
  671. elif command == 'uri':
  672. _rosservice_cmd_uri(argv)
  673. elif command == 'node':
  674. _rosservice_cmd_node(argv)
  675. elif command == 'call':
  676. _rosservice_cmd_call(argv)
  677. elif command == 'args':
  678. _rosservice_cmd_args(argv)
  679. elif command == 'find':
  680. _rosservice_cmd_find(argv)
  681. else:
  682. _fullusage()
  683. except socket.error:
  684. print("Network communication failed with the master or a node.", file=sys.stderr)
  685. sys.exit(1)
  686. except ROSServiceException as e:
  687. print("ERROR: "+str(e), file=sys.stderr)
  688. sys.exit(2)
  689. except rosgraph.MasterException as e:
  690. print("ERROR: "+str(e), file=sys.stderr)
  691. sys.exit(2)
  692. except KeyboardInterrupt:
  693. pass