Ejemplo n.º 1
0
class LogEvents(YomboLibrary):
    """
    Manages all notifications.

    """
    def _init_(self):
        """
        Setups up the basic framework.
        """
        # We only cache the last few events, and only for certain time.
        self.notifications = ExpiringDict(max_len=100, max_age_seconds=600)
        # return self.init_deferred

    def _load_(self):
        self._LocalDB = self._Libraries['localdb']
        self._checkExpiredLoop = LoopingCall(self.check_expired)
        self._checkExpiredLoop.start(self._Configs.get('notifications', 'check_expired', 30, False))
        self.load_notifications()


    def _stop_(self):
        if self.init_deferred is not None and self.init_deferred.called is False:
            self.init_deferred.callback(1)  # if we don't check for this, we can't stop!

    def _clear_(self):
        """
        Clear all devices. Should only be called by the loader module
        during a reconfiguration event. B{Do not call this function!}
        """
        self.notifications.clear()

    def _reload_(self):
        self._clear_()
        self.load_notifications()

    def check_expired(self):
        """
        Called by looping call to periodically purge expired notifications.
        :return:
        """
        cur_time = int(time())
        for id, notice in self.notifications.iteritems():
            print "cur : expired = %s : %s" % (cur_time, notice.expire)
            if cur_time > notice.expire:
                print "deleting notice: %s" % notice.title
                del self.notifications[id]
        self._LocalDB.delete_expired_notifications()

    def get(self, notification_requested):
        """
        Performs the actual search.

        .. note::

           Modules shouldn't use this function. Use the built in reference to
           find notification: `self._Notifications['8w3h4sa']`

        :raises YomboWarning: Raised when notifcation cannot be found.
        :param notification_requested: The input type ID or input type label to search for.
        :type notification_requested: string
        :return: A dict containing details about the notification
        :rtype: dict
        """
        if notification_requested in self.notifications:
            return self.notifications[notification_requested]
        else:
            raise YomboWarning('Notification not found: %s' % notification_requested)

    def delete(self, notification_requested):
        """
        Deletes a provided notification.

        :param notification_requested:
        :return:
        """
        try:
            del self.notifications[notification_requested]
        except:
            pass
        self._LocalDB.delete_notification(notification_requested)

    @inlineCallbacks
    def load_notifications(self):
        """
        Load the last few notifications into memory.
        """
        notifications = yield self._LocalDB.get_notifications()
        for notice in notifications:
            notice = notice.__dict__
            if notice['expire'] < int(time()):
                continue
            notice['meta'] = json.loads(notice['meta'])
            self.add_notice(notice, from_db=True)
        logger.debug("Done load_notifications: {notifications}", notifications=self.notifications)
        # self.init_deferred.callback(10)

    def add_notice(self, notice, from_db=False, persist=True, create_event=False):
        """
        Add a new notice.

        :param notice: A dictionary containing notification details.
        :type record: dict
        :returns: Pointer to new notice. Only used during unittest
        """
        print "adding notice1: %s" % notice
        if 'id' not in notice:
            notice['id'] = random_string(length=16)
        if 'type' not in notice:
            notice['type'] = 'system'
        if 'priority' not in notice:
            notice['priority'] = 'normal'
        if 'source' not in notice:
            notice['source'] = ''

        if 'expire' not in notice:
            if 'timeout' in notice:
                notice['expire'] = int(time()) + notice['timeout']
            else:
                notice['expire'] = int(time()) + 3600
        else:
            if notice['expire'] > int(time()):
                YomboWarning("New notification is set to expire before current time.")
        if 'created' not in notice:
            notice['created'] = int(time())

        if 'acknowledged' not in notice:
            notice['acknowledged'] = False
        else:
            if notice['acknowledged'] not in (True, False):
                YomboWarning("New notification 'acknowledged' must be either True or False.")

        if 'title' not in notice:
            raise YomboWarning("New notification requires a title.")
        if 'message' not in notice:
            raise YomboWarning("New notification requires a message.")
        if 'meta' not in notice:
            notice['meta'] = {}

        logger.debug("notice: {notice}", notice=notice)
        if from_db is False:
            self._LocalDB.add_notification(notice)
            self.notifications.prepend(notice['id'], Notification(notice))
        else:
            self.notifications[notice['id']] = Notification(notice)
            # self.notifications = OrderedDict(sorted(self.notifications.iteritems(), key=lambda x: x[1]['created']))
            pass
        return notice['id']
