diff --git a/hookbox/channel.py b/hookbox/channel.py index 3207a1d..ef55f95 100644 --- a/hookbox/channel.py +++ b/hookbox/channel.py @@ -22,6 +22,8 @@ class Channel(object): 'moderated_subscribe': False, 'moderated_unsubscribe': False, 'presenceful': False, + 'server_presenceful': False, + 'server_user_presence': [], 'anonymous': False, 'polling': { 'mode': "", @@ -242,7 +244,18 @@ def state_set(self, key, val): return self.state[key] = val self.state_broadcast(updates={ key: val }) - + + def state_multi_set(self, state): + #Set multiple state values at once + updates = {} + for k,v in state.iteritems(): + if k in self.state and self.state[k]==v: + pass + else: + self.state[k] = v + updates[k] = v + self.state_broadcast(updates=updates) + def state_broadcast(self, updates={}, deletes=[]): frame = { "channel_name": self.name, diff --git a/hookbox/server.py b/hookbox/server.py index 655909b..f486c72 100644 --- a/hookbox/server.py +++ b/hookbox/server.py @@ -75,6 +75,7 @@ def __init__(self, bound_socket, bound_api_socket, config, outputter): self.conns_by_cookie = {} self.conns = {} self.users = {} + self.user_channel_presence = {} self.pool = EventletPool() def _ws_wrapper(self, environ, start_response): @@ -284,6 +285,9 @@ def get_user(self, name): if name not in self.users: self.users[name] = User(self, name) self.admin.user_event('create', name, self.users[name].serialize()) + if name in self.user_channel_presence: + for channel in self.user_channel_presence[name]: + channel.state_set(name, True) return self.users[name] def remove_user(self, name): @@ -298,8 +302,13 @@ def remove_user(self, name): pass except Exception, e: self.logger.warn("Unexpected error when removing user: %s", e, exc_info=True) + + if name in self.user_channel_presence: + for channel in self.user_channel_presence[name]: + channel.state_set(name, False) def create_channel(self, conn, channel_name, options={}, needs_auth=True): + local_options = options.copy() if channel_name in self.channels: raise ExpectedException("Channel already exists") if needs_auth: @@ -309,10 +318,23 @@ def create_channel(self, conn, channel_name, options={}, needs_auth=True): } success, callback_options = self.http_request('create_channel', cookie_string, form) if success: - options.update(callback_options) + local_options.update(callback_options) else: raise ExpectedException(callback_options.get('error', 'Unauthorized')) - chan = self.channels[channel_name] = channel.Channel(self, channel_name, **options) + + chan = self.channels[channel_name] = channel.Channel(self, channel_name, **local_options) + + #If channel needs to know about server presence, register channel with users + if chan.server_presenceful: + user_state = {} + for user in chan.server_user_presence: + user_state[user] = user in self.users + if user not in self.user_channel_presence: + self.user_channel_presence[user] = [chan] + else: + self.user_channel_presence[user].append(chan) + chan.state_multi_set(user_state) + self.admin.channel_event('create_channel', channel_name, chan.serialize()) def destroy_channel(self, channel_name, needs_auth=True): @@ -320,6 +342,10 @@ def destroy_channel(self, channel_name, needs_auth=True): return None channel = self.channels[channel_name] if channel.destroy(needs_auth): + if channel.server_presenceful: + for user in channel.server_user_presence: + self.user_channel_presence[user].remove(channel) + del self.channels[channel_name] self.admin.channel_event('destroy_channel', channel_name, None) @@ -333,12 +359,13 @@ def get_channel(self, conn, channel_name): def maybe_auto_subscribe(self, user, options, conn=None): #print 'maybe autosubscribe....' + use_conn = conn if conn else user for destination in options.get('auto_subscribe', ()): #print 'subscribing to', destination - channel = self.get_channel(user, destination) + channel = self.get_channel(use_conn, destination) channel.subscribe(user, conn=conn, needs_auth=False) for destination in options.get('auto_unsubscribe', ()): - channel = self.get_channel(user, destination) + channel = self.get_channel(use_conn, destination) channel.unsubscribe(user, conn=conn, needs_auth=False) diff --git a/hookbox/user.py b/hookbox/user.py index 254b796..1664ef5 100644 --- a/hookbox/user.py +++ b/hookbox/user.py @@ -13,6 +13,7 @@ class User(object): _options = { 'reflective': True, 'moderated_message': True, + 'auto_subscribe': [] } def __init__(self, server, name, **options):