def on_close(self): # Unsubscribe here and let the exit callback handle disconnecting. if hasattr(self, "redis_task"): self.redis_task.cancel() if hasattr(self, "redis_client"): self.redis_client.close() if hasattr(self, "close_code") and self.close_code in (1000, 1001): message_type = "disconnect" else: message_type = "timeout" if self.joined and self.user_list.socket_disconnect(self.id, self.user_number): try: send_quit_message(self.user_list, self.db, *self.get_chat_user(), type=message_type) except NoResultFound: send_userlist(self.user_list, self.db, self.chat) self.db.commit() # Delete the database connection here and on_finish just to be sure. if hasattr(self, "_db"): self._db.close() del self._db if DEBUG: print("socket closed: %s" % self.id) try: sockets.remove(self) except KeyError: pass
def reap(): redis = reap.redis with session_scope() as db: current_time = int(time.time()) disconnected_users = set() # Long poll sessions. for dead in redis.zrangebyscore("chats_alive", 0, current_time): logger.info("Reaping %s" % dead) chat_id, session_id = dead.split('/') user_id = redis.hget("chat:%s:online" % chat_id, session_id) disconnected = disconnect(redis, chat_id, session_id) # Only send a timeout message if they were already online. if not disconnected: logger.info("Not sending timeout message.") continue disconnected_users.add((chat_id, user_id, False)) # Sockets. for dead in redis.zrangebyscore("sockets_alive", 0, current_time): logger.info("Reaping %s" % dead) chat_id, session_id, socket_id = dead.split('/') user_id = redis.hget("chat:%s:online" % chat_id, socket_id) disconnected = disconnect(redis, chat_id, socket_id) redis.srem("chat:%s:sockets:%s" % (chat_id, session_id), socket_id) redis.zrem("sockets_alive", "%s/%s/%s" % (chat_id, session_id, socket_id)) # Only send a timeout message if they were already online. if not disconnected: logger.info("Not sending timeout message.") continue disconnected_users.add((chat_id, user_id, True)) for chat_id, user_id, reaped_socket in disconnected_users: try: dead_chat_user = db.query(ChatUser).filter(and_( ChatUser.user_id == user_id, ChatUser.chat_id == chat_id, )).options(joinedload(ChatUser.chat), joinedload(ChatUser.user)).one() except NoResultFound: logger.error("Unable to find ChatUser (chat %s, user %s)." % (chat_id, user_id)) continue if reaped_socket: typing_key = "chat:%s:typing" % chat_id if redis.srem(typing_key, dead_chat_user.number): redis.publish("channel:%s:typing" % chat_id, json.dumps({ "typing": list(int(_) for _ in redis.smembers(typing_key)), })) if dead_chat_user.computed_group == "silent" or dead_chat_user.chat.type in ("pm", "roulette"): send_userlist(db, redis, dead_chat_user.chat) else: send_message(db, redis, Message( chat_id=chat_id, user_id=dead_chat_user.user_id, type="timeout", name=dead_chat_user.name, text="%s's connection timed out." % dead_chat_user.name, )) logger.info("Sent timeout message for ChatUser (chat %s, user %s)." % (chat_id, user_id))
def reap_chat(chat_id): user_list = UserListStore(NewparpRedis(connection_pool=redis_chat_pool), chat_id) old_user_ids = user_list.user_ids_online() if not old_user_ids: return with session_scope() as db: chat = db.query(Chat).filter(Chat.id == chat_id).one() chat_users = { _.user_id: _ for _ in db.query(ChatUser).filter(and_( ChatUser.chat_id == chat_id, ChatUser.user_id.in_(old_user_ids), )) } for socket_id, user_id in user_list.inconsistent_entries(): chat_user = chat_users[user_id] dead = user_list.socket_disconnect(socket_id, chat_user.number) if dead: logger.debug("dead: %s" % chat_user) # TODO optimise this when reaping several people at once? if chat_user.computed_group == "silent" or chat.type in ("pm", "roulette"): send_userlist(user_list, db, chat) else: send_message(db, reap_chat.redis, Message( chat=chat, user_id=chat_user.user_id, type="timeout", name=chat_user.name, text="%s's connection timed out." % chat_user.name, ), user_list)
def save_from_character(): try: character = g.db.query(Character).filter( and_( Character.id == request.form["character_id"], Character.user_id == g.user.id, )).order_by(Character.title).one() except NoResultFound: abort(404) # Remember old values so we can check if they've changed later. old_name = g.chat_user.name old_acronym = g.chat_user.acronym # Send a message if name, acronym or color has changed. changed = (g.chat_user.name != character.name or g.chat_user.acronym != character.acronym or g.chat_user.color != character.color) g.chat_user.name = character.name g.chat_user.acronym = character.acronym g.chat_user.color = character.color g.chat_user.quirk_prefix = character.quirk_prefix g.chat_user.quirk_suffix = character.quirk_suffix g.chat_user.case = character.case g.chat_user.replacements = character.replacements g.chat_user.regexes = character.regexes if changed: if g.chat_user.computed_group == "silent": send_userlist(g.user_list, g.db, g.chat) else: send_message( g.db, g.redis, Message( chat_id=g.chat.id, user_id=g.user.id, type="user_info", name=g.chat_user.name, text="%s [%s] is now %s [%s]." % ( old_name, old_acronym, g.chat_user.name, g.chat_user.acronym, ), ), g.user_list) return jsonify(g.chat_user.to_dict(include_options=True))
def save_from_character(): try: character = g.db.query(Character).filter(and_( Character.id == request.form["character_id"], Character.user_id == g.user.id, )).order_by(Character.title).one() except NoResultFound: abort(404) # Remember old values so we can check if they've changed later. old_name = g.chat_user.name old_acronym = g.chat_user.acronym # Send a message if name, acronym or color has changed. changed = ( g.chat_user.name != character.name or g.chat_user.acronym != character.acronym or g.chat_user.color != character.color ) g.chat_user.name = character.name g.chat_user.acronym = character.acronym g.chat_user.color = character.color g.chat_user.quirk_prefix = character.quirk_prefix g.chat_user.quirk_suffix = character.quirk_suffix g.chat_user.case = character.case g.chat_user.replacements = character.replacements g.chat_user.regexes = character.regexes if changed: if g.chat_user.computed_group == "silent": send_userlist(g.user_list, g.db, g.chat) else: send_message(g.db, g.redis, Message( chat_id=g.chat.id, user_id=g.user.id, type="user_info", name=g.chat_user.name, text="%s [%s] is now %s [%s]." % ( old_name, old_acronym, g.chat_user.name, g.chat_user.acronym, ), ), g.user_list) return jsonify(g.chat_user.to_dict(include_options=True))
def save(): # Remember old values so we can check if they've changed later. old_name = g.chat_user.name old_acronym = g.chat_user.acronym old_color = g.chat_user.color new_details = validate_character_form(request.form) g.chat_user.search_character_id = new_details["search_character_id"] g.chat_user.name = new_details["name"] g.chat_user.acronym = new_details["acronym"] g.chat_user.color = new_details["color"] g.chat_user.quirk_prefix = new_details["quirk_prefix"] g.chat_user.quirk_suffix = new_details["quirk_suffix"] g.chat_user.case = new_details["case"] g.chat_user.replacements = new_details["replacements"] g.chat_user.regexes = new_details["regexes"] # Send a message if name or acronym has changed. if g.chat_user.name != old_name or g.chat_user.acronym != old_acronym: if g.chat_user.computed_group == "silent": send_userlist(g.user_list, g.db, g.chat) else: send_message( g.db, g.redis, Message( chat_id=g.chat.id, user_id=g.user.id, type="user_info", name=g.chat_user.name, text=("%s [%s] is now %s [%s].") % ( old_name, old_acronym, g.chat_user.name, g.chat_user.acronym, ), ), g.user_list) # Just refresh the user list if the color has changed. elif g.chat_user.color != old_color: send_userlist(g.user_list, g.db, g.chat) return jsonify(g.chat_user.to_dict(include_options=True))
def save(): # Remember old values so we can check if they've changed later. old_name = g.chat_user.name old_acronym = g.chat_user.acronym old_color = g.chat_user.color new_details = validate_character_form(request.form) g.chat_user.search_character_id = new_details["search_character_id"] g.chat_user.name = new_details["name"] g.chat_user.acronym = new_details["acronym"] g.chat_user.color = new_details["color"] g.chat_user.quirk_prefix = new_details["quirk_prefix"] g.chat_user.quirk_suffix = new_details["quirk_suffix"] g.chat_user.case = new_details["case"] g.chat_user.replacements = new_details["replacements"] g.chat_user.regexes = new_details["regexes"] # Send a message if name or acronym has changed. if g.chat_user.name != old_name or g.chat_user.acronym != old_acronym: if g.chat_user.computed_group == "silent": send_userlist(g.db, g.redis, g.chat) else: send_message(g.db, g.redis, Message( chat_id=g.chat.id, user_id=g.user.id, type="user_info", name=g.chat_user.name, text=("%s [%s] is now %s [%s].") % ( old_name, old_acronym, g.chat_user.name, g.chat_user.acronym, ), )) # Just refresh the user list if the color has changed. elif g.chat_user.color != old_color: send_userlist(g.db, g.redis, g.chat) return jsonify(g.chat_user.to_dict(include_options=True))
def reap_chat(chat_id): user_list = UserListStore(NewparpRedis(connection_pool=redis_chat_pool), chat_id) old_user_ids = user_list.user_ids_online() if not old_user_ids: return with session_scope() as db: chat = db.query(Chat).filter(Chat.id == chat_id).one() chat_users = { _.user_id: _ for _ in db.query(ChatUser).filter( and_( ChatUser.chat_id == chat_id, ChatUser.user_id.in_(old_user_ids), )) } for socket_id, user_id in user_list.inconsistent_entries(): chat_user = chat_users[user_id] dead = user_list.socket_disconnect(socket_id, chat_user.number) if dead: logger.debug("dead: %s" % chat_user) # TODO optimise this when reaping several people at once? if chat_user.computed_group == "silent" or chat.type in ( "pm", "roulette"): send_userlist(user_list, db, chat) else: send_message( db, reap_chat.redis, Message( chat=chat, user_id=chat_user.user_id, type="timeout", name=chat_user.name, text="%s's connection timed out." % chat_user.name, ), user_list)