Ejemplo n.º 2
0
class YomboAPI(YomboLibrary):

    contentType = None

    def _init_(self):
        self.custom_agent = Agent(reactor, connectTimeout=20)
        self.contentType = self._Configs.get('yomboapi', 'contenttype', 'application/json', False)  # TODO: Msgpack later
        self.base_url = self._Configs.get('yomboapi', 'baseurl', "https://api.yombo.net/api", False)
        self.allow_system_session = self._Configs.get('yomboapi', 'allow_system_session', True)
        self.init_defer = None

        self.api_key = self._Configs.get('yomboapi', 'api_key', 'aBMKp5QcQoW43ipauw88R0PT2AohcE', False)
        self.valid_system_session = None
        self.session_validation_cache = ExpiringDict()

        if self.allow_system_session:
            self.system_session = self._Configs.get('yomboapi', 'auth_session')  # to be encrypted with gpg later
            self.system_login_key = self._Configs.get('yomboapi', 'login_key')  # to be encrypted with gpg later
        else:
            self.system_session = None
            self.system_login_key = None

    def _load_(self):
        if self._Atoms['loader.operation_mode'] == 'run':
            self.init_defer = Deferred()
            self.validate_system_login()
            return self.init_defer

    def _start_(self):
        # print "system_session status: %s" % self.system_session
        # print "system_login_key status: %s" % self.system_login_key
        pass

    def _stop_(self):
        pass

    def _unload_(self):
        pass

    @inlineCallbacks
    def gateway_index(self, session=None):
        results = yield self.request("GET", "/v1/gateway", None, session)
        if results['code'] == 200:
            returnValue(results)
        elif results['code'] == 404:
            raise YomboWarning("Server cannot get gateways")
        else:
            if results['content']['message'] == "Invalid Token.":
                raise YomboWarningCredentails("URI: '%s' requires credentials." % results['content']['response']['uri'])
            raise YomboWarning("Unknown error: %s" % results['content'])

    @inlineCallbacks
    def gateway_get(self, gateway_id, session=None):
        results = yield self.request("GET", "/v1/gateway/%s" % gateway_id, None, session)
        if results['code'] == 200:
            returnValue(results)
        elif results['code'] == 404:
            raise YomboWarning("Server cannot find requested gateway: %s" % gateway_id)
        else:
            raise YomboWarning("Unknown error: %s" % results['content']['message'])

    @inlineCallbacks
    def gateway_put(self, gateway_id, values, session=None):
        results = yield self.request("PATCH", "/v1/gateway/%s" % gateway_id, values, session)
        if results['code'] == 200:
            returnValue(results)
        elif results['code'] == 404:
            raise YomboWarning("Server cannot find requested gateway: %s" % gateway_id)
        else:
            raise YomboWarning("Unknown error: %s" % results['content']['message'])

    @inlineCallbacks
    def gateway__module_get(self, gateway_id, session=None):
        results = yield self.request("GET", "/v1/gateway/%s/modules" % gateway_id, None, session)
        if results['code'] == 200:
            returnValue(results)
        elif results['code'] == 404:
            raise YomboWarning("Server cannot find requested gateway: %s" % gateway_id)
        else:
            raise YomboWarning("Unknown error: %s" % results['content']['message'])

    @inlineCallbacks
    def gateway__module_put(self, gateway_id, values, session=None):
        results = yield self.request("PATCH", "/v1/gateway/%s/modules" % gateway_id, values, session)
        if results['code'] == 200:
            returnValue(results)
        elif results['code'] == 404:
            raise YomboWarning("Server cannot find requested gateway: %s" % gateway_id)
        else:
            raise YomboWarning("Unknown error: %s" % results['content']['message'])

    @inlineCallbacks
    def gateway_config_index(self, gateway_id, session=None):
        results = yield self.request("GET", "/v1/gateway/%s/config" % gateway_id, None, session)
        if results['code'] == 200:
            returnValue(results)
        elif results['code'] == 404:
            raise YomboWarning("Server cannot get gateways")
        else:
            raise YomboWarning("Unknown error: %s" % results['content']['message'])

    # Below are the core help functions

    def save_system_session(self, session):
        print "api save_system_session0: %s" % session
        self.system_session = session
        print "api save_system_session1: %s" % session
        self._Configs.set('yomboapi', 'auth_session', session)  # to be encrypted with gpg later
        print "api save_system_session2: %s" % session

    def save_system_login_key(self, login_key):
        print "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@api save_system_login_key: %s" % login_key
        self.system_login_key = login_key
        print "api save_system_login_key1: %s" % login_key
        self._Configs.set('yomboapi', 'login_key', login_key)  # to be encrypted with gpg later
        print "api save_system_login_key2: %s" % login_key

    def select_session(self, session_id=None, session_key=None):
        if session_id is None or session_key is None:
            if self.allow_system_session:
                return self.system_session, self.system_login_key

        logger.info("select_session: Yombo API has no session data for 'selection_session'")
        return None, None

    def clear_session_cache(self, session=None):
        if (session is None):
            self.session_validation_cache.clear()
        else:
            hashed = sha1(session)
            if hashed in self.session_validation_cache:
                del self.session_validation_cache[hashed]  # None works too...

    @inlineCallbacks
    def validate_system_login(self):
        """
        Validates a system session if it exists. If not, it tries the login_key and creates a new session.

        :return:
        """
        if self.allow_system_session is False:
            self._States.set('yomboapi.valid_system_session', False)
            self.init_defer.callback(10)
            returnValue(False)

        if self.system_session is None and self.system_login_key is None:
            print "validate_system_login: self.system_session: %s" % self.system_session
            print "validate_system_login: self.system_login_key: %s" % self.system_login_key
            logger.warn("No saved system session information and no login_key. Disabling automated system changes.")
            self._States.set('yomboapi.valid_system_session', False)
            self.valid_system_session = False
            if self.init_defer is not None:
                self.init_defer.callback(10)
            returnValue(None)

        self.clear_session_cache()
        if self.system_session is not None:
            results = yield self.do_validate_session(self.system_session)
            if (results is True):
                print "has a system session!"
                self._States.set('yomboapi.valid_system_session', True)
                self.valid_system_session = True
                self.init_defer.callback(10)
                returnValue(True)

        if self.system_login_key is not None:
            results = yield self.user_login_with_key(self.system_login_key)
            print "reslts: %s" % results
            if (results is not False):
                print "has a system login key!"
                self._Configs.set('yomboapi', 'auth_session', results['session'])  # to be encrypted with gpg later
                self.system_session = results['session']
                self._States.set('yomboapi.valid_system_session', True)
                self.valid_system_session = True
                self.init_defer.callback(10)
                returnValue(True)

        print "API system has some data, but it's invalid!"
        self._States.set('yomboapi.valid_system_session', False)
        self.valid_system_session = False
        self.init_defer.callback(10)
        returnValue(False)

    @inlineCallbacks
    def validate_session(self, session_id=None, session_key=None, clear_cache=False):
        session_id, session_key = self.select_session(session_id, session_key)
        if session_id is None or session_key is None:
            logger.debug("Yombo API session information is not valid: {id}:{key}", id=session_id, key=session_key)

        hashed = sha1(session_id + session_key)
        if hashed in self.session_validation_cache:
            if clear_cache is True:
                del self.session_validation_cache[hashed]
            else:
                returnValue(self.session_validation_cache[hashed])

        results = yield self.do_validate_session(session_id, session_key)
        self.session_validation_cache[hashed] = results
        returnValue(results)

    @inlineCallbacks
    def do_validate_session(self, session):
        try:
            results = yield self.request("GET", "/v1/user/session/validate", None, session)
        except Exception, e:
            logger.debug("$$$1 API Errror: {error}", error=e)
            returnValue(False)


        logger.debug("$$$a REsults from API: {results}", results=results['content'])
