class RouterRoleStaticAuth(RouterRole): """ A role on a router realm that is authorized using a static configuration. """ def __init__(self, router, uri, permissions=None, default_permissions=None): """ :param router: The router this role is defined on. :type router: obj :param uri: The URI of the role. :type uri: unicode :param permissions: A permissions configuration, e.g. a list of permission dicts like `{'uri': 'com.example.*', 'call': True}` :type permissions: list of dict :param default_permissions: The default permissions to apply when no other configured permission matches. The default permissions when not explicitly set is to deny all actions on all URIs! :type default_permissions: dict """ RouterRole.__init__(self, router, uri) assert (permissions is None or type(permissions) == list) if permissions: for p in permissions: assert (type(p) == dict) assert (default_permissions is None or type(default_permissions) == dict) # default permissions (used when nothing else is matching) # note: default permissions have their matching URI and match policy set to None! if default_permissions: self._default = RouterPermissions.from_dict(default_permissions) else: self._default = RouterPermissions(None, None, call=False, register=False, publish=False, subscribe=False, disclose_caller=False, disclose_publisher=False, cache=True) # Trie of explicitly configured permissions self._permissions = StringTrie() self._wild_permissions = StringTrie() # for "wildcard" URIs, there will be a ".." in them somewhere, # and so we want to match on the biggest prefix # (i.e. everything to the left of the first "..") for obj in permissions or []: perms = RouterPermissions.from_dict(obj) if '..' in perms.uri: trunc = perms.uri[:perms.uri.index('..')] self._wild_permissions[trunc] = perms else: self._permissions[perms.uri] = perms def authorize(self, session, uri, action, options): """ Authorize a session connected under this role to perform the given action on the given URI. :param session: The WAMP session that requests the action. :type session: Instance of :class:`autobahn.wamp.protocol.ApplicationSession` :param uri: The URI on which to perform the action. :type uri: str :param action: The action to be performed. :type action: str :return: bool -- Flag indicating whether session is authorized or not. """ self.log.debug( "CrossbarRouterRoleStaticAuth.authorize {myuri} {uri} {action}", myuri=self.uri, uri=uri, action=action) try: # longest prefix match of the URI to be authorized against our Trie # of configured URIs for permissions permissions = self._permissions.longest_prefix_value(uri) # if there is a _prefix_ matching URI, check that this is actually the # match policy on the permission (otherwise, apply default permissions)! if permissions.match != u'prefix' and uri != permissions.uri: permissions = self._default except KeyError: # workaround because of https://bitbucket.org/gsakkis/pytrie/issues/4/string-keys-of-zero-length-are-not permissions = self._permissions.get(u'', self._default) # if we found a non-"exact" match, there might be a better one in the wildcards if permissions.match != u'exact': try: wildperm = self._wild_permissions.longest_prefix_value(uri) Pattern(wildperm.uri, Pattern.URI_TARGET_ENDPOINT).match(uri) except (KeyError, Exception): # match() raises Exception on no match wildperm = None if wildperm is not None: permissions = wildperm # we now have some permissions, either from matching something # or via self._default if action == u'publish': return { u'allow': permissions.publish, u'disclose': permissions.disclose_publisher, u'cache': permissions.cache } elif action == u'subscribe': return { u'allow': permissions.subscribe, u'cache': permissions.cache } elif action == u'call': return { u'allow': permissions.call, u'disclose': permissions.disclose_caller, u'cache': permissions.cache } elif action == u'register': return { u'allow': permissions.register, u'cache': permissions.cache } else: # should not arrive here raise Exception('logic error')
class UriObservationMap(object): """ Represents the current set of observations maintained by a broker/dealer. To test: trial crossbar.router.test.test_subscription """ def __init__(self, ordered=False): # flag indicating whether observers should be maintained in a SortedSet # or a regular set (unordered) self._ordered = ordered # map: URI => ExactUriObservation self._observations_exact = {} # map: URI => PrefixUriObservation self._observations_prefix = StringTrie() # map: URI => WildcardUriObservation self._observations_wildcard = {} # map: pattern length => (map: pattern => pattern count) self._observations_wildcard_patterns = {} # map: observation ID => UriObservation self._observation_id_to_observation = {} def add_observer(self, observer, uri, match=u"exact", extra=None): """ Adds a observer to the observation set and returns the respective observation. :param observer: The observer to add (this can be any opaque object). :type observer: obj :param uri: The URI (or URI pattern) to add the observer to add to. :type uri: unicode :param match: The matching policy for observing, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``. :type match: unicode :returns: A tuple ``(observation, was_already_observed, was_first_observer)``. Here, ``observation`` is an instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``. :rtype: tuple """ if match == u"exact": # if the exact-matching URI isn't in our map, create a new observation # if uri not in self._observations_exact: self._observations_exact[uri] = ExactUriObservation(uri, ordered=self._ordered, extra=extra) is_first_observer = True else: is_first_observer = False # get the observation # observation = self._observations_exact[uri] elif match == u"prefix": # if the prefix-matching URI isn't in our map, create a new observation # if uri not in self._observations_prefix: self._observations_prefix[uri] = PrefixUriObservation(uri, ordered=self._ordered, extra=extra) is_first_observer = True else: is_first_observer = False # get the observation # observation = self._observations_prefix[uri] elif match == u"wildcard": # if the wildcard-matching URI isn't in our map, create a new observation # if uri not in self._observations_wildcard: observation = WildcardUriObservation(uri, ordered=self._ordered, extra=extra) self._observations_wildcard[uri] = observation is_first_observer = True # setup map: pattern length -> patterns if observation.pattern_len not in self._observations_wildcard_patterns: self._observations_wildcard_patterns[observation.pattern_len] = {} # setup map: (pattern length, pattern) -> pattern count if observation.pattern not in self._observations_wildcard_patterns[observation.pattern_len]: self._observations_wildcard_patterns[observation.pattern_len][observation.pattern] = 1 else: self._observations_wildcard_patterns[observation.pattern_len][observation.pattern] += 1 else: is_first_observer = False # get the observation # observation = self._observations_wildcard[uri] else: raise Exception("invalid match strategy '{}'".format(match)) # note observation in observation ID map # if is_first_observer: self._observation_id_to_observation[observation.id] = observation # add observer if not already in observation # if observer not in observation.observers: observation.observers.add(observer) was_already_observed = False else: was_already_observed = True return observation, was_already_observed, is_first_observer def get_observation(self, uri, match=u"exact"): """ Get a observation (if any) for given URI and match policy. :param uri: The URI (or URI pattern) to get the observation for. :type uri: unicode :param match: The matching policy for observation to retrieve, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``. :type match: unicode :returns: The observation (instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``) or ``None``. :rtype: obj or None """ if match == u"exact": return self._observations_exact.get(uri, None) elif match == u"prefix": return self._observations_prefix.get(uri, None) elif match == u"wildcard": return self._observations_wildcard.get(uri, None) else: raise Exception("invalid match strategy '{}'".format(match)) def match_observations(self, uri): """ Returns the observations matching the given URI. This is the core method called by a broker to actually dispatch events. :param uri: The URI to match. :type uri: unicode :returns: A list of observations matching the URI. This is a list of instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``. :rtype: list """ observations = [] if uri in self._observations_exact: observations.append(self._observations_exact[uri]) for observation in self._observations_prefix.iter_prefix_values(uri): observations.append(observation) uri_parts = tuple(uri.split('.')) uri_parts_len = len(uri_parts) if uri_parts_len in self._observations_wildcard_patterns: for pattern in self._observations_wildcard_patterns[uri_parts_len]: patterned_uri = '.'.join(['' if pattern[i] else uri_parts[i] for i in range(uri_parts_len)]) if patterned_uri in self._observations_wildcard: observations.append(self._observations_wildcard[patterned_uri]) return observations def best_matching_observation(self, uri): """ Returns the observation that best matches the given URI. This is the core method called by a dealer to actually forward calls. :param uri: The URI to match. :type uri: unicode :returns: The observation best matching the URI. This is an instance of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` or ``None``. :rtype: obj or None """ # a exact matching observation is always "best", if any # if uri in self._observations_exact: return self._observations_exact[uri] # "second best" is the longest prefix-matching observation, if any # FIXME: do we want this to take precedence over _any_ wildcard (see below)? # try: return self._observations_prefix.longest_prefix_value(uri) except KeyError: pass # FIXME: for wildcard observations, when there are multiple matching, we'd # like to deterministically select the "most selective one" # We first need a definition of "most selective", and then we need to implement # this here. # uri_parts = tuple(uri.split('.')) uri_parts_len = len(uri_parts) if uri_parts_len in self._observations_wildcard_patterns: for pattern in self._observations_wildcard_patterns[uri_parts_len]: patterned_uri = '.'.join(['' if pattern[i] else uri_parts[i] for i in range(uri_parts_len)]) if patterned_uri in self._observations_wildcard: return self._observations_wildcard[patterned_uri] def get_observation_by_id(self, id): """ Get a observation by ID. :param id: The ID of the observation to retrieve. :type id: int :returns: The observation for the given ID or ``None``. :rtype: obj or None """ return self._observation_id_to_observation.get(id, None) def drop_observer(self, observer, observation): """ Drop a observer from a observation. :param observer: The observer to drop from the given observation. :type observer: obj :param observation: The observation from which to drop the observer. An instance of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` previously created and handed out by this observation map. :type observation: obj :returns: A tuple ``(was_observed, was_last_observer)``. :rtype: tuple """ if observer in observation.observers: was_observed = True # remove observer from observation # observation.observers.discard(observer) # no more observers on this observation! # if not observation.observers: if observation.match == u"exact": del self._observations_exact[observation.uri] elif observation.match == u"prefix": del self._observations_prefix[observation.uri] elif observation.match == u"wildcard": # cleanup if this was the last observation with given pattern self._observations_wildcard_patterns[observation.pattern_len][observation.pattern] -= 1 if not self._observations_wildcard_patterns[observation.pattern_len][observation.pattern]: del self._observations_wildcard_patterns[observation.pattern_len][observation.pattern] # cleanup if this was the last observation with given pattern length if not self._observations_wildcard_patterns[observation.pattern_len]: del self._observations_wildcard_patterns[observation.pattern_len] # remove actual observation del self._observations_wildcard[observation.uri] else: # should not arrive here raise Exception("logic error") was_last_observer = True del self._observation_id_to_observation[observation.id] else: was_last_observer = False else: # observer wasn't on this observation was_observed = False return was_observed, was_last_observer
class UriObservationMap(object): """ Represents the current set of observations maintained by a broker/dealer. To test: trial crossbar.router.test.test_subscription """ __slots__ = ( "_ordered", "_observations_exact", "_observations_prefix", "_observations_wildcard", "_observation_id_to_observation", ) def __init__(self, ordered=False): # flag indicating whether observers should be maintained in a SortedSet # or a regular set (unordered) self._ordered = ordered # map: URI => ExactUriObservation self._observations_exact = {} # map: URI => PrefixUriObservation self._observations_prefix = StringTrie() # map: URI => WildcardUriObservation if True: # use a Trie-based implementation (supposed to be faster, but # otherwise compatible to the naive implementation below) self._observations_wildcard = WildcardTrieMatcher() else: self._observations_wildcard = WildcardMatcher() # map: observation ID => UriObservation self._observation_id_to_observation = {} def __repr__(self): return "{}(_ordered={}, _observations_exact={}, _observations_wildcard={})".format( self.__class__.__name__, self._ordered, self._observations_exact, self._observations_prefix, self._observations_wildcard, self._observation_id_to_observation, ) def add_observer(self, observer, uri, match=u"exact", extra=None): """ Adds a observer to the observation set and returns the respective observation. :param observer: The observer to add (this can be any opaque object). :type observer: obj :param uri: The URI (or URI pattern) to add the observer to add to. :type uri: unicode :param match: The matching policy for observing, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``. :type match: unicode :returns: A tuple ``(observation, was_already_observed, was_first_observer)``. Here, ``observation`` is an instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``. :rtype: tuple """ if not isinstance(uri, six.text_type): raise Exception("'uri' should be unicode, not {}".format(type(uri).__name__)) if match == u"exact": # if the exact-matching URI isn't in our map, create a new observation # if uri not in self._observations_exact: self._observations_exact[uri] = ExactUriObservation(uri, ordered=self._ordered, extra=extra) is_first_observer = True else: is_first_observer = False # get the observation # observation = self._observations_exact[uri] elif match == u"prefix": # if the prefix-matching URI isn't in our map, create a new observation # if uri not in self._observations_prefix: self._observations_prefix[uri] = PrefixUriObservation(uri, ordered=self._ordered, extra=extra) is_first_observer = True else: is_first_observer = False # get the observation # observation = self._observations_prefix[uri] elif match == u"wildcard": # if the wildcard-matching URI isn't in our map, create a new observation # if uri not in self._observations_wildcard: self._observations_wildcard[uri] = WildcardUriObservation(uri, ordered=self._ordered, extra=extra) is_first_observer = True else: is_first_observer = False # get the observation # observation = self._observations_wildcard[uri] else: raise Exception("invalid match strategy '{}'".format(match)) # note observation in observation ID map # if is_first_observer: self._observation_id_to_observation[observation.id] = observation # add observer if not already in observation # if observer not in observation.observers: observation.observers.add(observer) was_already_observed = False else: was_already_observed = True return observation, was_already_observed, is_first_observer def get_observation(self, uri, match=u"exact"): """ Get a observation (if any) for given URI and match policy. :param uri: The URI (or URI pattern) to get the observation for. :type uri: unicode :param match: The matching policy for observation to retrieve, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``. :type match: unicode :returns: The observation (instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``) or ``None``. :rtype: obj or None """ if not isinstance(uri, six.text_type): raise Exception("'uri' should be unicode, not {}".format(type(uri).__name__)) if match == u"exact": return self._observations_exact.get(uri, None) elif match == u"prefix": return self._observations_prefix.get(uri, None) elif match == u"wildcard": return self._observations_wildcard.get(uri, None) else: raise Exception("invalid match strategy '{}'".format(match)) def match_observations(self, uri): """ Returns the observations matching the given URI. This is the core method called by a broker to actually dispatch events. :param uri: The URI to match. :type uri: unicode :returns: A list of observations matching the URI. This is a list of instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``. :rtype: list """ observations = [] if not isinstance(uri, six.text_type): raise Exception("'uri' should be unicode, not {}".format(type(uri).__name__)) if uri in self._observations_exact: observations.append(self._observations_exact[uri]) for observation in self._observations_prefix.iter_prefix_values(uri): observations.append(observation) for observation in self._observations_wildcard.iter_matches(uri): observations.append(observation) return observations def best_matching_observation(self, uri): """ Returns the observation that best matches the given URI. This is the core method called by a dealer to actually forward calls. :param uri: The URI to match. :type uri: unicode :returns: The observation best matching the URI. This is an instance of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` or ``None``. :rtype: obj or None """ if not isinstance(uri, six.text_type): raise Exception("'uri' should be unicode, not {}".format(type(uri).__name__)) # a exact matching observation is always "best", if any # if uri in self._observations_exact: return self._observations_exact[uri] # "second best" is the longest prefix-matching observation, if any # FIXME: do we want this to take precedence over _any_ wildcard (see below)? # try: return self._observations_prefix.longest_prefix_value(uri) except KeyError: pass # FIXME: for wildcard observations, when there are multiple matching, we'd # like to deterministically select the "most selective one" # We first need a definition of "most selective", and then we need to implement # this here. # for observation in self._observations_wildcard.iter_matches(uri): return observation def get_observation_by_id(self, id): """ Get a observation by ID. :param id: The ID of the observation to retrieve. :type id: int :returns: The observation for the given ID or ``None``. :rtype: obj or None """ return self._observation_id_to_observation.get(id, None) def drop_observer(self, observer, observation): """ Drop a observer from a observation. :param observer: The observer to drop from the given observation. :type observer: obj :param observation: The observation from which to drop the observer. An instance of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` previously created and handed out by this observation map. :type observation: obj :returns: A tuple ``(was_observed, was_last_observer)``. :rtype: tuple """ if observer in observation.observers: was_observed = True # remove observer from observation # observation.observers.discard(observer) # no more observers on this observation! # if not observation.observers: if observation.match == u"exact": del self._observations_exact[observation.uri] elif observation.match == u"prefix": del self._observations_prefix[observation.uri] elif observation.match == u"wildcard": del self._observations_wildcard[observation.uri] else: # should not arrive here raise Exception("logic error") was_last_observer = True del self._observation_id_to_observation[observation.id] else: was_last_observer = False else: # observer wasn't on this observation was_observed = False return was_observed, was_last_observer
class UriObservationMap(object): """ Represents the current set of observations maintained by a broker/dealer. To test: trial crossbar.router.test.test_subscription """ def __init__(self, ordered=False): # flag indicating whether observers should be maintained in a SortedSet # or a regular set (unordered) self._ordered = ordered # map: URI => ExactUriObservation self._observations_exact = {} # map: URI => PrefixUriObservation self._observations_prefix = StringTrie() # map: URI => WildcardUriObservation self._observations_wildcard = {} # map: pattern length => (map: pattern => pattern count) self._observations_wildcard_patterns = {} # map: observation ID => UriObservation self._observation_id_to_observation = {} def add_observer(self, observer, uri, match=u"exact", extra=None): """ Adds a observer to the observation set and returns the respective observation. :param observer: The observer to add (this can be any opaque object). :type observer: obj :param uri: The URI (or URI pattern) to add the observer to add to. :type uri: unicode :param match: The matching policy for observing, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``. :type match: unicode :returns: A tuple ``(observation, was_already_observed, was_first_observer)``. Here, ``observation`` is an instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``. :rtype: tuple """ if match == u"exact": # if the exact-matching URI isn't in our map, create a new observation # if uri not in self._observations_exact: self._observations_exact[uri] = ExactUriObservation( uri, ordered=self._ordered, extra=extra) is_first_observer = True else: is_first_observer = False # get the observation # observation = self._observations_exact[uri] elif match == u"prefix": # if the prefix-matching URI isn't in our map, create a new observation # if uri not in self._observations_prefix: self._observations_prefix[uri] = PrefixUriObservation( uri, ordered=self._ordered, extra=extra) is_first_observer = True else: is_first_observer = False # get the observation # observation = self._observations_prefix[uri] elif match == u"wildcard": # if the wildcard-matching URI isn't in our map, create a new observation # if uri not in self._observations_wildcard: observation = WildcardUriObservation(uri, ordered=self._ordered, extra=extra) self._observations_wildcard[uri] = observation is_first_observer = True # setup map: pattern length -> patterns if observation.pattern_len not in self._observations_wildcard_patterns: self._observations_wildcard_patterns[ observation.pattern_len] = {} # setup map: (pattern length, pattern) -> pattern count if observation.pattern not in self._observations_wildcard_patterns[ observation.pattern_len]: self._observations_wildcard_patterns[ observation.pattern_len][observation.pattern] = 1 else: self._observations_wildcard_patterns[ observation.pattern_len][observation.pattern] += 1 else: is_first_observer = False # get the observation # observation = self._observations_wildcard[uri] else: raise Exception("invalid match strategy '{}'".format(match)) # note observation in observation ID map # if is_first_observer: self._observation_id_to_observation[observation.id] = observation # add observer if not already in observation # if observer not in observation.observers: observation.observers.add(observer) was_already_observed = False else: was_already_observed = True return observation, was_already_observed, is_first_observer def get_observation(self, uri, match=u"exact"): """ Get a observation (if any) for given URI and match policy. :param uri: The URI (or URI pattern) to get the observation for. :type uri: unicode :param match: The matching policy for observation to retrieve, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``. :type match: unicode :returns: The observation (instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``) or ``None``. :rtype: obj or None """ if match == u"exact": return self._observations_exact.get(uri, None) elif match == u"prefix": return self._observations_prefix.get(uri, None) elif match == u"wildcard": return self._observations_wildcard.get(uri, None) else: raise Exception("invalid match strategy '{}'".format(match)) def match_observations(self, uri): """ Returns the observations matching the given URI. This is the core method called by a broker to actually dispatch events. :param uri: The URI to match. :type uri: unicode :returns: A list of observations matching the URI. This is a list of instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``. :rtype: list """ observations = [] if uri in self._observations_exact: observations.append(self._observations_exact[uri]) for observation in self._observations_prefix.iter_prefix_values(uri): observations.append(observation) uri_parts = tuple(uri.split('.')) uri_parts_len = len(uri_parts) if uri_parts_len in self._observations_wildcard_patterns: for pattern in self._observations_wildcard_patterns[uri_parts_len]: patterned_uri = '.'.join([ '' if pattern[i] else uri_parts[i] for i in range(uri_parts_len) ]) if patterned_uri in self._observations_wildcard: observations.append( self._observations_wildcard[patterned_uri]) return observations def best_matching_observation(self, uri): """ Returns the observation that best matches the given URI. This is the core method called by a dealer to actually forward calls. :param uri: The URI to match. :type uri: unicode :returns: The observation best matching the URI. This is an instance of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` or ``None``. :rtype: obj or None """ # a exact matching observation is always "best", if any # if uri in self._observations_exact: return self._observations_exact[uri] # "second best" is the longest prefix-matching observation, if any # FIXME: do we want this to take precedence over _any_ wildcard (see below)? # try: return self._observations_prefix.longest_prefix_value(uri) except KeyError: pass # FIXME: for wildcard observations, when there are multiple matching, we'd # like to deterministically select the "most selective one" # We first need a definition of "most selective", and then we need to implement # this here. # uri_parts = tuple(uri.split('.')) uri_parts_len = len(uri_parts) if uri_parts_len in self._observations_wildcard_patterns: for pattern in self._observations_wildcard_patterns[uri_parts_len]: patterned_uri = '.'.join([ '' if pattern[i] else uri_parts[i] for i in range(uri_parts_len) ]) if patterned_uri in self._observations_wildcard: return self._observations_wildcard[patterned_uri] def get_observation_by_id(self, id): """ Get a observation by ID. :param id: The ID of the observation to retrieve. :type id: int :returns: The observation for the given ID or ``None``. :rtype: obj or None """ return self._observation_id_to_observation.get(id, None) def drop_observer(self, observer, observation): """ Drop a observer from a observation. :param observer: The observer to drop from the given observation. :type observer: obj :param observation: The observation from which to drop the observer. An instance of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` previously created and handed out by this observation map. :type observation: obj :returns: A tuple ``(was_observed, was_last_observer)``. :rtype: tuple """ if observer in observation.observers: was_observed = True # remove observer from observation # observation.observers.discard(observer) # no more observers on this observation! # if not observation.observers: if observation.match == u"exact": del self._observations_exact[observation.uri] elif observation.match == u"prefix": del self._observations_prefix[observation.uri] elif observation.match == u"wildcard": # cleanup if this was the last observation with given pattern self._observations_wildcard_patterns[ observation.pattern_len][observation.pattern] -= 1 if not self._observations_wildcard_patterns[ observation.pattern_len][observation.pattern]: del self._observations_wildcard_patterns[ observation.pattern_len][observation.pattern] # cleanup if this was the last observation with given pattern length if not self._observations_wildcard_patterns[ observation.pattern_len]: del self._observations_wildcard_patterns[ observation.pattern_len] # remove actual observation del self._observations_wildcard[observation.uri] else: # should not arrive here raise Exception("logic error") was_last_observer = True del self._observation_id_to_observation[observation.id] else: was_last_observer = False else: # observer wasn't on this observation was_observed = False return was_observed, was_last_observer
class UriObservationMap(object): """ Represents the current set of observations maintained by a broker/dealer. To test: trial crossbar.router.test.test_subscription """ __slots__ = ('_ordered', '_observations_exact', '_observations_prefix', '_observations_wildcard', '_observation_id_to_observation') def __init__(self, ordered=False): # flag indicating whether observers should be maintained in a SortedSet # or a regular set (unordered) self._ordered = ordered # map: URI => ExactUriObservation self._observations_exact = {} # map: URI => PrefixUriObservation self._observations_prefix = StringTrie() # map: URI => WildcardUriObservation if True: # use a Trie-based implementation (supposed to be faster, but # otherwise compatible to the naive implementation below) self._observations_wildcard = WildcardTrieMatcher() else: self._observations_wildcard = WildcardMatcher() # map: observation ID => UriObservation self._observation_id_to_observation = {} def __repr__(self): return "{}(_ordered={}, _observations_exact={}, _observations_wildcard={})".format( self.__class__.__name__, self._ordered, self._observations_exact, self._observations_prefix, self._observations_wildcard, self._observation_id_to_observation) def add_observer(self, observer, uri, match=u"exact", extra=None, observer_extra=None): """ Adds a observer to the observation set and returns the respective observation. :param observer: The observer to add (this can be any opaque object). :type observer: obj :param uri: The URI (or URI pattern) to add the observer to add to. :type uri: unicode :param match: The matching policy for observing, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``. :type match: unicode :returns: A tuple ``(observation, was_already_observed, was_first_observer)``. Here, ``observation`` is an instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``. :rtype: tuple """ if not isinstance(uri, six.text_type): raise Exception("'uri' should be unicode, not {}".format( type(uri).__name__)) is_first_observer = False if match == u"exact": # if the exact-matching URI isn't in our map, create a new observation # if uri not in self._observations_exact: self.create_observation(uri, match, extra) is_first_observer = True # get the observation # observation = self._observations_exact[uri] elif match == u"prefix": # if the prefix-matching URI isn't in our map, create a new observation # if uri not in self._observations_prefix: self.create_observation(uri, match, extra) is_first_observer = True # get the observation # observation = self._observations_prefix[uri] elif match == u"wildcard": # if the wildcard-matching URI isn't in our map, create a new observation # if uri not in self._observations_wildcard: self.create_observation(uri, match, extra) is_first_observer = True # get the observation # observation = self._observations_wildcard[uri] else: raise Exception("invalid match strategy '{}'".format(match)) # add observer if not already in observation # if observer not in observation.observers: was_already_observed = False # add the observer to the set of observers sitting on the observation observation.observers.add(observer) # if there is observer-specific extra data, store it if observer_extra: observation.observers_extra[observer] = observer_extra else: was_already_observed = True return observation, was_already_observed, is_first_observer def get_observation(self, uri, match=u"exact"): """ Get a observation (if any) for given URI and match policy. :param uri: The URI (or URI pattern) to get the observation for. :type uri: unicode :param match: The matching policy for observation to retrieve, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``. :type match: unicode :returns: The observation (instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``) or ``None``. :rtype: obj or None """ if not isinstance(uri, six.text_type): raise Exception("'uri' should be unicode, not {}".format( type(uri).__name__)) if match == u"exact": return self._observations_exact.get(uri, None) elif match == u"prefix": return self._observations_prefix.get(uri, None) elif match == u"wildcard": return self._observations_wildcard.get(uri, None) else: raise Exception("invalid match strategy '{}'".format(match)) def match_observations(self, uri): """ Returns the observations matching the given URI. This is the core method called by a broker to actually dispatch events. :param uri: The URI to match. :type uri: unicode :returns: A list of observations matching the URI. This is a list of instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``. :rtype: list """ observations = [] if not isinstance(uri, six.text_type): raise Exception("'uri' should be unicode, not {}".format( type(uri).__name__)) if uri in self._observations_exact: observations.append(self._observations_exact[uri]) for observation in self._observations_prefix.iter_prefix_values(uri): observations.append(observation) for observation in self._observations_wildcard.iter_matches(uri): observations.append(observation) return observations def best_matching_observation(self, uri): """ Returns the observation that best matches the given URI. This is the core method called by a dealer to actually forward calls. :param uri: The URI to match. :type uri: unicode :returns: The observation best matching the URI. This is an instance of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` or ``None``. :rtype: obj or None """ if not isinstance(uri, six.text_type): raise Exception("'uri' should be unicode, not {}".format( type(uri).__name__)) # a exact matching observation is always "best", if any if uri in self._observations_exact: return self._observations_exact[uri] # "second best" is the longest prefix-matching observation, if any # FIXME: do we want this to take precedence over _any_ wildcard (see below)? try: return self._observations_prefix.longest_prefix_value(uri) except KeyError: # workaround because of https://bitbucket.org/gsakkis/pytrie/issues/4/string-keys-of-zero-length-are-not if u'' in self._observations_prefix: return self._observations_prefix[u''] # FIXME: for wildcard observations, when there are multiple matching, we'd # like to deterministically select the "most selective one" # We first need a definition of "most selective", and then we need to implement # this here. for observation in self._observations_wildcard.iter_matches(uri): return observation def get_observation_by_id(self, id): """ Get a observation by ID. :param id: The ID of the observation to retrieve. :type id: int :returns: The observation for the given ID or ``None``. :rtype: obj or None """ return self._observation_id_to_observation.get(id, None) def create_observation(self, uri, match=u"exact", extra=None): """ Create an observation with no observers. :param uri: The URI (or URI pattern) to get the observation for. :type uri: unicode :param match: The matching policy for observation to retrieve, one of ``u"exact"``, ``u"prefix"`` or ``u"wildcard"``. :type match: unicode :returns: The observation (instance of one of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation``). :rtype: obj """ if match == u"exact": observation = ExactUriObservation(uri, ordered=self._ordered, extra=extra) self._observations_exact[uri] = observation elif match == u"prefix": observation = PrefixUriObservation(uri, ordered=self._ordered, extra=extra) self._observations_prefix[uri] = observation elif match == u"wildcard": observation = WildcardUriObservation(uri, ordered=self._ordered, extra=extra) self._observations_wildcard[uri] = observation # note observation in observation ID map # self._observation_id_to_observation[observation.id] = observation return observation def drop_observer(self, observer, observation): """ Drop a observer from a observation. :param observer: The observer to drop from the given observation. :type observer: obj :param observation: The observation from which to drop the observer. An instance of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` previously created and handed out by this observation map. :type observation: obj :param delete: Whether or not to delete the observation if they are the last observer. :type delete: bool :returns: A tuple ``(was_observed, was_last_observer)``. :rtype: tuple """ was_last_observer = False if observer in observation.observers: was_observed = True # remove observer from observation # observation.observers.discard(observer) # discard observer-level extra data (if any) # if observer in observation.observers_extra: del observation.observers_extra[observer] # no more observers on this observation! # if not observation.observers: was_last_observer = True else: # observer wasn't on this observation was_observed = False return was_observed, was_last_observer def delete_observation(self, observation): """ Delete the observation from the map. :param observation: The observation which to remove from the map. An instance of ``ExactUriObservation``, ``PrefixUriObservation`` or ``WildcardUriObservation`` previously created and handed out by this observation map. :type observation: obj :rtype: None """ if observation.observers: raise ValueError( "Can't delete an observation with current observers.") if observation.match == u"exact": del self._observations_exact[observation.uri] elif observation.match == u"prefix": del self._observations_prefix[observation.uri] elif observation.match == u"wildcard": del self._observations_wildcard[observation.uri] else: # should not arrive here raise Exception("logic error") del self._observation_id_to_observation[observation.id]
#BUİLD TRİE FOR QUERY 2 for i in range(len(all_files)): with open(all_files[i], 'r') as f: for line in f: res = re.findall(r'\w+', line) #take list of words line by line ,convert lower and put with filename to trie for j in range(len(res)): #check the key existence in the trie if not myTrie.has_key( res[j].lower()): # word is NOT in the trie myTrie[res[j].lower()] = {all_files[i] } # word-> set of file else: myTrie.get(res[j].lower()).add( all_files[i] ) # if word is IN the trie add only file info to fileSET OF WORD #BUİLD TRİE FOR QUERY 1 for i in range(len(all_files)): with open(all_files[i], 'r') as f: counter = 0 for line in f: res = re.findall(r'\w+', line) #take list of words line by line ,convert lower and put with filename to trie for j in range(len(res)): #check the key existence in the trie #need index data index = counter + line.index(res[j]) #take index of each word if not myTrie1.has_key( res[j].lower()): # word is NOT in the trie
class RouterRoleStaticAuth(RouterRole): """ A role on a router realm that is authorized using a static configuration. """ def __init__(self, router, uri, permissions=None, default_permissions=None): """ :param router: The router this role is defined on. :type router: obj :param uri: The URI of the role. :type uri: unicode :param permissions: A permissions configuration, e.g. a list of permission dicts like `{'uri': 'com.example.*', 'call': True}` :type permissions: list of dict :param default_permissions: The default permissions to apply when no other configured permission matches. The default permissions when not explicitly set is to deny all actions on all URIs! :type default_permissions: dict """ RouterRole.__init__(self, router, uri) assert(permissions is None or isinstance(permissions, list)) if permissions: for p in permissions: assert(isinstance(p, dict)) assert(default_permissions is None or isinstance(default_permissions, dict)) # default permissions (used when nothing else is matching) # note: default permissions have their matching URI and match policy set to None! if default_permissions: self._default = RouterPermissions.from_dict(default_permissions) else: self._default = RouterPermissions(None, None, call=False, register=False, publish=False, subscribe=False, disclose_caller=False, disclose_publisher=False, cache=True) # Trie of explicitly configured permissions self._permissions = StringTrie() self._wild_permissions = StringTrie() # for "wildcard" URIs, there will be a ".." in them somewhere, # and so we want to match on the biggest prefix # (i.e. everything to the left of the first "..") for obj in permissions or []: perms = RouterPermissions.from_dict(obj) if '..' in perms.uri: trunc = perms.uri[:perms.uri.index('..')] self._wild_permissions[trunc] = perms else: self._permissions[perms.uri] = perms def authorize(self, session, uri, action, options): """ Authorize a session connected under this role to perform the given action on the given URI. :param session: The WAMP session that requests the action. :type session: Instance of :class:`autobahn.wamp.protocol.ApplicationSession` :param uri: The URI on which to perform the action. :type uri: str :param action: The action to be performed. :type action: str :return: bool -- Flag indicating whether session is authorized or not. """ self.log.debug( "CrossbarRouterRoleStaticAuth.authorize {myuri} {uri} {action}", myuri=self.uri, uri=uri, action=action) try: # longest prefix match of the URI to be authorized against our Trie # of configured URIs for permissions permissions = self._permissions.longest_prefix_value(uri) # if there is a _prefix_ matching URI, check that this is actually the # match policy on the permission (otherwise, apply default permissions)! if permissions.match != u'prefix' and uri != permissions.uri: permissions = self._default except KeyError: # workaround because of https://bitbucket.org/gsakkis/pytrie/issues/4/string-keys-of-zero-length-are-not permissions = self._permissions.get(u'', self._default) # if we found a non-"exact" match, there might be a better one in the wildcards if permissions.match != u'exact': try: wildperm = self._wild_permissions.longest_prefix_value(uri) Pattern(wildperm.uri, Pattern.URI_TARGET_ENDPOINT).match(uri) except (KeyError, Exception): # match() raises Exception on no match wildperm = None if wildperm is not None: permissions = wildperm # we now have some permissions, either from matching something # or via self._default if action == u'publish': return { u'allow': permissions.publish, u'disclose': permissions.disclose_publisher, u'cache': permissions.cache } elif action == u'subscribe': return { u'allow': permissions.subscribe, u'cache': permissions.cache } elif action == u'call': return { u'allow': permissions.call, u'disclose': permissions.disclose_caller, u'cache': permissions.cache } elif action == u'register': return { u'allow': permissions.register, u'cache': permissions.cache } else: # should not arrive here raise Exception('logic error')