17
17
# with this program. If not, see <http://www.gnu.org/licenses/>.
18
18
"""Module that implements the Event Queue machinery."""
23
from Queue import Queue, Empty
25
24
from ubuntuone.platform import FilesystemMonitor
27
class InvalidEventError(Exception):
28
"""Received an Event that is not in the allowed list."""
30
26
# these are our internal events, what is inserted into the whole system
32
28
'FS_FILE_OPEN': ('path',),
179
175
self.monitor = FilesystemMonitor(self, fs, ignore_config)
181
177
self.dispatching = False
182
self.dispatch_queue = Queue()
178
self.dispatch_queue = collections.deque()
179
self._have_empty_eq_cback = False
183
180
self.empty_event_queue_callbacks = set()
185
182
def add_to_mute_filter(self, event, **info):
193
190
def add_empty_event_queue_callback(self, callback):
194
191
"""Add a callback for when the even queue has no more events."""
192
self._have_empty_eq_cback = True
195
193
self.empty_event_queue_callbacks.add(callback)
196
if not self.dispatching and self.dispatch_queue.empty():
194
if not self.dispatching and not self.dispatch_queue:
197
195
if callable(callback):
200
198
def remove_empty_event_queue_callback(self, callback):
201
199
"""Remove the callback."""
202
200
self.empty_event_queue_callbacks.remove(callback)
201
if not self.empty_event_queue_callbacks:
202
self._have_empty_eq_cback = False
204
204
def shutdown(self):
205
205
"""Make the monitor shutdown."""
232
235
These objects should provide a 'handle_FOO' to receive the FOO
233
236
events (replace FOO with the desired event).
235
if obj not in self._listeners:
236
self._listeners.append(obj)
238
for event_name in EVENTS.keys():
239
meth_name = "handle_" + event_name
240
method = self._get_listener_method(obj, meth_name, event_name)
241
if method is not None:
242
self.listener_map.setdefault(event_name, {})[obj] = method
238
244
def push(self, event_name, **kwargs):
239
245
"""Receives a push for all events.
251
257
self.log.debug(log_msg, event_name, kwargs)
253
# get the event parameters
255
event_params = EVENTS[event_name]
257
msg = "The received event_name (%r) is not valid!" % event_name
259
raise InvalidEventError(msg)
261
# validate that the received arguments are ok
262
s_eventparms = set(event_params)
263
s_kwargs = set(kwargs.keys())
264
if s_eventparms != s_kwargs:
265
msg = "Wrong arguments for event %s (should receive %s, got %s)" \
266
% (event_name, event_params, kwargs.keys())
270
259
# check if we are currently dispatching an event
271
self.dispatch_queue.put((event_name, kwargs))
260
self.dispatch_queue.append((event_name, kwargs))
272
261
if not self.dispatching:
273
262
self.dispatching = True
276
event_name, kwargs = self.dispatch_queue.get(block=False)
265
event_name, kwargs = self.dispatch_queue.popleft()
277
266
self._dispatch(event_name, **kwargs)
279
268
self.dispatching = False
280
for callable in self.empty_event_queue_callbacks.copy():
269
if self._have_empty_eq_cback:
270
for cback in self.empty_event_queue_callbacks.copy():
284
274
def _dispatch(self, event_name, **kwargs):
285
275
""" push the event to all listeners. """
277
listeners = self.listener_map[event_name]
279
# no listener for this
286
282
# check listeners to see if have the proper method, and call it
287
meth_name = "handle_" + event_name
288
for listener in self._listeners:
289
# don't use hasattr because is expensive and
290
# catch too many errors
291
# we need to catch all here, pylint: disable-msg=W0703
292
method = self._get_listener_method(listener, meth_name, event_name)
293
if method is not None:
297
self.log.exception("Error encountered while handling: %s"
298
" in %s", event_name, listener)
283
for listener, method in listeners.items():
287
self.log.exception("Error encountered while handling: %s "
288
"in %s", event_name, listener)
300
290
def _get_listener_method(self, listener, method_name, event_name):
301
291
""" returns the method named method_name or hanlde_default from the