1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
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.has_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)
def exec_matches(self, match_rule, message):
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:
rule.execute(message)
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
def execute(self, message):
args = message.get_args_list()
for handler in self.handler_functions:
if getattr(handler, "_dbus_pass_message", False):
keywords = {"dbus_message": message}
handler(*args, **keywords)
else:
handler(*args)
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):
if rule.handler_functions == []:
return True
_funcs_copy_a = self.handler_functions[0:]
_funcs_copy_b = rule.handler_functions[0:]
_funcs_copy_a.sort()
_funcs_copy_b.sort()
return _funcs_copy_a == _funcs_copy_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
|