示例#1
0
    def register_user_consumer(self, userid, worker, broadcast_presence = True, supports_mailbox = False, pending = True):
        uhash, resource = utils.split_userid(userid)

        if uhash in self._consumers:
            if resource in self._consumers[uhash]:
                # resource conflict - stop previous queue worker
                self._consumers[uhash][resource].stop(True)
                # disconnect client
                self._callbacks[userid]['conflict']()
        else:
            self._consumers[uhash] = {}

        self._callbacks[userid] = { 'conflict' : worker.conflict, 'client_protocol' : worker.get_client_protocol }
        # TODO configurable queue width
        self._consumers[uhash][resource] = ResizableDispatchQueue(worker.incoming, 50)

        # mark user as online in the push notifications manager
        if self.push_manager:
            self.push_manager.mark_user_online(userid)

        # broadcast presence (if not hidden)
        if not self.user_hidden(userid):
            self.broadcast_presence(userid, c2s.UserPresence.EVENT_ONLINE, None, not broadcast_presence)

        # requeue pending messages
        self.pending_messages(userid, supports_mailbox)
示例#2
0
    def unregister_user_consumer(self, userid, broadcast_presence=True):
        uhash, resource = utils.split_userid(userid)

        try:
            # end user storage
            self.storage.stop(userid)
            # user logout
            self.usercache.touch_user(userid)
            try:
                # remove callbacks
                del self._callbacks[userid]
            except:
                pass
            # stop previous queue if any
            self._consumers[uhash][resource].stop(True)
            del self._consumers[uhash][resource]
            if len(self._consumers[uhash]) == 0:
                del self._consumers[uhash]
        except:
            import traceback
            traceback.print_exc()

        # remove presence subscriptions
        self.unsubscribe_user_presence(userid)
        # broadcast presence
        self.broadcast_presence(userid, c2s.UserPresence.EVENT_OFFLINE, None,
                                not broadcast_presence)
示例#3
0
    def unregister_user_consumer(self, userid, broadcast_presence = True):
        uhash, resource = utils.split_userid(userid)

        try:
            # end user storage
            self.storage.stop(userid)
            # user logout
            self.usercache.touch_user(userid)
            try:
                # remove callbacks
                del self._callbacks[userid]
            except:
                pass
            # stop previous queue if any
            self._consumers[uhash][resource].stop(True)
            del self._consumers[uhash][resource]
            if len(self._consumers[uhash]) == 0:
                del self._consumers[uhash]
        except:
            import traceback
            traceback.print_exc()

        # remove presence subscriptions
        self.unsubscribe_user_presence(userid)
        # broadcast presence
        self.broadcast_presence(userid, c2s.UserPresence.EVENT_OFFLINE, None, not broadcast_presence)
示例#4
0
    def user_online(self, uid):
        '''Returns true if the specified user currently is a registered consumer.'''
        uhash, resource = utils.split_userid(uid)
        generic_online = (uhash in self._consumers and len(self._consumers[uhash]) > 0)

        if resource:
            return generic_online and resource in self._consumers[uhash]
        else:
            return generic_online
示例#5
0
    def user_online(self, uid):
        '''Returns true if the specified user currently is a registered consumer.'''
        uhash, resource = utils.split_userid(uid)
        generic_online = (uhash in self._consumers
                          and len(self._consumers[uhash]) > 0)

        if resource:
            return generic_online and resource in self._consumers[uhash]
        else:
            return generic_online
示例#6
0
 def pending_messages(self, userid, supports_mailbox = False):
     uhash, resource = utils.split_userid(userid)
     """
     WARNING these two need to be called in this order!!!
     Otherwise bad things happen...
     """
     # load previously stored messages (for specific) and requeue them
     self._reload_usermsg_queue(userid, supports_mailbox)
     # load previously stored messages (for generic) and requeue them
     self._reload_usermsg_queue(uhash, supports_mailbox)
