2005-05-24 00:21:07 +00:00
|
|
|
from exceptions import *
|
|
|
|
|
|
|
|
|
|
class SignalMatchNode:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.wildcard = None
|
|
|
|
|
self.finite = {}
|
|
|
|
|
self.rules = []
|
|
|
|
|
|
|
|
|
|
def add(self, key, leaf=None):
|
|
|
|
|
node = None
|
|
|
|
|
|
|
|
|
|
if key:
|
|
|
|
|
if self.finite.has_key(key):
|
|
|
|
|
node = self.finite[key]
|
|
|
|
|
else:
|
|
|
|
|
node = SignalMatchNode()
|
|
|
|
|
self.finite[key] = node
|
|
|
|
|
else:
|
|
|
|
|
if self.wildcard:
|
|
|
|
|
node = self.wildcard
|
|
|
|
|
else:
|
|
|
|
|
node = SignalMatchNode()
|
|
|
|
|
self.wildcard = node
|
|
|
|
|
|
|
|
|
|
node.rules.append(leaf)
|
|
|
|
|
return node
|
|
|
|
|
|
|
|
|
|
def get_matches(self, key):
|
|
|
|
|
result = []
|
|
|
|
|
if self.wildcard:
|
|
|
|
|
result.append(self.wildcard)
|
|
|
|
|
|
|
|
|
|
if self.finite.has_key(key):
|
|
|
|
|
result.append(self.finite[key])
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def get_match(self, key):
|
|
|
|
|
if key:
|
|
|
|
|
if self.finite.has_key(key):
|
|
|
|
|
return self.finite[key]
|
|
|
|
|
else:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
return self.wildcard
|
|
|
|
|
|
|
|
|
|
def has_children(self):
|
|
|
|
|
if self.wildcard or len(self.finite.iterkeys()) > 0:
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def remove_child(self, child, key=None):
|
|
|
|
|
if self.wildcard == child:
|
|
|
|
|
self.wildcard = None
|
|
|
|
|
elif self.finite.had_key(key):
|
|
|
|
|
del self.finite[key]
|
|
|
|
|
|
|
|
|
|
class SignalMatchTree:
|
|
|
|
|
"""This class creates an ordered tree of SignalMatchRules
|
|
|
|
|
to speed searchs. Left branches are wildcard elements
|
|
|
|
|
and all other branches are concreet elements.
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self._tree = SignalMatchNode()
|
|
|
|
|
|
|
|
|
|
def add(self, rule):
|
|
|
|
|
interface = self._tree.add(rule.sender)
|
|
|
|
|
signal = interface.add(rule.dbus_interface)
|
|
|
|
|
path = signal.add(rule.signal_name)
|
|
|
|
|
path.add(rule.path, leaf=rule)
|
|
|
|
|
|
2005-05-24 16:30:51 +00:00
|
|
|
def exec_matches(self, match_rule, message):
|
2005-05-24 00:21:07 +00:00
|
|
|
sender_matches = self._tree.get_matches(match_rule.sender)
|
|
|
|
|
for sender_node in sender_matches:
|
|
|
|
|
interface_matches = sender_node.get_matches(match_rule.dbus_interface)
|
|
|
|
|
for interface_node in interface_matches:
|
|
|
|
|
signal_matches = interface_node.get_matches(match_rule.signal_name)
|
|
|
|
|
for signal_node in signal_matches:
|
|
|
|
|
path_matches = signal_node.get_matches(match_rule.path)
|
|
|
|
|
for path_node in path_matches:
|
|
|
|
|
if(path_node.rules):
|
|
|
|
|
for rule in path_node.rules:
|
2005-05-24 16:30:51 +00:00
|
|
|
rule.execute(message)
|
2005-05-24 00:21:07 +00:00
|
|
|
|
|
|
|
|
def remove(self, rule):
|
|
|
|
|
try:
|
|
|
|
|
sender = self._tree.get_match(rule.sender)
|
|
|
|
|
interface = sender.get_match(rule.dbus_interface)
|
|
|
|
|
signal = interface.get_match(rule.signal_name)
|
|
|
|
|
path = signal.get_match(rule.path)
|
|
|
|
|
|
|
|
|
|
rule_matches = []
|
|
|
|
|
for _rule in path.rules:
|
|
|
|
|
if _rule.is_match(rule):
|
|
|
|
|
rule_matches.append(_rule)
|
|
|
|
|
|
|
|
|
|
for _rule in rule_matches:
|
|
|
|
|
path.rules.remove(_rule)
|
|
|
|
|
|
|
|
|
|
#clean up tree
|
|
|
|
|
if len(path.rules) == 0:
|
|
|
|
|
signal.remove_child(path, key = rule.path)
|
|
|
|
|
if not signal.has_children():
|
|
|
|
|
interface.remove_child(signal, key = rule.signal_name)
|
|
|
|
|
if not interface.has_children():
|
|
|
|
|
sender.remove_child(interface, key = rule.dbus_interface)
|
|
|
|
|
if not sender.has_children():
|
|
|
|
|
self._tree.remove_child(sender, key = rule.sender)
|
|
|
|
|
|
|
|
|
|
except:
|
|
|
|
|
raise DBusException ("Trying to remove unkown rule: %s"%str(rule))
|
|
|
|
|
|
|
|
|
|
class SignalMatchRule:
|
|
|
|
|
"""This class represents a dbus rule used to filter signals.
|
|
|
|
|
When a rule matches a filter, the signal is propagated to the handler_funtions
|
|
|
|
|
"""
|
|
|
|
|
def __init__(self, signal_name, dbus_interface, sender, path):
|
|
|
|
|
self.handler_functions = []
|
|
|
|
|
|
|
|
|
|
self.signal_name = signal_name
|
|
|
|
|
self.dbus_interface = dbus_interface
|
|
|
|
|
self.sender = sender
|
|
|
|
|
self.path = path
|
|
|
|
|
|
2005-05-24 16:30:51 +00:00
|
|
|
def execute(self, message):
|
|
|
|
|
args = message.get_args_list()
|
2005-05-24 00:21:07 +00:00
|
|
|
for handler in self.handler_functions:
|
2005-05-24 16:30:51 +00:00
|
|
|
if getattr(handler, "_dbus_pass_message", False):
|
|
|
|
|
keywords = {"dbus_message": message}
|
|
|
|
|
handler(*args, **keywords)
|
|
|
|
|
else:
|
|
|
|
|
handler(*args)
|
2005-05-24 00:21:07 +00:00
|
|
|
|
|
|
|
|
def add_handler(self, handler):
|
|
|
|
|
self.handler_functions.append(handler)
|
|
|
|
|
|
|
|
|
|
def is_match(self, rule):
|
|
|
|
|
if (self.signal_name == rule.signal_name and
|
|
|
|
|
self.dbus_interface == rule.dbus_interface and
|
|
|
|
|
self.sender == rule.sender and
|
|
|
|
|
self.path == rule.path):
|
|
|
|
|
_funcs_copy_a = self.dbus.handler_functions[0:]
|
|
|
|
|
_funcs_copy_b = rule.dbus.handler_functions[0:]
|
|
|
|
|
_funcs_copy_a.sort()
|
|
|
|
|
_funcs_copy_b.sort()
|
|
|
|
|
return a == b
|
|
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
|
"""Returns a custom representation of this DBusMatchRule that can
|
|
|
|
|
be used with dbus_bindings
|
|
|
|
|
"""
|
|
|
|
|
repr = "type='signal'"
|
|
|
|
|
if (self.dbus_interface):
|
|
|
|
|
repr = repr + ",interface='%s'" % (self.dbus_interface)
|
|
|
|
|
|
|
|
|
|
if (self.sender):
|
|
|
|
|
repr = repr + ",sender='%s'" % (self.sender)
|
|
|
|
|
|
|
|
|
|
if (self.path):
|
|
|
|
|
repr = repr + ",path='%s'" % (self.path)
|
|
|
|
|
|
|
|
|
|
if (self.signal_name):
|
|
|
|
|
repr = repr + ",member='%s'" % (self.signal_name)
|
|
|
|
|
|
|
|
|
|
return repr
|