def send_flip_request(self, remote_gateway, connection): ''' Sends a message to the remote gateway via redis pubsub channel. This is called from the watcher thread, when a flip rule gets activated. - redis channel name: rocon:<remote_gateway_name> - data : list of [ command, gateway, rule type, type, xmlrpc_uri ] - [0] - command : in this case 'flip' - [1] - gateway : the name of this gateway, i.e. the flipper - [2] - name : local name - [3] - node : local node name - [4] - connection_type : one of ConnectionType.PUBLISHER etc - [5] - type_info : a ros format type (e.g. std_msgs/String or service api) - [6] - xmlrpc_uri : the xmlrpc node uri @param command : string command name - either 'flip' or 'unflip' @type str @param flip_rule : the flip to send @type gateway_msgs.RemoteRule @param type_info : topic type (e.g. std_msgs/String) @param str @param xmlrpc_uri : the node uri @param str ''' source = hub_api.key_base_name(self._redis_keys['gateway']) cmd = utils.serialize_connection_request('flip', source, connection) try: self._redis_server.publish( hub_api.create_rocon_key(remote_gateway), cmd) except Exception as unused_e: return False return True
def run(self): ''' Run the hub watcher (sidekick) thread at the rate specified by the watcher_thread_rate parameter. The watcher thread does the following: 1. For all gateways available, see if we have a pinger available. 2. Add and remove pingers as necessary 3. Depending on pinger stats, update hub appropriately ''' rate = WallRate(self.watcher_thread_rate) unavailable_set = set() while True: remote_gateway_names = self.hub.list_remote_gateway_names() # Check all pingers for name in remote_gateway_names: gateway_key = hub_api.create_rocon_key(name) # Get time for this gateway when hub was last seen ping_key = hub_api.create_rocon_gateway_key(name, ':ping') expiration_time = self.hub._redis_server.ttl(ping_key) # rospy.logwarn("<= {0} TTL {1}".format(ping_key, expiration_time)) if expiration_time is None or expiration_time == -2: # Probably in the process of starting up, ignore for now continue seconds_since_last_seen = int(ConnectionStatistics.MAX_TTL - expiration_time) # rospy.logwarn("<= Not seen since {0} secs...".format(seconds_since_last_seen)) # if it has been gone for more than one loop if seconds_since_last_seen > rate.period: rospy.logwarn("Hub Watcher: gateway " + name + " has been unavailable for " + str(seconds_since_last_seen) + " seconds.") unavailable_set.add(gateway_key) self.hub.mark_named_gateway_available( gateway_key, False, seconds_since_last_seen) # Check if gateway gone if seconds_since_last_seen > self.gateway_gone_timeout: rospy.logwarn("Hub Watcher: gateway " + name + " has been unavailable for " + str(self.gateway_gone_timeout) + " seconds! Removing from hub.") # Gone for too long => unregister self.hub.unregister_named_gateway(gateway_key) # Mark gateway as available else: if gateway_key in unavailable_set: rospy.logwarn("Hub Watcher: gateway " + name + " detected available again !") unavailable_set.remove(gateway_key) self.hub.mark_named_gateway_available( gateway_key, True, seconds_since_last_seen) rate.sleep()
def _send_unflip_request(self, remote_gateway, rule): source = hub_api.key_base_name(self._redis_keys['gateway']) cmd = utils.serialize_rule_request('unflip', source, rule) try: self._redis_server.publish( hub_api.create_rocon_key(remote_gateway), cmd) except Exception as unused_e: return False return True
def register_gateway(self, firewall, unique_gateway_name, hub_connection_lost_gateway_hook, gateway_ip): ''' Register a gateway with the hub. @param firewall @param unique_gateway_name @param hub_connection_lost_gateway_hook : used to trigger Gateway.disengage_hub(hub) on lost hub connections in redis pubsub listener thread. @gateway_ip @raise HubConnectionLostError if for some reason, the redis server has become unavailable. ''' if not self._redis_server: raise HubConnectionLostError() self._unique_gateway_name = unique_gateway_name self._redis_keys['gateway'] = hub_api.create_rocon_key(unique_gateway_name) self._redis_keys['firewall'] = hub_api.create_rocon_gateway_key(unique_gateway_name, 'firewall') self._firewall = 1 if firewall else 0 self._hub_connection_lost_gateway_hook = hub_connection_lost_gateway_hook if not self._redis_server.sadd(self._redis_keys['gatewaylist'], self._redis_keys['gateway']): # should never get here - unique should be unique pass self.mark_named_gateway_available(self._redis_keys['gateway']) self._redis_server.set(self._redis_keys['firewall'], self._firewall) # I think we just used this for debugging, but we might want to hide it in # future (it's the ros master hostname/ip) self._redis_keys['ip'] = hub_api.create_rocon_gateway_key(unique_gateway_name, 'ip') self._redis_server.set(self._redis_keys['ip'], gateway_ip) self.private_key, public_key = utils.generate_private_public_key() self._redis_keys['public_key'] = hub_api.create_rocon_gateway_key(unique_gateway_name, 'public_key') old_key = self._redis_server.get(self._redis_keys['public_key']) serialized_public_key = utils.serialize_key(public_key) self._redis_server.set(self._redis_keys['public_key'], serialized_public_key) if serialized_public_key != old_key: rospy.loginfo('Gateway : Found existing mismatched public key on the hub. ' + 'Requesting resend for all flip-ins.') self._resend_all_flip_ins() # Mark this gateway as now available self._redis_server.sadd(self._redis_keys['gatewaylist'], self._redis_keys['gateway']) self.hub_connection_checker_thread = HubConnectionCheckerThread( self.ip, self.port, self._hub_connection_lost_hook) self.hub_connection_checker_thread.start() self.connection_lost_lock = threading.Lock() # Let hub know we are alive ping_key = hub_api.create_rocon_gateway_key(self._unique_gateway_name, ':ping') self._redis_server.set(ping_key, True) self._redis_server.expire(ping_key, gateway_msgs.ConnectionStatistics.MAX_TTL)
def run(self): ''' Run the hub watcher (sidekick) thread at the rate specified by the watcher_thread_rate parameter. The wathcer thread does the following: 1. For all gateways available, see if we have a pinger available. 2. Add and remove pingers as necessary 3. Depending on pinger stats, update hub appropriately ''' rate = WallRate(self.watcher_thread_rate) while True: remote_gateway_names = self.hub.list_remote_gateway_names() # Check all pingers for name in remote_gateway_names: gateway_key = hub_api.create_rocon_key(name) # Get time for this gateway when hub was last seen ping_key = hub_api.create_rocon_gateway_key(name, ':ping') expiration_time = self.hub._redis_server.ttl(ping_key) if expiration_time is None: # Probably in the process of starting up, ignore for now continue seconds_since_last_seen = \ int(ConnectionStatistics.MAX_TTL - expiration_time) # Check if gateway gone for low timeout (unavailable) if seconds_since_last_seen > self.gateway_unavailable_timeout: if name not in self.unavailable_gateways: rospy.logwarn("Hub Watcher: gateway " + name + " has been unavailable for " + str(self.gateway_unavailable_timeout) + " seconds! Marking as unavailable.") self.unavailable_gateways.append(name) self.hub.mark_named_gateway_available(gateway_key, False, seconds_since_last_seen) else: if name in self.unavailable_gateways: self.unavailable_gateways.remove(name) self.hub.mark_named_gateway_available(gateway_key, True, seconds_since_last_seen) # Check if gateway gone for high timeout (dead) if seconds_since_last_seen > self.gateway_dead_timeout: rospy.logwarn("Hub Watcher: gateway " + name + " has been unavailable for " + str(self.gateway_dead_timeout) + " seconds! Removing from hub.") self.hub.unregister_named_gateway(gateway_key) rate.sleep()
def register_gateway(self, firewall, unique_gateway_name, remote_gateway_request_callbacks, hub_connection_lost_gateway_hook, gateway_ip): ''' Register a gateway with the hub. @param firewall @param unique_gateway_name @param remote_gateway_request_callbacks @param hub_connection_lost_hook : used to trigger Gateway.disengage_hub(hub) on lost hub connections in redis pubsub listener thread. @gateway_ip @raise HubConnectionLostError if for some reason, the redis server has become unavailable. ''' if not self._redis_server: raise HubConnectionLostError() self._unique_gateway_name = unique_gateway_name self._redis_keys['gateway'] = hub_api.create_rocon_key( unique_gateway_name) self._redis_keys['firewall'] = hub_api.create_rocon_gateway_key( unique_gateway_name, 'firewall') self._firewall = 1 if firewall else 0 self._redis_keys['gatewaylist'] = hub_api.create_rocon_hub_key( 'gatewaylist') self._remote_gateway_request_callbacks = remote_gateway_request_callbacks self._hub_connection_lost_gateway_hook = hub_connection_lost_gateway_hook if not self._redis_server.sadd(self._redis_keys['gatewaylist'], self._redis_keys['gateway']): # should never get here - unique should be unique pass unused_ret = self._redis_server.sadd(self._redis_keys['gatewaylist'], self._redis_keys['gateway']) self._redis_server.set(self._redis_keys['firewall'], self._firewall) # I think we just used this for debugging, but we might want to hide it in future (it's the ros master hostname/ip) self._redis_keys['ip'] = hub_api.create_rocon_gateway_key( unique_gateway_name, 'ip') self._redis_server.set(self._redis_keys['ip'], gateway_ip) self._redis_channels['gateway'] = self._redis_keys['gateway'] self._redis_pubsub_server.subscribe(self._redis_channels['gateway']) self.remote_gateway_listener_thread = RedisListenerThread( self._redis_pubsub_server, self._remote_gateway_request_callbacks, self._hub_connection_lost_hook) self.remote_gateway_listener_thread.start()