示例#7
0
 def pending_messages(self, userid, supports_mailbox=False):
     uhash, resource = utils.split_userid(userid)
     """
     WARNING these two need to be called in this order!!!
     Otherwise bad things happen...
     """
     # load previously stored messages (for specific) and requeue them
     self._reload_usermsg_queue(userid, supports_mailbox)
     # load previously stored messages (for generic) and requeue them
     self._reload_usermsg_queue(uhash, supports_mailbox)
示例#8
0
    def get_presence_subscribers(self, userid):
        '''Returns a tuple containing presence subscribers respectively for the generic user and the specific user.'''
        uhash, resource = utils.split_userid(userid)
        try:
            generic = self._presence[uhash]['']
        except:
            generic = None
        try:
            specific = self._presence[uhash][resource]
        except:
            specific = None

        return generic, specific
示例#9
0
    def get_presence_subscribers(self, userid):
        '''Returns a tuple containing presence subscribers respectively for the generic user and the specific user.'''
        uhash, resource = utils.split_userid(userid)
        try:
            generic = self._presence[uhash]['']
        except:
            generic = None
        try:
            specific = self._presence[uhash][resource]
        except:
            specific = None

        return generic, specific
示例#10
0
        def _stat_found(found, deferred=True):
            end = time.time()
            #log.debug("lookup of %d users took %.2f seconds (found %d users)" % (len(users), end-start, len(found)))

            ret = {}
            for stat in found:
                userid, resource = utils.split_userid(stat['userid'])

                #log.debug("LOOKUP/%s" % (stat,))
                # check if user is online here
                if self.broker.user_online(stat['userid']):
                    if userid not in ret:
                        ret[userid] = {'userid': userid}
                    ret[userid]['timediff'] = 0
                    if 'status' in stat and stat['status']:
                        ret[userid]['status'] = stat['status']
                    # user is online: remove timestamp
                    try:
                        del ret[userid]['timestamp']
                    except:
                        pass
                else:
                    # consider updating timestamp if user is not online here
                    if 'timestamp' in stat and stat['timestamp'] and (
                            userid not in ret or 'timestamp' in ret[userid]):
                        if userid not in ret:
                            ret[userid] = {'userid': userid}

                        ts = long(stat['timestamp'])
                        # update timestamp only if newer
                        #log.debug("TSDIFF %s old=%d new=%d" % (userid, ret[userid]['timestamp'] if 'timestamp' in ret[userid] else -1, ts))
                        if 'timestamp' not in ret[
                                userid] or ret[userid]['timestamp'] < ts:
                            ret[userid]['timestamp'] = ts
                            ret[userid]['timediff'] = long(time.time() - ts)

                        if 'status' in stat and stat['status']:
                            ret[userid]['status'] = stat['status']

            #log.debug("RESULT/%s" % (ret,))
            ret = ret.values()
            if deferred:
                d.callback(ret)
            else:
                return ret
示例#11
0
        def _stat_found(found, deferred = True):
            end = time.time()
            #log.debug("lookup of %d users took %.2f seconds (found %d users)" % (len(users), end-start, len(found)))

            ret = {}
            for stat in found:
                userid, resource = utils.split_userid(stat['userid'])

                #log.debug("LOOKUP/%s" % (stat,))
                # check if user is online here
                if self.broker.user_online(stat['userid']):
                    if userid not in ret:
                        ret[userid] = {'userid' : userid}
                    ret[userid]['timediff'] = 0
                    if 'status' in stat and stat['status']:
                        ret[userid]['status'] = stat['status']
                    # user is online: remove timestamp
                    try:
                        del ret[userid]['timestamp']
                    except:
                        pass
                else:
                    # consider updating timestamp if user is not online here
                    if 'timestamp' in stat and stat['timestamp'] and (userid not in ret or 'timestamp' in ret[userid]):
                        if userid not in ret:
                            ret[userid] = {'userid' : userid}

                        ts = long(stat['timestamp'])
                        # update timestamp only if newer
                        #log.debug("TSDIFF %s old=%d new=%d" % (userid, ret[userid]['timestamp'] if 'timestamp' in ret[userid] else -1, ts))
                        if 'timestamp' not in ret[userid] or ret[userid]['timestamp'] < ts:
                            ret[userid]['timestamp'] = ts
                            ret[userid]['timediff'] = long(time.time()-ts)

                        if 'status' in stat and stat['status']:
                            ret[userid]['status'] = stat['status']

            #log.debug("RESULT/%s" % (ret,))
            ret = ret.values()
            if deferred:
                d.callback(ret)
            else:
                return ret
