Package rocon_gateway :: Module interactive_interface
[frames] | no frames]

Source Code for Module rocon_gateway.interactive_interface

  1  #!/usr/bin/env python 
  2  # 
  3  # License: BSD 
  4  #   https://raw.github.com/robotics-in-concert/rocon_multimaster/master/rocon_gateway/LICENSE 
  5  # 
  6   
  7  ############################################################################## 
  8  # Imports 
  9  ############################################################################## 
 10   
 11  import threading 
 12  from gateway_msgs.msg import RemoteRule 
 13  import re 
 14  import copy 
 15   
 16  # Local imports 
 17  import utils 
 18   
 19  ############################################################################## 
 20  # Classes 
 21  ############################################################################## 
 22   
 23   
24 -class InteractiveInterface(object):
25 ''' 26 Parent interface for flip and pull interfaces. 27 '''
28 - def __init__(self, default_rule_blacklist, default_rules, all_targets):
29 ''' 30 @param default_rule_blacklist : used when in flip/pull all mode 31 @type dictionary of gateway 32 @param default_rules : static rules to flip/pull on startup 33 @type gateway_msgs.msg.RemoteRule[] 34 @param all_targets : static flip/pull all targets to flip/pull to on startup 35 @type string[] 36 ''' 37 # Rules that are active, ie have been flipped or pulled from remote gateways 38 # keys are connection_types, elements are lists of RemoteRule objects 39 # This gets aliased to self.flipped or self.pulled as necessary in 40 # the subclasses 41 self.active = utils.create_empty_connection_type_dictionary() 42 43 # Default rules used in the xxxAll modes 44 self._default_blacklist = default_rule_blacklist # dictionary of gateway-gateway_msgs.msg.Rule lists, not RemoteRules! 45 46 # keys are connection_types, elements are lists of gateway_msgs.msg.RemoteRule objects 47 self.watchlist = utils.create_empty_connection_type_dictionary() # Specific rules used to determine what local rules to flip 48 49 # keys are connection_types, elements are lists of utils.Registration objects 50 self.registrations = utils.create_empty_connection_type_dictionary() # Flips from remote gateways that have been locally registered 51 52 # Blacklists when doing flip all - different for each gateway, each value is one of our usual rule type dictionaries 53 self._blacklist = {} 54 55 self._lock = threading.Lock() 56 57 # Load up static rules. 58 for rule in default_rules: 59 self.add_rule(rule) 60 for gateway in all_targets: 61 self.add_all(gateway, []) # don't add the complexity of extra blacklists yet, maybe later
62 63 ########################################################################## 64 # Rules 65 ########################################################################## 66
67 - def add_rule(self, remote_rule):
68 ''' 69 Add a remote rule to the watchlist for monitoring. 70 71 @param remote_rule : the remote rule to add to the watchlist 72 @type gateway_msgs.msg.RemoteRule 73 74 @return the remote rule, or None if the rule already exists. 75 @rtype gateway_msgs.msg.RemoteRule || None 76 ''' 77 result = None 78 self._lock.acquire() 79 rule_already_exists = False 80 # Could be a bit smarter here - given regex expressions an added 81 # rule may be redundant. It doesn't break the eventual behaviour though 82 for watched_rule in self.watchlist[remote_rule.rule.type]: 83 if watched_rule.gateway == remote_rule.gateway and \ 84 watched_rule.rule.name == remote_rule.rule.name and \ 85 watched_rule.rule.node == remote_rule.rule.node: 86 rule_already_exists = True 87 break 88 if not rule_already_exists: 89 self.watchlist[remote_rule.rule.type].append(remote_rule) 90 result = remote_rule 91 self._lock.release() 92 return result
93
94 - def remove_rule(self, remote_rule):
95 ''' 96 Remove a rule. Be a bit careful looking for a rule to remove, depending 97 on the node name, which can be set (exact rule/node name match) or 98 None in which case all nodes of that kind of flip will match. 99 100 Handle the remapping appropriately. 101 102 @param remote_rule : the remote rule to remove from the watchlist. 103 @type gateway_msgs.msg.RemoteRule 104 105 @return Rules remaining in the watchlist 106 @rtype RemoteRule[] 107 ''' 108 if remote_rule.rule.node: 109 # This looks for *exact* matches. 110 try: 111 self._lock.acquire() 112 self.watchlist[remote_rule.rule.type].remove(remote_rule) 113 self._lock.release() 114 return [remote_rule] 115 except ValueError: 116 self._lock.release() 117 return [] 118 else: 119 # This looks for any flip rules which match except for the node name 120 existing_rules = [] 121 self._lock.acquire() 122 for existing_rule in self.watchlist[remote_rule.rule.type]: 123 if (existing_rule.gateway == remote_rule.gateway) and \ 124 (existing_rule.rule.name == remote_rule.rule.name): 125 existing_rules.append(existing_rule) 126 for rule in existing_rules: 127 self.watchlist[remote_rule.rule.type].remove(rule) # not terribly optimal 128 self._lock.release() 129 return existing_rules
130
131 - def add_all(self, gateway, blacklist):
132 ''' 133 Instead of watching/acting on specific rules, take action 134 on everything except for rules in a blacklist. 135 136 @param gateway : target remote gateway string id 137 @type str 138 139 @param blacklist : do not act on rules matching these patterns 140 @type gateway_msgs.msg.Rule[] 141 142 @return success or failure depending on if it ahs already been set or not 143 @rtype Bool 144 ''' 145 self._lock.acquire() 146 # Blacklist 147 if gateway in self._blacklist: 148 self._lock.release() 149 return False 150 self._blacklist[gateway] = self._default_blacklist 151 for rule in blacklist: 152 self._blacklist[gateway][rule.type].append(rule) 153 # Flips 154 for connection_type in utils.connection_types: 155 remote_rule = RemoteRule() 156 remote_rule.gateway = gateway 157 remote_rule.rule.name = '.*' 158 remote_rule.rule.node = None 159 remote_rule.rule.type = connection_type 160 # Remove all other rules for that gateway 161 self.watchlist[connection_type][:] = [rule for rule in self.watchlist[connection_type] if rule.gateway != gateway] 162 # basically self.add_rule() - do it manually here so we don't deadlock locks 163 self.watchlist[connection_type].append(remote_rule) 164 self._lock.release() 165 return True
166
167 - def remove_all(self, gateway):
168 ''' 169 Remove the add all rule for the specified gateway. 170 171 @param gateway : target remote gateway string id 172 @type str 173 ''' 174 self._lock.acquire() 175 if gateway in self._blacklist: 176 del self._blacklist[gateway] 177 for connection_type in utils.connection_types: 178 for rule in self.watchlist[connection_type]: 179 if rule.gateway == gateway: 180 # basically self.remove_rule() - do it manually here so we don't deadlock locks 181 try: 182 self.watchlist[connection_type].remove(rule) 183 except ValueError: 184 pass # should never get here 185 self._lock.release()
186 187 ########################################################################## 188 # Accessors for Gateway Info 189 ########################################################################## 190
191 - def is_matched(self, rule, rule_name, name, node):
192 matched = False 193 name_match_result = re.match(rule_name, name) 194 if name_match_result and name_match_result.group() == name: 195 if utils.is_all_pattern(rule_name): 196 if self._is_in_blacklist(rule.gateway, rule.rule.type, name, node): 197 return False 198 if rule.rule.node: 199 node_match_result = re.match(rule.rule.node, node) 200 if node_match_result and node_match_result.group() == node: 201 matched = True 202 else: 203 matched = True 204 return matched
205
206 - def getLocalRegistrations(self):
207 ''' 208 Gets the local registrations for GatewayInfo consumption (flipped ins/pulls). 209 210 We don't need to show the service and node uri's here. 211 212 Basic operation : convert Registration -> RemoteRule for each registration 213 214 @return the list of registrations corresponding to remote interactions 215 @rtype RemoteRule[] 216 ''' 217 local_registrations = [] 218 for connection_type in utils.connection_types: 219 for registration in self.registrations[connection_type]: 220 remote_rule = RemoteRule() 221 remote_rule.gateway = registration.remote_gateway 222 remote_rule.rule.name = registration.connection.rule.name 223 remote_rule.rule.node = registration.connection.rule.node 224 remote_rule.rule.type = connection_type 225 local_registrations.append(remote_rule) 226 return local_registrations
227
228 - def getWatchlist(self):
229 ''' 230 Gets the watchlist for GatewayInfo consumption. 231 232 @return the list of flip rules that are being watched 233 @rtype gateway_msgs.msg.RemoteRule[] 234 ''' 235 watchlist = [] 236 for connection_type in utils.connection_types: 237 watchlist.extend(copy.deepcopy(self.watchlist[connection_type])) 238 # ros messages must have string output 239 for remote in watchlist: 240 if not remote.rule.node: 241 remote.rule.node = 'None' 242 return watchlist
243 244 ########################################################################## 245 # Utilities 246 ########################################################################## 247
248 - def find_registration_match(self, remote_gateway, remote_name, remote_node, connection_type):
249 ''' 250 Check to see if a registration exists. Note that it doesn't use the 251 local node name in the check. We will get things like unflip requests that 252 don't have this variable set (that gets autogenerated when registering 253 the flip), but we need to find the matching registration. 254 255 We then return the registration that matches. 256 257 @param remote_gateway : string remote gateway id 258 @type string 259 @param remote_name, remote_node, connection_type : remote connection details 260 @type string 261 262 @return matching registration or none 263 @rtype utils.Registration 264 ''' 265 266 matched_registration = None 267 self._lock.acquire() 268 for registration in self.registrations[connection_type]: 269 if (registration.remote_gateway == remote_gateway) and \ 270 (registration.connection.rule.name == remote_name) and \ 271 (registration.connection.rule.node == remote_node) and \ 272 (registration.connection.rule.type == connection_type): 273 matched_registration = registration 274 break 275 else: 276 continue 277 self._lock.release() 278 return matched_registration
279
280 - def _is_in_blacklist(self, gateway, connection_type, name, node):
281 ''' 282 Check if a particular connection is in the blacklist. Use this to 283 filter connections from the flip_all command. 284 285 @todo move to utils - should be shared with the public interface. 286 ''' 287 for blacklist_rule in self._blacklist[gateway][connection_type]: 288 name_match_result = re.match(blacklist_rule.name, name) 289 if name_match_result and name_match_result.group() == name: 290 if blacklist_rule.node: 291 node_match_result = re.match(blacklist_rule.node, node) 292 if node_match_result and node_match_result.group() == node: 293 return True 294 else: # rule.connection.node is None so we don't care about matching the node 295 return True 296 return False
297