def run(self): # f**k loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop = get_event_loop() loop.run_until_complete(self.asnyc_run()) log('thread end')
def save_to_cache(self): user_key = 'user.' + str(self.user_id) user_cache = cache.get(user_key) user_cache['player_state'] = self.state log(self.name + 'saved to cache, state = ' + str(self.state)) user_cache['room_id'] = self.room_id if 'channel_name' in user_cache: del user_cache['channel_name'] cache.set(user_key, user_cache, timeout=USER_TTL)
def load_from_cache(self): user_key = 'user.' + str(self.user_id) user_cache = cache.get(user_key) user_cache['channel_name'] = self.channel_name cache.set(user_key, user_cache, timeout=USER_TTL) self.name = user_cache.get('name') self.state = user_cache.get('player_state', PlayerState.Out) self.room_id = user_cache.get('room_id') log(self.name + 'loaded from cache, state = ' + str(self.state))
async def asnyc_run(self): self.layer = channels.layers.get_channel_layer() log('Room', self.id, 'created') # clean old messages until get a 'hello' while True: msg = await self.layer.receive('room.' + self.id) if msg['type'] == 'hello': break while True: self.killer = Timer(ROOM_TTL, self.kill) self.killer.start() msg = await self.layer.receive('room.' + self.id) self.killer.cancel() if await self.process_msg(msg): break log('Room', self.id, 'disbanded')
def enter_room(self, room_id): room_key = 'room.' + room_id self.state = PlayerState.Waiting # 先收听频道,以获得频道解散消息 log(self.name, 'add group:', room_key) async_to_sync(self.channel_layer.group_add)(room_key, self.channel_name) self.room_id = room_id if not cache.get(room_key): self.leave_room() # 房间不存在或已经解散 raise GameException('room not exist') self.send_msg_to_room({ 'type': 'enter', 'name': self.name, 'channel': self.channel_name, })
def receive_json(self, context): if len(context) == 0: self.send_json({}) return try: log('recieve json from', self.name, ':') log(context) msg = context['msg'] if msg in GameConsumer.msg_listener: GameConsumer.msg_listener[msg](self, context) else: self.send_error('type error: ' + msg) except KeyError as e: self.send_error('key error: ' + e.args[0]) except GameException as e: self.send_error(str(e)) except Exception: self.send_error('unkown server error') traceback.log_exc()
async def process_msg(self, msg): log('Room', self.id, 'get message:') log(msg) try: return await getattr(self, 'on_' + msg['type'], self.on_error_msg)(msg) except GameException as e: player = self.find_player_by_id(msg['id']) if player and player.channel_name: channel_name = player.channel_name elif 'channel' in msg: channel_name = msg['channel'] else: raise GameException( 'got error message from people not in the room, error =' + e.msg) await self.post_msg_to(channel_name, { 'msg': 'error', 'error': str(e), })
def connect(self): session = self.scope['session'] user_id = get_online_user_id(session) if user_id: self.accept() self.user_id = user_id self.load_from_cache() log('connect: user', self.name) self.send_json({ 'msg': 'connect', 'id': self.user_id, }) # 尝试连接房间(房间将下线同id的连接) if self.state != PlayerState.Out: log('try reconnect to room') self.try_reconnect_to_room() else: self.user_id = None self.accept() self.close(code=4233)
async def on_reconnect(self, msg): uid = msg['id'] channel_name = msg['channel'] log('on reconnect, uid =', uid, 'channel =', channel_name) player = self.find_player_by_id(uid) if player == None: log('player == None') raise GameException('not in room') else: if player.channel_name: await self.post_msg_to(player.channel_name, { 'msg': 'downlined', }) player.channel_name = channel_name await self.post_msg({ 'msg': 'reconnect', 'id': uid, 'state': player.state.value, 'room_type': self.type, }) await self.post_msg_to(player.channel_name, self.get_situation_msg(player))
def room_msg(self, event): log(self.name, 'get msg from room:') log(event) if event['msg'] == 'error' and event['error'] == 'not in room': self.leave_room() return # 设置状态改变 if 'id' in event and event['id'] == self.user_id: state = { 'enter': PlayerState.UnReady, 'watch': PlayerState.Watching, 'finish': PlayerState.Finished, }.get(event['msg'], None) if state == None and event['msg'] == 'reconnect': state = PlayerState(event.get('state')) if event['msg'] == 'change_state': state = PlayerState(event['state']) if state != None: self.state = state log('set state', state) if event['msg'] == 'start': self.state = PlayerState.Playing # 被下线 if event['msg'] == 'downlined': self.close(code=4111) return # 如果房间解散,被禁止加入房间或者主动离场,则离开 if event['msg'] == 'disband' \ or (event['msg'] == 'leave' and event['id'] == self.user_id) \ or (self.state == PlayerState.Waiting and event['msg'] == 'error'): self.leave_room() elif self.state == PlayerState.Waiting: # 尚未进入房间,其他消息与你无关 return # 向客户端发送消息 context = event.copy() context.pop('type') # 这是Room与Customer传递消息用的,与客户端无关 self.send_json(context)
async def on_error_msg(self, msg): log('Room', self.id, 'error message:', msg) raise GameException('unknown backend message type: ' + str(msg['type']))
async def post_msg_to(self, channel_name, context): context['type'] = 'room.msg' log('Room', self.id, 'post message to channel', channel_name, ':') log(context) await self.layer.send(channel_name, context)
async def post_msg(self, context): context['type'] = 'room.msg' log('Room', self.id, 'post message:') log(context) await self.layer.group_send('room.' + self.id, context)
def send_error(self, msg): log('send error to', self.name, ':', msg) self.send_json({'msg': 'error', 'error': msg})