示例#12
0
    def subscribe_user_presence(self, userid, uid, events, internal=False):
        #if not internal:
        #log.debug("subscribing %s to presence notifications by %s for events %d" % (userid, uid, events))
        # invalid username
        if len(uid) != utils.USERID_LENGTH and len(
                uid) != utils.USERID_LENGTH_RESOURCE:
            return c2s.UserPresenceSubscribeResponse.STATUS_INVALID_USERNAME
        # invalid event mask
        if events > c2s.USER_EVENT_MASK_ALL:
            return c2s.UserPresenceSubscribeResponse.STATUS_ERROR

        uhash, resource = utils.split_userid(uid)
        if uhash not in self._presence:
            self._presence[uhash] = {}
        if resource not in self._presence[uhash]:
            self._presence[uhash][resource] = {}
        if userid not in self._presence_lists:
            self._presence_lists[userid] = []

        if events == 0:
            try:
                # remove from subscriptions map
                del self._presence[uhash][resource][userid]
            except:
                pass
            if not internal:
                try:
                    # remove from subscriptions lists
                    self._presence_lists[userid].remove(uid)
                except:
                    pass
        else:
            # add to subscriptions map
            self._presence[uhash][resource][userid] = events
            if not internal:
                # add to subscriptions lists
                if uid not in self._presence_lists:
                    self._presence_lists[userid].append(uid)

        return c2s.UserPresenceSubscribeResponse.STATUS_SUCCESS
示例#13
0
    def subscribe_user_presence(self, userid, uid, events, internal = False):
        #if not internal:
            #log.debug("subscribing %s to presence notifications by %s for events %d" % (userid, uid, events))
        # invalid username
        if len(uid) != utils.USERID_LENGTH and len(uid) != utils.USERID_LENGTH_RESOURCE:
            return c2s.UserPresenceSubscribeResponse.STATUS_INVALID_USERNAME
        # invalid event mask
        if events > c2s.USER_EVENT_MASK_ALL:
            return c2s.UserPresenceSubscribeResponse.STATUS_ERROR

        uhash, resource = utils.split_userid(uid)
        if uhash not in self._presence:
            self._presence[uhash] = {}
        if resource not in self._presence[uhash]:
            self._presence[uhash][resource] = {}
        if userid not in self._presence_lists:
            self._presence_lists[userid] = []

        if events == 0:
            try:
                # remove from subscriptions map
                del self._presence[uhash][resource][userid]
            except:
                pass
            if not internal:
                try:
                    # remove from subscriptions lists
                    self._presence_lists[userid].remove(uid)
                except:
                    pass
        else:
            # add to subscriptions map
            self._presence[uhash][resource][userid] = events
            if not internal:
                # add to subscriptions lists
                if uid not in self._presence_lists:
                    self._presence_lists[userid].append(uid)

        return c2s.UserPresenceSubscribeResponse.STATUS_SUCCESS
