gateway.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # License: BSD
00004 #   https://raw.github.com/robotics-in-concert/rocon_multimaster/master/rocon_gateway/LICENSE
00005 #
00006 ##############################################################################
00007 # Imports
00008 ##############################################################################
00009 
00010 import roslib
00011 roslib.load_manifest('rocon_gateway')
00012 import rospy
00013 import rocon_gateway
00014 import redis
00015 import gateway_msgs.msg
00016 import gateway_msgs.srv
00017 from urlparse import urlparse
00018 import zeroconf_msgs.srv
00019 
00020 ##############################################################################
00021 # Gateway Configuration and Main Loop Class
00022 ##############################################################################
00023 
00024 
00025 class Gateway():
00026     '''
00027       Currently this just provides getup and go for the gateway.
00028 
00029         1. configure ros params
00030         2. setup ros pubsubs, services
00031         3. optionally setup zeroconf if necessary and available
00032         4. loop until a hub connection is made, then spin
00033         5. shutdown
00034     '''
00035     def __init__(self):
00036         self.gateway_sync = None  # hub and local ros master connection
00037 
00038         self.param = rocon_gateway.setup_ros_parameters()
00039         self.gateway_sync = rocon_gateway.GatewaySync(self.param)  # maybe pass in the whole params dictionary?
00040         self._gateway_services = self._setup_ros_services()
00041 
00042         self._zeroconf_services = {}
00043         if not self._attempt_direct_connection():
00044             self._zeroconf_services = rocon_gateway.zeroconf.setup_ros_services()
00045 
00046     ##########################################################################
00047     # Main Loop
00048     ##########################################################################
00049 
00050     def spin(self):
00051         previously_found_hubs = []
00052         while not rospy.is_shutdown() and not self.gateway_sync.is_connected:
00053             rospy.sleep(1.0)
00054             if self._zeroconf_services:
00055                 self._scan_for_zeroconf_hubs(previously_found_hubs)
00056             else:
00057                 # do nothing, just wait for a service call
00058                 rospy.logdebug("Gateway : waiting for hub uri input.")
00059 
00060         rospy.loginfo("Gateway : connected to hub [%s][%s]." % (self.gateway_sync.unique_name, self.gateway_sync.hub.name))
00061         rospy.spin()
00062         self._shutdown()
00063 
00064     def _shutdown(self):
00065         '''
00066           Clears this gateway's information from the redis server.
00067         '''
00068         try:
00069             self.gateway_sync.shutdown()
00070         except Exception as e:
00071             rospy.logerr("Gateway : error on shutdown [%s]" % str(e))
00072         rospy.logdebug("Gateway : redis server cleared of gateway information")
00073 
00074     #############################################
00075     # Ros Pubs, Subs and Services
00076     #############################################
00077 
00078     def _setup_ros_services(self):
00079         gateway_services = {}
00080         gateway_services['connect_hub']   = rospy.Service('~connect_hub',                   gateway_msgs.srv.ConnectHub,       self.ros_service_connect_hub)
00081         gateway_services['gateway_info']  = rospy.Service('~gateway_info',                  gateway_msgs.srv.GatewayInfo,      self.ros_service_gateway_info)
00082         gateway_services['remote_gateway_info']  = rospy.Service('~remote_gateway_info',    gateway_msgs.srv.RemoteGatewayInfo,self.ros_service_remote_gateway_info)
00083         gateway_services['advertise']     = rospy.Service('~advertise',                     gateway_msgs.srv.Advertise,        self.gateway_sync.ros_service_advertise)
00084         gateway_services['advertise_all'] = rospy.Service('~advertise_all',                 gateway_msgs.srv.AdvertiseAll,     self.gateway_sync.ros_service_advertise_all)        
00085         gateway_services['flip']          = rospy.Service('~flip',                          gateway_msgs.srv.Remote,    self.gateway_sync.ros_service_flip)        
00086         gateway_services['flip_all']      = rospy.Service('~flip_all',                      gateway_msgs.srv.RemoteAll, self.gateway_sync.ros_service_flip_all)
00087         gateway_services['pull']          = rospy.Service('~pull',                          gateway_msgs.srv.Remote,    self.gateway_sync.ros_service_pull)        
00088         gateway_services['pull_all']      = rospy.Service('~pull_all',                      gateway_msgs.srv.RemoteAll, self.gateway_sync.ros_service_pull_all)
00089         return gateway_services
00090 
00091     #############################################
00092     # Ros Service Callbacks
00093     #############################################
00094 
00095     def ros_service_connect_hub(self, request):
00096         '''
00097           Incoming requests are used to then try and connect to the gateway hub
00098           if not already connected.
00099 
00100           Requests are of the form of a uri (hostname:port pair) pointing to
00101           the gateway hub.
00102         '''
00103         response = gateway_msgs.srv.ConnectHubResponse()
00104         o = urlparse(request.uri)
00105         response.result = self._connect(o.hostname, o.port)
00106         if response.result == gateway_msgs.msg.Result.SUCCESS:
00107             rospy.loginfo("Gateway : made direct connection to hub [%s]" % request.uri)
00108         elif response.result == gateway_msgs.msg.Result.HUB_CONNECTION_BLACKLISTED:
00109             response.error_message = "cowardly refusing your request since that hub is blacklisted [%s]." % request.uri
00110         elif response.result == gateway_msgs.msg.Result.HUB_CONNECTION_ALREADY_EXISTS:
00111             response.error_message = "(currently) can only connect to one hub at a time [%s]." % self.gateway_sync.hub.name
00112         else:
00113             response.error_message = "direct connection failed, probably not available [%s]." % request.uri
00114         return response
00115 
00116     def ros_service_gateway_info(self, msg):
00117         response = gateway_msgs.srv.GatewayInfoResponse()
00118         if self.gateway_sync.unique_name != None:
00119             response.name = self.gateway_sync.unique_name
00120         else:
00121             response.name = self.gateway_sync.unresolved_name
00122         if self.gateway_sync._ip != None:
00123             response.ip = self.gateway_sync._ip
00124         else:
00125             response.ip = 'unavailable'
00126         response.connected = self.gateway_sync.is_connected
00127         response.hub_name = self.gateway_sync.hub.name
00128         response.hub_uri = self.gateway_sync.hub.uri
00129         response.firewall = self.param['firewall']
00130         response.flipped_connections = self.gateway_sync.flipped_interface.get_flipped_connections()
00131         response.flipped_in_connections = self.gateway_sync.flipped_interface.getLocalRegistrations()
00132         response.flip_watchlist = self.gateway_sync.flipped_interface.getWatchlist()
00133         response.pulled_connections = self.gateway_sync.pulled_interface.getLocalRegistrations()
00134         response.pull_watchlist = self.gateway_sync.pulled_interface.getWatchlist()
00135         response.public_watchlist = self.gateway_sync.public_interface.getWatchlist()
00136         response.public_interface = self.gateway_sync.public_interface.getInterface()
00137         return response
00138 
00139     def ros_service_remote_gateway_info(self, request):
00140         response = gateway_msgs.srv.RemoteGatewayInfoResponse()
00141         requested_gateways = request.gateways if request.gateways else self.gateway_sync.hub.list_remote_gateway_names()
00142         for gateway in requested_gateways:
00143             remote_gateway_info = self.gateway_sync.hub.remote_gateway_info(gateway)
00144             if remote_gateway_info:
00145                 response.gateways.append(remote_gateway_info)
00146             else:
00147                 rospy.logwarn("Gateway : requested gateway info for unavailable gateway [%s]" % gateway)
00148         return response
00149 
00150     #############################################
00151     # Hub Connection Methods
00152     #############################################
00153 
00154     def _attempt_direct_connection(self):
00155         '''
00156           If configured with a static hub_uri, attempt a direct connection.
00157 
00158           @return success of the connection
00159           @rtype bool
00160         '''
00161         if self.param['hub_uri'] != '':
00162             o = urlparse(self.param['hub_uri'])
00163             if self._connect(o.hostname, o.port) == gateway_msgs.msg.Result.SUCCESS:
00164                 rospy.loginfo("Gateway : made direct connection to hub [%s]" % self.param['hub_uri'])
00165                 return True
00166             else:
00167                 rospy.logwarn("Gateway : failed direct connection attempt to hub [%s]" % self.param['hub_uri'])
00168         return False
00169 
00170     def _scan_for_zeroconf_hubs(self, previously_found_hubs):
00171         '''
00172           Does a quick scan on zeroconf for gateway hubs. If new ones are
00173           found, and it is not on the blacklist, it attempts a connection.
00174 
00175           This gets run in the pre-spin part of the spin loop.
00176 
00177           @param previously_found_hubs: zeroconf names of previously scanned hubs
00178           @type  previously_found_hubs: list of str
00179         '''
00180         # Get discovered redis server list from zeroconf
00181         req = zeroconf_msgs.srv.ListDiscoveredServicesRequest()
00182         req.service_type = rocon_gateway.zeroconf.gateway_hub_service
00183         resp = self._zeroconf_services["list_discovered_services"](req)
00184         rospy.logdebug("Gateway : checking for autodiscovered gateway hubs")
00185         new_services = lambda l1,l2: [x for x in l1 if x not in l2]
00186         for service in new_services(resp.services,previously_found_hubs):
00187             previously_found_hubs.append(service)
00188             (ip, port) = rocon_gateway.zeroconf.resolve_address(service)
00189             rospy.loginfo("Gateway : discovered hub zeroconf service at " + str(ip) + ":"+str(service.port))
00190             connect_result = self._connect(ip,port)
00191             if connect_result == gateway_msgs.msg.Result.SUCCESS:
00192                 break
00193 
00194     def _connect(self,ip,port):
00195         if self.gateway_sync.is_connected: 
00196             rospy.logwarn("Gateway : gateway is already connected, aborting connection attempt.")
00197             return gateway_msgs.msg.Result.HUB_CONNECTION_ALREADY_EXISTS
00198         try:
00199             hub_name = rocon_gateway.resolve_hub(ip,port)
00200             rospy.loginfo("Gateway : resolved hub name [%s].", hub_name)
00201         except redis.exceptions.ConnectionError:
00202             rospy.logerr("Gateway : couldn't connect to the hub [%s:%s]", ip, port)
00203             return gateway_msgs.msg.Result.HUB_CONNECTION_UNRESOLVABLE
00204         if ip in self.param['hub_blacklist']:
00205             rospy.loginfo("Gateway : ignoring blacklisted hub [%s]",ip)
00206             return gateway_msgs.msg.Result.HUB_CONNECTION_BLACKLISTED
00207         elif hub_name in self.param['hub_blacklist']:
00208             rospy.loginfo("Gateway : ignoring blacklisted hub [%s]",hub_name)
00209             return gateway_msgs.msg.Result.HUB_CONNECTION_BLACKLISTED
00210         # Handle whitelist (ip or hub name)
00211         if (len(self.param['hub_whitelist']) == 0) or (ip in self.param['hub_whitelist']) or (hub_name in self.param['hub_whitelist']):
00212             if self.gateway_sync.connect_to_hub(ip,port):
00213                 return gateway_msgs.msg.Result.SUCCESS
00214             else:
00215                 return gateway_msgs.msg.Result.HUB_CONNECTION_FAILED
00216         else:
00217             rospy.loginfo("Gateway : hub/ip not in non-empty whitelist [%s]",hub_name)
00218             return gateway_msgs.msg.Result.HUB_CONNECTION_NOT_IN_NONEMPTY_WHITELIST
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends


rocon_gateway
Author(s): Daniel Stonier, Jihoon Lee,
autogenerated on Tue Jan 15 2013 17:43:24