def prepare(self): self.id = str(uuid4()) self.joined = False try: self.session_id = self.cookies["session"].value self.chat_id = int(self.path_args[0]) self.user_id = int(redis.get("session:%s" % self.session_id)) except (KeyError, TypeError, ValueError): self.send_error(400) return self.db = sm() try: self.chat_user, self.user, self.chat = self.get_chat_user() except NoResultFound: self.send_error(404) return # Remember the user number so typing notifications can refer to it # without reopening the database session. self.user_number = self.chat_user.number self.user.last_online = datetime.now() self.user.last_ip = self.request.headers["X-Forwarded-For"] if self.user.group == "banned": self.send_error(403) return try: authorize_joining(redis, self.db, self) except (UnauthorizedException, BannedException, TooManyPeopleException): self.send_error(403) return
#!/usr/bin/python import time from redis import StrictRedis from sqlalchemy import and_, func from sqlalchemy.orm import joinedload from sqlalchemy.orm.exc import NoResultFound from charat2.helpers.chat import disconnect, send_message, send_userlist from charat2.model import sm, Message, ChatUser from charat2.model.connections import redis_pool if __name__ == "__main__": db = sm() print "Obtaining lock..." db.query(func.pg_advisory_lock(413, 1)).scalar() print "Lock obtained." redis = StrictRedis(connection_pool=redis_pool) while True: current_time = int(time.time()) # Make sure a message is sent every 25 seconds so the long poll requests # don't time out. # XXX INCREASE THIS TO SEVERAL MINUTES for chat_id in redis.zrangebyscore("longpoll_timeout", 0, current_time):
def run_matchmaker( lock_id, searchers_key, searcher_prefix, get_searcher_info, check_compatibility, ChatClass, get_character_info, ): # XXX get log level from stdin root = logging.getLogger() root.setLevel(logging.DEBUG) db = sm() print "Obtaining lock..." db.query(func.pg_advisory_lock(413, lock_id)).scalar() print "Lock obtained." redis = StrictRedis(connection_pool=redis_pool) searcher_ids = redis.smembers(searchers_key) while True: # Reset the searcher list for the next iteration. redis.delete(searchers_key) for searcher in searcher_ids: logging.debug("Waking unmatched searcher %s." % searcher) redis.publish("%s:%s" % (searcher_prefix, searcher), "{ \"status\": \"unmatched\" }") time.sleep(10) logging.info("Starting match loop.") searcher_ids = redis.smembers(searchers_key) # We can't do anything with less than 2 people, so don't bother. if len(searcher_ids) < 2: logging.info("Not enough searchers, skipping.") continue searchers = get_searcher_info(redis, searcher_ids) logging.debug("Searcher list: %s" % searchers) shuffle(searchers) already_matched = set() # Range hack so we don't check opposite pairs or against itself. for n in range(len(searchers)): s1 = searchers[n] for m in range(n + 1, len(searchers)): s2 = searchers[m] if s1["id"] in already_matched or s2["id"] in already_matched: continue logging.debug("Comparing %s and %s." % (s1["id"], s2["id"])) match, options = check_compatibility(redis, s1, s2) if not match: logging.debug("No match.") continue blocked = ( db.query(func.count("*")).select_from(Block).filter(and_( Block.blocking_user_id == s1["user_id"], Block.blocked_user_id == s2["user_id"] )).scalar() != 0 or db.query(func.count("*")).select_from(Block).filter(and_( Block.blocking_user_id == s2["user_id"], Block.blocked_user_id == s1["user_id"] )).scalar() != 0 ) if blocked: logging.debug("Blocked.") continue new_url = str(uuid4()).replace("-", "") logging.info( "Matched %s and %s, sending to %s." % (s1["id"], s2["id"], new_url) ) new_chat = ChatClass(url=new_url) db.add(new_chat) db.flush() s1_user = db.query(User).filter(User.id == s1["user_id"]).one() s2_user = db.query(User).filter(User.id == s2["user_id"]).one() db.add(ChatUser.from_user(s1_user, chat_id=new_chat.id, number=1, **get_character_info(db, s1))) db.add(ChatUser.from_user(s2_user, chat_id=new_chat.id, number=2, **get_character_info(db, s2))) if options: db.add(Message( chat_id=new_chat.id, type="search_info", text=" ".join(option_messages[_] for _ in options), )) db.commit() already_matched.add(s1["id"]) already_matched.add(s2["id"]) match_message = json.dumps({ "status": "matched", "url": new_url }) redis.publish("%s:%s" % (searcher_prefix, s1["id"]), match_message) redis.publish("%s:%s" % (searcher_prefix, s2["id"]), match_message) searcher_ids.remove(s1["id"]) searcher_ids.remove(s2["id"])
def prepare(self): self.db = sm()
def db_connect(): if not hasattr(g, "db"): g.db = sm()