示例#14
0
    def register_user_consumer(self,
                               userid,
                               worker,
                               broadcast_presence=True,
                               supports_mailbox=False,
                               pending=True):
        uhash, resource = utils.split_userid(userid)

        if uhash in self._consumers:
            if resource in self._consumers[uhash]:
                # resource conflict - stop previous queue worker
                self._consumers[uhash][resource].stop(True)
                # disconnect client
                self._callbacks[userid]['conflict']()
        else:
            self._consumers[uhash] = {}

        self._callbacks[userid] = {
            'conflict': worker.conflict,
            'client_protocol': worker.get_client_protocol
        }
        # TODO configurable queue width
        self._consumers[uhash][resource] = ResizableDispatchQueue(
            worker.incoming, 50)

        # mark user as online in the push notifications manager
        if self.push_manager:
            self.push_manager.mark_user_online(userid)

        # broadcast presence (if not hidden)
        if not self.user_hidden(userid):
            self.broadcast_presence(userid, c2s.UserPresence.EVENT_ONLINE,
                                    None, not broadcast_presence)

        # requeue pending messages
        self.pending_messages(userid, supports_mailbox)
示例#15
0
    def _usermbox_worker(self, mbox):
        '''
        Processes a bunch of messages to be sent massively to recipients.
        This takes every message and put it in different lists to be delivered
        to their respective channels - if available.
        TODO this method is used only to requeue messages on login, so we can
        take something for granted, e.g. userid will be the same for every
        message, push notifications are not needed, ...
        '''
        outbox = {}

        for msg in mbox:
            userid = msg['recipient']
            need_ack = msg['need_ack']
            #log.debug("queue data for user %s (need_ack=%s)" % (userid, need_ack))

            # generic user, post to every consumer
            if len(userid) == utils.USERID_LENGTH:
                try:
                    for resource, q in self._consumers[userid].iteritems():
                        outmsg = dict(msg)
                        # branch the message :)
                        outmsg['messageid'] = self.message_id()
                        outmsg['originalid'] = msg['messageid']
                        outmsg['recipient'] += resource

                        # store to disk (if need_ack)
                        if need_ack:
                            try:
                                #log.debug("storing message %s to disk" % outmsg['messageid'])
                                self.storage.deliver(outmsg['recipient'],
                                                     outmsg)
                            except:
                                # TODO handle errors
                                import traceback
                                traceback.print_exc()

                        # keep in outbox
                        if outmsg['recipient'] not in outbox:
                            outbox[outmsg['recipient']] = []
                        outbox[outmsg['recipient']].append(outmsg)

                except KeyError:
                    #log.debug("warning: no consumer to deliver message to %s" % userid)
                    # store to temporary spool
                    self.storage.store(userid, msg)
                    # send push notifications to all matching users
                    try:
                        # do not push for receipts
                        if self.push_manager and msg['headers'][
                                'mime'] != MIME_RECEIPT:
                            self.push_manager.notify_all(userid)
                    except:
                        # TODO notify errors
                        import traceback
                        traceback.print_exc()

            elif len(userid) == utils.USERID_LENGTH_RESOURCE:
                uhash, resource = utils.split_userid(userid)

                # store to disk (if need_ack)
                if need_ack:
                    try:
                        #log.debug("storing message %s to disk" % msg['messageid'])
                        if 'storage' not in msg:
                            self.storage.store(userid, msg)
                    except:
                        # TODO handle errors
                        import traceback
                        traceback.print_exc()

                # keep in outbox
                if userid not in outbox:
                    outbox[userid] = []
                outbox[userid].append(msg)

            else:
                log.warn("warning: unknown userid format %s" % userid)

        for userid, msglist in outbox.iteritems():
            uhash, resource = utils.split_userid(userid)

            try:
                # send to client consumer
                #log.debug("sending message %s to consumer" % msg['messageid'])
                self._consumers[uhash][resource].put(msglist)
            except:
                #log.debug("warning: no consumer to deliver message to %s/%s!" % (uhash, resource))
                # send push notification
                try:
                    # do not push for receipts
                    receipt_found = False
                    for msg in msglist:
                        if msg['headers']['mime'] == MIME_RECEIPT:
                            receipt_found = True
                            break
                    if self.push_manager and not receipt_found:
                        self.push_manager.notify(userid)
                except:
                    # TODO notify errors
                    import traceback
                    traceback.print_exc()
