예제 #1
0
class SubscriptionsHandler():
    """
    Subscription type handlers class to get, edit, and streaming
    subscriptions from the database
    """
    def __init__(self):
        self.db_handler = DBHandler('subscriptions')
        self.db_handler.create_table('id')
        self.users = UsersHandler()
        self.filters = BusFiltersHandler()
        self.templates = TemplatesHandler()

    def get(self, sub_id=None):
        """
        Get all the subscriptions from the database.
        If id is provided search for a single subscription
        :sub_id: Id of the subscription to search for if provided
        """
        return self.db_handler.get_data(sub_id)

    def get_with_relationships(self):
        """
        Get subscriptions joining users and bus_filtes tables
        """
        sub_list = []
        subscriptions = self.db_handler.join_tables("subscriptions", "users",
                                                    "bus_filters", "user_id",
                                                    "filter_id")
        for sub in subscriptions:
            sub_list.append(sub)
        return sub_list

    def get_realtime(self):
        """
        Get all subscriptions from the database in realtime.
        If user is edited in the db it returns the change.
        This method blocks the current thread
        use this method in a separated thread
        """
        return self.db_handler.get_data_streaming()

    def get_users_by_filter(self, bus_filter):
        """
        Get user associates with filter
        :bus_filter: Bus filter to search users
        """
        users = []
        subscriptions = self.get_by_filter(bus_filter)
        for subscription in subscriptions:
            user = self.users.get(subscription['user_id'])
            users.append(user)
        return users

    def get_filters_by_user(self, user):
        """
        Get filters associates with user
        :user: User to seach for bus filters
        """
        filters = []
        subscriptions = self.get_by_user(user)
        for subscription in subscriptions:
            bus_filter = self.filters.get(subscription['filter_id'])
            filters.append(bus_filter)
        return filters

    def get_filters_by_template(self, template):
        """
        Get bus filters assigned to a template
        :template: Template to search for his filters
        """
        filters = []
        subscriptions = self.get_by_template(template)
        for subscription in subscriptions:
            bfilter = self.filters.get(subscription['filter_id'])
            if not any(bus_filter['id'] == bfilter['id']
                       for bus_filter in filters):
                filters.append(bfilter)
        return filters

    def get_by_id(self, subsc_id):
        """
        Get subscription by his id
        :subsc_id: ID of the subscription to search
        """
        return self.db_handler.filter_data({'id': subsc_id})

    def get_by_template(self, template):
        """
        Get subscription searching by his template
        :template: Template to search for
        """
        return self.db_handler.filter_data({'template_id': template['id']})

    def get_by_template_id(self, template_id):
        """
        Get subscription searching by his template id
        :template_id: Template id to search for
        """
        return self.db_handler.filter_data({'template_id': template_id})

    def get_by_filter(self, bus_filter):
        """
        Get subscription by his id
        :bus_filter: Bus filter to search for
        """
        return self.db_handler.filter_data({'filter_id': bus_filter['id']})

    def get_by_filter_id(self, bus_filter_id):
        """
        Get subscription by his id
        :bus_filter: Bus filter to search for
        """
        return self.db_handler.filter_data({'filter_id': bus_filter_id})

    def get_by_user(self, user):
        """
        Get subscription by his id
        :user: User to seach for
        """
        return self.db_handler.filter_data({'user_id': user['id']})

    def insert(self, subscriptions):
        """
        Insert subscriptions to the database
        :subscriptions: Subscription or bus subscriptions to insert
        """
        if isinstance(subscriptions, list):
            for sub in subscriptions:
                if not sub.get('template_id'):
                    sub = self.set_subscription_template(sub)
        else:
            if not subscriptions.get('template_id'):
                subscriptions = self.set_subscription_template(subscriptions)
        return self.db_handler.insert_data(subscriptions)

    def set_subscription_template(self, subscription):
        """
        Sets subscription notification template
        If the bus filter associated with the subscription
        has template uses it. If not create default one
        :subscription: Subscription to add template
        """
        bus_filter = self.filters.get(subscription.get('filter_id'))
        template_id = ''
        if bus_filter:
            if isinstance(bus_filter, list):
                bus_filter = bus_filter[0]
            template_id = bus_filter.get('template_id')
        if not hasattr(subscription,
                       'template_id') and template_id and bus_filter:
            subscription['template_id'] = bus_filter['template_id']
        else:
            subscription['template_id'] = self.templates.get_default_template()
        return subscription

    def edit(self, subscription, subscription_id):
        """
        Modify subscriptions
        :subscription: Modified subscription
        :subscription_id: Id of the subscription to edit
        """
        self.db_handler.edit_data(subscription, subscription_id)

    def delete_user(self, user_id):
        """
        Delete subscriptions associated with the user
        :user_id: user id to search for
        """
        subscriptions = self.get()
        for sub in subscriptions:
            if sub['user_id'] == user_id:
                self.delete(sub['id'])

    def delete_bus_filter(self, bus_filter):
        """
        Delete subscriptions associated with the bus filter
        :bus_filter_id: filter id to search for
        """
        subscriptions = self.db_handler.filter_data(
            {'filter_id': bus_filter['id']})
        for sub in subscriptions:
            self.delete(sub['id'])

    def edit_subscriptions_template(self, bus_filter):
        subscriptions = self.db_handler.filter_data(
            {'filter_id': bus_filter.get('id')})
        for subs in subscriptions:
            subs['template_id'] = bus_filter.get('template_id')
            print(subs)
            self.edit(subs, subs['id'])

    def subscriptions_template(self, template_id):
        """
        Return subscriptions with specific template id
        """
        return self.db_handler.filter_data({'template_id': template_id})

    def delete(self, subscription_id):
        """
        Delete subscription.
        :subscription_id: Subscription id to delete
        """
        self.db_handler.delete_data(subscription_id)