# waiting on final API.yombo.com to complete this.  If we get something, we are good for now.

        if (results['content']['code'] != 200):
            returnValue(False)
        elif (results['content']['response']['session_status'] == 'valid'):
            returnValue(True)
        else:
            returnValue(False)
Ejemplo n.º 3
0
class LogEvents(YomboLibrary):
    """
    Manages all notifications.

    """
    def _init_(self):
        """
        Setups up the basic framework.
        """
        # We only cache the last few events, and only for certain time.
        self.notifications = ExpiringDict(max_len=100, max_age_seconds=600)
        # return self.init_deferred

    def _load_(self):
        self._LocalDB = self._Libraries['localdb']
        self._checkExpiredLoop = LoopingCall(self.check_expired)
        self._checkExpiredLoop.start(
            self._Configs.get('notifications', 'check_expired', 30, False))
        self.load_notifications()

    def _stop_(self):
        if self.init_deferred is not None and self.init_deferred.called is False:
            self.init_deferred.callback(
                1)  # if we don't check for this, we can't stop!

    def _clear_(self):
        """
        Clear all devices. Should only be called by the loader module
        during a reconfiguration event. B{Do not call this function!}
        """
        self.notifications.clear()

    def _reload_(self):
        self._clear_()
        self.load_notifications()

    def check_expired(self):
        """
        Called by looping call to periodically purge expired notifications.
        :return:
        """
        cur_time = int(time())
        for id, notice in self.notifications.items():
            print("cur : expired = %s : %s" % (cur_time, notice.expire))
            if cur_time > notice.expire:
                print("deleting notice: %s" % notice.title)
                del self.notifications[id]
        self._LocalDB.delete_expired_notifications()

    def get(self, notification_requested):
        """
        Performs the actual search.

        .. note::

           Modules shouldn't use this function. Use the built in reference to
           find notification: `self._Notifications['8w3h4sa']`

        :raises YomboWarning: Raised when notifcation cannot be found.
        :param notification_requested: The input type ID or input type label to search for.
        :type notification_requested: string
        :return: A dict containing details about the notification
        :rtype: dict
        """
        if notification_requested in self.notifications:
            return self.notifications[notification_requested]
        else:
            raise YomboWarning('Notification not found: %s' %
                               notification_requested)

    def delete(self, notification_requested):
        """
        Deletes a provided notification.

        :param notification_requested:
        :return:
        """
        try:
            del self.notifications[notification_requested]
        except:
            pass
        self._LocalDB.delete_notification(notification_requested)

    @inlineCallbacks
    def load_notifications(self):
        """
        Load the last few notifications into memory.
        """
        notifications = yield self._LocalDB.get_notifications()
        for notice in notifications:
            notice = notice.__dict__
            if notice['expire'] < int(time()):
                continue
            notice['meta'] = json.loads(notice['meta'])
            self.add_notice(notice, from_db=True)
        logger.debug("Done load_notifications: {notifications}",
                     notifications=self.notifications)
        # self.init_deferred.callback(10)

    def add_notice(self,
                   notice,
                   from_db=False,
                   persist=True,
                   create_event=False):
        """
        Add a new notice.

        :param notice: A dictionary containing notification details.
        :type record: dict
        :returns: Pointer to new notice. Only used during unittest
        """
        print("adding notice1: %s" % notice)
        if 'id' not in notice:
            notice['id'] = random_string(length=16)
        if 'type' not in notice:
            notice['type'] = 'system'
        if 'priority' not in notice:
            notice['priority'] = 'normal'
        if 'source' not in notice:
            notice['source'] = ''

        if 'expire' not in notice:
            if 'timeout' in notice:
                notice['expire'] = int(time()) + notice['timeout']
            else:
                notice['expire'] = int(time()) + 3600
        else:
            if notice['expire'] > int(time()):
                YomboWarning(
                    "New notification is set to expire before current time.")
        if 'created_at' not in notice:
            notice['created_at'] = int(time())

        if 'acknowledged' not in notice:
            notice['acknowledged'] = False
        else:
            if notice['acknowledged'] not in (True, False):
                YomboWarning(
                    "New notification 'acknowledged' must be either True or False."
                )

        if 'title' not in notice:
            raise YomboWarning("New notification requires a title.")
        if 'message' not in notice:
            raise YomboWarning("New notification requires a message.")
        if 'meta' not in notice:
            notice['meta'] = {}

        logger.debug("notice: {notice}", notice=notice)
        if from_db is False:
            self._LocalDB.add_notification(notice)
            self.notifications.prepend(notice['id'], Notification(notice))
        else:
            self.notifications[notice['id']] = Notification(notice)
            # self.notifications = OrderedDict(sorted(self.notifications.items(), key=lambda x: x[1]['created_at']))
            pass
        return notice['id']