示例#16
0
    def _usermsg_worker(self, msg):
        userid = msg['recipient']
        need_ack = msg['need_ack']
        #log.debug("queue data for user %s (need_ack=%s)" % (userid, need_ack))

        # generic user, post to every consumer
        if len(userid) == utils.USERID_LENGTH:
            try:
                for resource, q in self._consumers[userid].iteritems():
                    outmsg = dict(msg)
                    # branch the message :)
                    outmsg['messageid'] = self.message_id()
                    outmsg['originalid'] = msg['messageid']
                    outmsg['recipient'] += resource

                    # store to disk (if need_ack)
                    if need_ack:
                        try:
                            #log.debug("storing message %s to disk" % outmsg['messageid'])
                            self.storage.deliver(outmsg['recipient'], outmsg)
                        except:
                            # TODO handle errors
                            import traceback
                            traceback.print_exc()

                    # send to client listener
                    q.put(outmsg)

            except KeyError:
                #log.debug("warning: no consumer to deliver message to %s" % userid)
                # store to temporary spool
                self.storage.store(userid, msg)
                # send push notifications to all matching users
                try:
                    # do not push for receipts
                    if self.push_manager and msg['headers'][
                            'mime'] != MIME_RECEIPT:
                        self.push_manager.notify_all(userid)
                except:
                    # TODO notify errors
                    import traceback
                    traceback.print_exc()

        elif len(userid) == utils.USERID_LENGTH_RESOURCE:
            uhash, resource = utils.split_userid(userid)

            # store to disk (if need_ack)
            if need_ack:
                try:
                    #log.debug("storing message %s to disk" % msg['messageid'])
                    if 'storage' not in msg:
                        self.storage.store(userid, msg)
                except:
                    # TODO handle errors
                    import traceback
                    traceback.print_exc()

            try:
                # send to client consumer
                #log.debug("sending message %s to consumer" % msg['messageid'])
                self._consumers[uhash][resource].put(msg)
            except:
                #log.debug("warning: no consumer to deliver message to %s/%s!" % (uhash, resource))
                # send push notification
                try:
                    # do not push for receipts
                    if self.push_manager and msg['headers'][
                            'mime'] != MIME_RECEIPT:
                        self.push_manager.notify(userid)
                except:
                    # TODO notify errors
                    import traceback
                    traceback.print_exc()

        else:
            log.warn("warning: unknown userid format %s" % userid)
示例#17
0
    def _usermsg_worker(self, msg):
        userid = msg['recipient']
        need_ack = msg['need_ack']
        #log.debug("queue data for user %s (need_ack=%s)" % (userid, need_ack))

        # generic user, post to every consumer
        if len(userid) == utils.USERID_LENGTH:
            try:
                for resource, q in self._consumers[userid].iteritems():
                    outmsg = dict(msg)
                    # branch the message :)
                    outmsg['messageid'] = self.message_id()
                    outmsg['originalid'] = msg['messageid']
                    outmsg['recipient'] += resource

                    # store to disk (if need_ack)
                    if need_ack:
                        try:
                            #log.debug("storing message %s to disk" % outmsg['messageid'])
                            self.storage.deliver(outmsg['recipient'], outmsg)
                        except:
                            # TODO handle errors
                            import traceback
                            traceback.print_exc()

                    # send to client listener
                    q.put(outmsg)

            except KeyError:
                #log.debug("warning: no consumer to deliver message to %s" % userid)
                # store to temporary spool
                self.storage.store(userid, msg)
                # send push notifications to all matching users
                try:
                    # do not push for receipts
                    if self.push_manager and msg['headers']['mime'] != MIME_RECEIPT:
                        self.push_manager.notify_all(userid)
                except:
                    # TODO notify errors
                    import traceback
                    traceback.print_exc()


        elif len(userid) == utils.USERID_LENGTH_RESOURCE:
            uhash, resource = utils.split_userid(userid)

            # store to disk (if need_ack)
            if need_ack:
                try:
                    #log.debug("storing message %s to disk" % msg['messageid'])
                    if 'storage' not in msg:
                        self.storage.store(userid, msg)
                except:
                    # TODO handle errors
                    import traceback
                    traceback.print_exc()

            try:
                # send to client consumer
                #log.debug("sending message %s to consumer" % msg['messageid'])
                self._consumers[uhash][resource].put(msg)
            except:
                #log.debug("warning: no consumer to deliver message to %s/%s!" % (uhash, resource))
                # send push notification
                try:
                    # do not push for receipts
                    if self.push_manager and msg['headers']['mime'] != MIME_RECEIPT:
                        self.push_manager.notify(userid)
                except:
                    # TODO notify errors
                    import traceback
                    traceback.print_exc()

        else:
            log.warn("warning: unknown userid format %s" % userid)