예제 #2
0
class Realtime():
    """
    Realtime class
    """
    def __init__(self):
        self.filters = BusFiltersHandler()
        self.subscriptions = SubscriptionsHandler()
        self.templates = TemplatesHandler()
        Thread(target=self.realtime_subscriptions).start()
        Thread(target=self.realtime_filters).start()
        Thread(target=self.realtime_templates).start()

    def realtime_subscriptions(self):
        """
        Realtime subscriptions.
        If a subscription is removed, the bus connection stops
        If a subscription is updated, recreates the thread
        """
        self.start_connection()

        cursor = self.subscriptions.get_realtime()

        try:
            for subscription in cursor:
                if subscription['old_val'] and not subscription['new_val']:
                    # When a subscription is deleted
                    self.on_subscription_delete(subscription['old_val'])
                if subscription['new_val'] and not subscription['old_val']:
                    # When a subscription is added
                    self.start_connection()
        except BaseException:
            raise ConnectionLost()

    def realtime_filters(self):
        """
        Realtime bus filters. Listening for a template
        change in the database.
        """
        cursor = self.filters.get_realtime()
        try:
            for bus_filter in cursor:
                if bus_filter['old_val'] and not bus_filter['new_val']:
                    # When a bus filter is deleted
                    self.on_bus_filter_delete(bus_filter['old_val'])
                if bus_filter['old_val'] and bus_filter['new_val']:
                    # Bus filter edited
                    old_bus = bus_filter['old_val']
                    new_bus = bus_filter['new_val']
                    if old_bus.get('exchange') != new_bus.get(
                            'exchange') or old_bus.get('key') != new_bus.get(
                                'key'):
                        self.start_connection()

                    if old_bus.get('template_id') != new_bus.get(
                            'template_id'):
                        self.subscriptions.edit_subscriptions_template(new_bus)
        except BaseException:
            raise ConnectionLost()

    def realtime_templates(self):
        """
        Realtime templates. Listening for a template
        change in the database.
        """
        cursor = self.templates.get_realtime()
        try:
            for template in cursor:
                if template['old_val'] and not template['new_val']:
                    self.on_template_deleted(template['old_val'])

        except BaseException:
            raise ConnectionLost()

    def start_connection(self):
        """
        Creates a new connection thread listening
        to the subscriptions stored in the database
        """
        bus_filters = []
        subscriptions_list = self.subscriptions.get()
        if subscriptions_list:
            for sub in subscriptions_list:
                bus_filters.append(self.bus_filter_from_subscription(sub))
            if bus_filters:
                self.create_connection(bus_filters)

    def bus_filter_from_subscription(self, subscription):
        """
        Returns bus filters with the same bus filter id
        than the subscription bus filter
        :subscription: Subscription that is going to look for bus filters
        """
        return self.filters.get(subscription.get('filter_id'))

    def on_subscription_delete(self, subscription):
        """
        If a subscription is deleted, it search if is the
        last subscription with this bus filters. If so, it
        stops listen to this bus filter from the bus
        """
        subscriptions = []
        if isinstance(subscription, list):
            for sub in subscription:
                subscriptions = subscriptions + \
                    self.same_bus_filter_subscription(sub)
        else:
            subscriptions = self.same_bus_filter_subscription(subscription)

        if subscriptions:
            if len(subscriptions) == 1:
                # If only one subscription left, unbind bus filter
                bus_filter = self.bus_filter_from_subscription(subscription)
                self.connection_stop(bus_filter)

    def same_bus_filter_subscription(self, subscription):
        """
        Returns all subscriptions with the same
        bus filter than the provided subscription
        :subscription: Subscription that is going to look for bus filters
        """
        try:
            return self.subscriptions.get_by_filter_id(
                subscription.get('filter_id'))
        except BaseException:
            pass

    def on_bus_filter_delete(self, bus_filter):
        """
        If a bus filter is delete, delete it from
        the subscriptions asociated to and stops
        listening from the bus
        """
        self.subscriptions.delete_bus_filter(bus_filter)
        self.connection_stop(bus_filter)

    def on_template_deleted(self, template):
        """
        If a template is deleted, it search for subscriptions
        and bus filters with that template and replace it with
        default template id.
        """
        template_id = template.get('id')
        subscriptions = self.subscriptions.subscriptions_template(template_id)
        for subscription in subscriptions:
            subscription['template_id'] = self.templates.get_default_template()
            self.subscriptions.edit(subscription, subscription['id'])
        self.filters.delete_template(template_id)

    def create_connection(self, subscriptions):
        """
        Creates a thread with a new rabbitmq connection
        :subscriptions: Subscriptions to add to bus thread
        """
        if not hasattr(self, 'bus_thread'):
            self.bus_thread = BusConnectionHandler(subscriptions)
        else:
            self.bus_thread.set_subscriptions(subscriptions)
        self.bus_thread.start()

    def connection_stop(self, bus_filter=None):
        """
        Search for a thread with the bus_filter to pause and delete it
        """
        if hasattr(self, 'bus_thread'):
            self.bus_thread.stop()
            if bus_filter:
                self.bus_thread.unbind(bus_filter.get('exchange'),
                                       bus_filter.get('key'))