def __init__(self, pyrebase_app, root_path, ttl=None): self._app = pyrebase_app self._root_path = root_path self._ttl = ttl self._db = self._app.database() self._streams = {} self._gc_streams = queue.Queue() self._gc_thread = None self._cache = None self.events = Namespace() self._handlers = { 'put': self._put_handler, 'patch': self._patch_handler, }
def __init__(self, pyrebase_app, root_path, ttl=None, retry_interval=None): self._app = pyrebase_app self._root_path = root_path self._ttl = ttl self._retry_interval = (RETRY_INTERVAL if retry_interval is None else retry_interval) self._db = self._app.database() self._streams = {} self._gc_streams = queue.Queue() self._gc_thread = None self._cache = None self.events = Namespace() self._handlers = { 'put': self._put_handler, 'patch': self._patch_handler, }
class LiveData(object): def __init__(self, pyrebase_app, root_path, ttl=None, retry_interval=None): self._app = pyrebase_app self._root_path = root_path self._ttl = ttl self._retry_interval = (RETRY_INTERVAL if retry_interval is None else retry_interval) self._db = self._app.database() self._streams = {} self._gc_streams = queue.Queue() self._gc_thread = None self._cache = None self.events = Namespace() self._handlers = { 'put': self._put_handler, 'patch': self._patch_handler, } def get_data(self): if self._cache is None: # Fetch data now value = self._db.child(self._root_path).get().val() self._cache = data.FirebaseData(value) # Listen for updates self.listen() return self._cache def get_data_silent(self): try: return self.get_data() except Exception: logger.exception('Error getting data') def set_data(self, path, value): path_list = data.get_path_list(path) child = self._db.child(self._root_path) for path_part in path_list: child = child.child(path_part) child.set(value) def is_stale(self): if self._ttl is None: return False data = self.get_data() if data is None or data.last_updated_at is None: logger.debug('Data is invalid: %s', data) return True stale = datetime.datetime.utcnow() - data.last_updated_at > self._ttl if stale: logger.debug('Data is stale: %s', data) else: logger.debug('Data is fresh: %s', data) return stale def signal(self, path, doc=None): norm_path = data.normalize_path(path) return self.events.signal(norm_path, doc=doc) def listen(self): stream = self._db.child(self._root_path).stream(self._stream_handler) self._streams[id(stream)] = stream self._start_stream_gc() watcher.watch(id(self), self.is_stale, self.restart, interval=self._ttl) # If the stream and stale watcher are established, # the metawatcher is no longer needed. self.cancel_metawatcher() def get_metawatcher_name(self): return 'meta_{}'.format(id(self)) def start_metawatcher(self): watcher.watch(self.get_metawatcher_name(), lambda: self._cache is None, self.get_data_silent, interval=self._retry_interval) def cancel_metawatcher(self): watcher.cancel(self.get_metawatcher_name()) def restart(self): self.reset() self.start_metawatcher() self.get_data_silent() def reset(self): logger.debug('Resetting all data') self.hangup(block=False) self._cache = None def hangup(self, block=True): logger.debug('Marking all streams for shut down') watcher.cancel(id(self)) for stream in self._streams.values(): self._gc_streams.put(stream) if block: self._gc_streams.join() def _set_path_value(self, path, value): data = self.get_data() data.set(path, value) self._recurse_signal(path) def _recurse_signal(self, path): path_list = data.get_path_list(path) partial_path = '' value = self.get_data() self.signal('/').send(value, value=value.get(), path=path) for part in path_list: partial_path = '/'.join((partial_path, part)) self.signal(partial_path).send(value, value=value.get(partial_path), path=path) def _put_handler(self, path, value): logger.debug('PUT: path=%s data=%s', path, value) self._set_path_value(path, value) def _patch_handler(self, path, all_values): logger.debug('PATCH: path=%s data=%s', path, all_values) for rel_path, value in all_values.items(): full_path = data.normalize_path('{}/{}'.format(path, rel_path)) self._set_path_value(full_path, value) def _valid_message(self, message): required_keys = [ 'event', 'path', 'data', ] valid_keys = all(k in message for k in required_keys) if not valid_keys: return False if message['event'] not in self._handlers: return False return True def _stream_handler(self, message): logger.debug('STREAM received: %s', message) if not self._valid_message(message): logger.warn('Invalid message: %s', message) return handler = self._handlers[message['event']] handler(message['path'], message['data']) def _gc_stream_worker(self): while True: stream = self._gc_streams.get() logger.debug('Closing stream: %s', stream) try: stream.close() del self._streams[id(stream)] except Exception as e: logger.warning('Error closing stream %s: %s', stream, e) else: logger.debug('Stream closed: %s', stream) self._gc_streams.task_done() def _start_stream_gc(self): if self._gc_thread is None: self._gc_thread = threading.Thread(target=self._gc_stream_worker, daemon=True) self._gc_thread.start()
# coding=utf-8 """""" from blinker.base import Namespace # pylint: disable=C0103 # invalid constant name ns = Namespace() #: sent when membership is set. Sender is community, arguments are: #: :class:`.models.Membership` instance, :bool:`is_new` membership_set = ns.signal("membership_set") #: sent just before membership is removed. Sender is community, arguments: # :class:`.models.Membership` instance membership_removed = ns.signal("membership_removed")
from blinker.base import Namespace SIG_ROLES_EDITED = 'roles-edited' SIG_ROLES_ADDED = 'roles-added' SIG_ACC_CREATED = 'acc-created' SIG_ACC_STATUS_CHANGE = 'acc-status-change' waitlist_bps = Namespace() roles_changed_sig = waitlist_bps.signal( SIG_ROLES_EDITED, "Called when roles are changed on an account") account_created_sig = waitlist_bps.signal( SIG_ACC_CREATED, 'Called when a new Waitlist Account is created') account_status_change_sig = waitlist_bps.signal( SIG_ACC_STATUS_CHANGE, 'Called when an account is enabled or disabled') roles_added_sig = waitlist_bps.signal(SIG_ROLES_ADDED, 'Called when a new role is added') def send_roles_changed(sender, to_id, by_id, added_roles, removed_roles, note): roles_changed_sig.send(sender, to_id=to_id, by_id=by_id, added_roles=added_roles, removed_roles=removed_roles, note=note) def send_roles_added(sender, by_id, role_name, role_display_name): roles_added_sig.send(sender, by_id=by_id, role_name=role_name,
"""All signals used by Abilian Core. Signals are the main tools used for decoupling applications components by sending notifications. In short, signals allow certain senders to notify subscribers that something happened. Cf. http://flask.pocoo.org/docs/signals/ for detailed documentation. The main signal is currently :obj:`activity`. """ from blinker.base import Namespace signals = Namespace() #: Triggered at application initialization when all extensions and plugins have #: been loaded components_registered = signals.signal("app:components:registered") #: Trigger when JS api must be registered. At this time :func:`flask.url_for` is #: usable register_js_api = signals.signal("app:register-js-api") #: This signal is used by the activity streams service and its clients. activity = signals.signal("activity") #: This signal is sent when user object has been loaded. g.user and current_user #: are available. user_loaded = signals.signal("user_loaded") auth_failed = signals.signal("auth_failed")
SIG_ROLES_EDITED = 'roles-edited' SIG_ROLES_ADDED = 'roles-added' SIG_ROLES_REMOVED = 'roles-removed' SIG_ACC_CREATED = 'acc-created' SIG_ACC_STATUS_CHANGE = 'acc-status-change' SIG_ALT_LINK_REMOVED = 'alt-link-removed' SIG_ALT_LINK_ADDED = 'alt-link-added' SIG_ACCOUNT_NAME_CHANGE = 'acc-namec-change' SIG_FLEET_REMOVED = 'fleet-removed' SIG_FLEET_ADDED_FIRST = 'fleet-added-first' SIG_FLEET_REMOVED_LAST = 'fleet-removed-last' waitlist_bps = Namespace() roles_changed_sig = waitlist_bps.\ signal(SIG_ROLES_EDITED, "Called when roles are changed on an account") account_created_sig = waitlist_bps.\ signal(SIG_ACC_CREATED, 'Called when a new Waitlist Account is created') account_status_change_sig = waitlist_bps.\ signal(SIG_ACC_STATUS_CHANGE, 'Called when an account is enabled or disabled') role_created_sig = waitlist_bps.\ signal(SIG_ROLES_ADDED, 'Called when a new role is created') role_removed_sig = waitlist_bps.\
# coding=utf-8 """""" from __future__ import absolute_import, print_function, unicode_literals from blinker.base import Namespace # pylint: disable=C0103 # invalid constant name ns = Namespace() #: sent when membership is set. Sender is community, arguments are: #: :class:`.models.Membership` instance, :bool:`is_new` membership_set = ns.signal("membership_set") #: sent just before membership is removed. Sender is community, arguments: # :class:`.models.Membership` instance membership_removed = ns.signal("membership_removed")
#!/usr/bin/env python # coding=utf8 __version__ = '0.5.dev1' from blinker.base import Namespace, Signal namespace = Namespace() user_id_changed = namespace.signal('user_id_changed') user_id_reset = namespace.signal('user_id_reset')
All signals used by Abilian Core. Signals are the main tools used for decoupling applications components by sending notifications. In short, signals allow certain senders to notify subscribers that something happened. Cf. http://flask.pocoo.org/docs/signals/ for detailed documentation. The main signal is currently :obj:`activity`. """ from __future__ import absolute_import from blinker.base import Namespace signals = Namespace() #: Triggered at application initialization when all extensions and plugins have #: been loaded components_registered = signals.signal("app:components:registered") #: This signal is used by the activity streams service and its clients. activity = signals.signal("activity") #: Currently not used and subject to change. entity_created = signals.signal("entity:created") #: Currently not used and subject to change. entity_updated = signals.signal("entity:updated")
""" All signals used by Abilian Core. Cf. http://flask.pocoo.org/docs/signals/ for detailed documentation. These signals are currently not used, and for this reason subject to change. """ from blinker.base import Namespace signals = Namespace() entity_created = signals.signal("entity:created") entity_updated = signals.signal("entity:updated") entity_deleted = signals.signal("entity:deleted") #user_created = signals.signal("user:created") #user_deleted = signals.signal("user:deleted") activity = signals.signal("activity")
# coding=utf-8 """All signals used by Abilian Core. Signals are the main tools used for decoupling applications components by sending notifications. In short, signals allow certain senders to notify subscribers that something happened. Cf. http://flask.pocoo.org/docs/signals/ for detailed documentation. The main signal is currently :obj:`activity`. """ from blinker.base import Namespace signals = Namespace() #: Triggered at application initialization when all extensions and plugins have #: been loaded components_registered = signals.signal("app:components:registered") #: Trigger when JS api must be registered. At this time :func:`flask.url_for` is #: usable register_js_api = signals.signal("app:register-js-api") #: This signal is used by the activity streams service and its clients. activity = signals.signal("activity") #: This signal is sent when user object has been loaded. g.user and current_user #: are available. user_loaded = signals.signal("user_loaded")
All signals used by Abilian Core. Signals are the main tools used for decoupling applications components by sending notifications. In short, signals allow certain senders to notify subscribers that something happened. Cf. http://flask.pocoo.org/docs/signals/ for detailed documentation. The main signal is currently :obj:`activity`. """ from __future__ import absolute_import, print_function, division from blinker.base import Namespace signals = Namespace() #: Triggered at application initialization when all extensions and plugins have #: been loaded components_registered = signals.signal("app:components:registered") #: Trigger when JS api must be registered. At this time :func:`flask.url_for` is #: usable register_js_api = signals.signal('app:register-js-api') #: This signal is used by the activity streams service and its clients. activity = signals.signal("activity") #: This signal is sent when user object has been loaded. g.user and current_user #: are available. user_loaded = signals.signal('user_loaded')
# coding=utf-8 """ """ from __future__ import absolute_import from blinker.base import Namespace # pylint: disable=C0103 # invalid constant name ns = Namespace() #: sent when membership is set. Sender is community, arguments are: #: :class:`.models.Membership` instance, :bool:`is_new` membership_set = ns.signal('membership_set') #: sent just before membership is removed. Sender is community, arguments: # :class:`.models.Membership` instance membership_removed = ns.signal('membership_removed')
Signals are the main tools used for decoupling applications components by sending notifications. In short, signals allow certain senders to notify subscribers that something happened. Cf. http://flask.pocoo.org/docs/signals/ for detailed documentation. The main signal is currently :obj:`activity`. """ from __future__ import absolute_import, division, print_function, \ unicode_literals from blinker.base import Namespace signals = Namespace() #: Triggered at application initialization when all extensions and plugins have #: been loaded components_registered = signals.signal("app:components:registered") #: Trigger when JS api must be registered. At this time :func:`flask.url_for` is #: usable register_js_api = signals.signal('app:register-js-api') #: This signal is used by the activity streams service and its clients. activity = signals.signal("activity") #: This signal is sent when user object has been loaded. g.user and current_user #: are available. user_loaded = signals.signal('user_loaded')