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)
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)
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)
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
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)
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)
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
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
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
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
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
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)
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()
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)
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)
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()