示例#18
0
    def _usermbox_worker(self, mbox):
        '''
        Processes a bunch of messages to be sent massively to recipients.
        This takes every message and put it in different lists to be delivered
        to their respective channels - if available.
        TODO this method is used only to requeue messages on login, so we can
        take something for granted, e.g. userid will be the same for every
        message, push notifications are not needed, ...
        '''
        outbox = {}

        for msg in mbox:
            userid = msg['recipient']
            need_ack = msg['need_ack']
            #log.debug("queue data for user %s (need_ack=%s)" % (userid, need_ack))

            # generic user, post to every consumer
            if len(userid) == utils.USERID_LENGTH:
                try:
                    for resource, q in self._consumers[userid].iteritems():
                        outmsg = dict(msg)
                        # branch the message :)
                        outmsg['messageid'] = self.message_id()
                        outmsg['originalid'] = msg['messageid']
                        outmsg['recipient'] += resource

                        # store to disk (if need_ack)
                        if need_ack:
                            try:
                                #log.debug("storing message %s to disk" % outmsg['messageid'])
                                self.storage.deliver(outmsg['recipient'], outmsg)
                            except:
                                # TODO handle errors
                                import traceback
                                traceback.print_exc()

                        # keep in outbox
                        if outmsg['recipient'] not in outbox:
                            outbox[outmsg['recipient']] = []
                        outbox[outmsg['recipient']].append(outmsg)

                except KeyError:
                    #log.debug("warning: no consumer to deliver message to %s" % userid)
                    # store to temporary spool
                    self.storage.store(userid, msg)
                    # send push notifications to all matching users
                    try:
                        # do not push for receipts
                        if self.push_manager and msg['headers']['mime'] != MIME_RECEIPT:
                            self.push_manager.notify_all(userid)
                    except:
                        # TODO notify errors
                        import traceback
                        traceback.print_exc()

            elif len(userid) == utils.USERID_LENGTH_RESOURCE:
                uhash, resource = utils.split_userid(userid)

                # store to disk (if need_ack)
                if need_ack:
                    try:
                        #log.debug("storing message %s to disk" % msg['messageid'])
                        if 'storage' not in msg:
                            self.storage.store(userid, msg)
                    except:
                        # TODO handle errors
                        import traceback
                        traceback.print_exc()

                # keep in outbox
                if userid not in outbox:
                    outbox[userid] = []
                outbox[userid].append(msg)

            else:
                log.warn("warning: unknown userid format %s" % userid)

        for userid, msglist in outbox.iteritems():
            uhash, resource = utils.split_userid(userid)

            try:
                # send to client consumer
                #log.debug("sending message %s to consumer" % msg['messageid'])
                self._consumers[uhash][resource].put(msglist)
            except:
                #log.debug("warning: no consumer to deliver message to %s/%s!" % (uhash, resource))
                # send push notification
                try:
                    # do not push for receipts
                    receipt_found = False
                    for msg in msglist:
                        if msg['headers']['mime'] == MIME_RECEIPT:
                            receipt_found = True
                            break
                    if self.push_manager and not receipt_found:
                        self.push_manager.notify(userid)
                except:
                    # TODO notify errors
                    import traceback
                    traceback.print_exc()