添加掉线重连

pull/12/head
John Smith 5 years ago
parent ce4974be94
commit 938f758920

@ -7,7 +7,7 @@ import config from '@/api/config'
import ChatRenderer from '@/components/ChatRenderer'
import * as constants from '@/components/ChatRenderer/constants'
// const COMMAND_HEARTBEAT = 0
const COMMAND_HEARTBEAT = 0
const COMMAND_JOIN_ROOM = 1
const COMMAND_ADD_TEXT = 2
const COMMAND_ADD_GIFT = 3
@ -27,7 +27,12 @@ export default {
cfg.maxSpeed = 0
return {
config: cfg,
websocket: null,
retryCount: 0,
isDestroying: false,
heartbeatTimerId: null,
messagesBufferTimerId: null,
nextId: 0,
messagesBuffer: [], //
@ -35,28 +40,17 @@ export default {
paidMessages: []
}
},
async created() {
// 使localhost:12450
const url = process.env.NODE_ENV === 'development' ? 'ws://localhost:12450/chat' : `ws://${window.location.host}/chat`
this.websocket = new WebSocket(url)
this.websocket.onopen = this.onWsOpen
this.websocket.onmessage = this.onWsMessage
created() {
this.wsConnect()
if (this.$route.query.config_id) {
try {
let cfg = await config.getRemoteConfig(this.$route.query.config_id)
cfg.blockKeywords = cfg.blockKeywords.split('\n').filter(val => val)
cfg.blockUsers = cfg.blockUsers.split('\n').filter(val => val)
this.config = cfg
} catch (e) {
this.$message.error('获取配置失败:' + e)
}
this.updateConfig(this.$route.query.config_id)
}
},
beforeDestroy() {
if (this.messagesBufferTimerId) {
window.clearInterval(this.messagesBufferTimerId)
}
this.isDestroying = true
this.websocket.close()
},
watch: {
@ -66,12 +60,37 @@ export default {
this.messagesBufferTimerId = null
}
if (val.maxSpeed > 0) {
this.messagesBufferTimerId = window.setInterval(this.handleMessagesBuffer.bind(this), 1000 / val.maxSpeed)
this.messagesBufferTimerId = window.setInterval(this.handleMessagesBuffer, 1000 / val.maxSpeed)
}
}
},
methods: {
async updateConfig(configId) {
try {
let cfg = await config.getRemoteConfig(configId)
cfg.blockKeywords = cfg.blockKeywords.split('\n').filter(val => val)
cfg.blockUsers = cfg.blockUsers.split('\n').filter(val => val)
this.config = cfg
} catch (e) {
this.$message.error('获取配置失败:' + e)
}
},
wsConnect() {
// 使localhost:12450
const url = process.env.NODE_ENV === 'development' ? 'ws://localhost:12450/chat' : `ws://${window.location.host}/chat`
this.websocket = new WebSocket(url)
this.websocket.onopen = this.onWsOpen
this.websocket.onclose = this.onWsClose
this.websocket.onmessage = this.onWsMessage
this.heartbeatTimerId = window.setInterval(this.sendHeartbeat, 10 * 1000)
},
sendHeartbeat() {
this.websocket.send(JSON.stringify({
cmd: COMMAND_HEARTBEAT
}))
},
onWsOpen() {
this.retryCount = 0
this.websocket.send(JSON.stringify({
cmd: COMMAND_JOIN_ROOM,
data: {
@ -79,6 +98,17 @@ export default {
}
}))
},
onWsClose() {
if (this.heartbeatTimerId) {
window.clearInterval(this.heartbeatTimerId)
this.heartbeatTimerId = null
}
if (this.isDestroying) {
return
}
window.console.log(`掉线重连中${++this.retryCount}`)
this.wsConnect()
},
onWsMessage(event) {
let {cmd, data} = JSON.parse(event.data)
let message = null

@ -181,76 +181,49 @@ class RoomManager:
def __init__(self):
self._rooms: Dict[int, Room] = {}
def add_client(self, room_id, client: 'ChatHandler'):
if room_id in self._rooms:
room = self._rooms[room_id]
else:
logger.info('Creating room %d', room_id)
room = Room(room_id)
self._rooms[room_id] = room
room.start()
async def add_client(self, room_id, client: 'ChatHandler'):
if room_id not in self._rooms:
if not await self._add_room(room_id):
client.close()
return
room = self._rooms[room_id]
room.clients.append(client)
logger.info('%d clients in room %s', len(room.clients), room_id)
if client.application.settings['debug']:
self.__send_test_message(room)
client.send_test_message()
def del_client(self, room_id, client: 'ChatHandler'):
if room_id not in self._rooms:
return
room = self._rooms[room_id]
room.clients.remove(client)
logger.info('%d clients in room %s', len(room.clients), room_id)
if not room.clients:
logger.info('Removing room %d', room_id)
room.stop_and_close()
del self._rooms[room_id]
self._del_room(room_id)
# 测试用
@staticmethod
def __send_test_message(room):
base_data = {
'avatarUrl': 'https://i0.hdslb.com/bfs/face/29b6be8aa611e70a3d3ac219cdaf5e72b604f2de.jpg@48w_48h',
'timestamp': time.time(),
'authorName': 'xfgryujk',
}
text_data = {
**base_data,
'authorType': 0,
'content': '我能吞下玻璃而不伤身体',
'privilegeType': 0,
'isGiftDanmaku': False,
'authorLevel': 20,
'isNewbie': False,
'isMobileVerified': True
}
member_data = base_data
gift_data = {
**base_data,
'giftName': '摩天大楼',
'giftNum': 1,
'totalCoin': 450000
}
sc_data = {
**base_data,
'price': 30,
'content': 'The quick brown fox jumps over the lazy dog',
'id': 1
}
room.send_message(Command.ADD_TEXT, text_data)
text_data['authorName'] = '主播'
text_data['authorType'] = 3
text_data['content'] = "I can eat glass, it doesn't hurt me."
room.send_message(Command.ADD_TEXT, text_data)
room.send_message(Command.ADD_MEMBER, member_data)
room.send_message(Command.ADD_SUPER_CHAT, sc_data)
sc_data['price'] = 100
sc_data['content'] = '敏捷的棕色狐狸跳过了懒狗'
sc_data['id'] = 2
room.send_message(Command.ADD_SUPER_CHAT, sc_data)
# room.send_message(Command.DEL_SUPER_CHAT, {'ids': [1, 2]})
room.send_message(Command.ADD_GIFT, gift_data)
gift_data['giftName'] = '小电视飞船'
gift_data['totalCoin'] = 1245000
room.send_message(Command.ADD_GIFT, gift_data)
async def _add_room(self, room_id):
if room_id in self._rooms:
return True
logger.info('Creating room %d', room_id)
room = Room(room_id)
self._rooms[room_id] = room
if await room.init_room():
room.start()
return True
else:
self._del_room(room_id)
return False
def _del_room(self, room_id):
if room_id not in self._rooms:
return
logger.info('Removing room %d', room_id)
room = self._rooms[room_id]
for client in room.clients:
client.close()
room.stop_and_close()
del self._rooms[room_id]
room_manager = RoomManager()
@ -266,18 +239,21 @@ class ChatHandler(tornado.websocket.WebSocketHandler):
logger.info('Websocket connected %s', self.request.remote_ip)
def on_message(self, message):
if self.room_id is not None:
return
body = json.loads(message)
if body['cmd'] == Command.JOIN_ROOM:
cmd = body['cmd']
if cmd == Command.HEARTBEAT:
pass
elif cmd == Command.JOIN_ROOM:
if self.room_id is not None:
return
self.room_id = int(body['data']['roomId'])
logger.info('Client %s is joining room %d', self.request.remote_ip, self.room_id)
room_manager.add_client(self.room_id, self)
asyncio.ensure_future(room_manager.add_client(self.room_id, self))
else:
logger.warning('Unknown cmd: %s data: %s', body['cmd'], body['data'])
logger.warning('Unknown cmd: %s body: %s', cmd, body)
def on_close(self):
logger.info('Websocket disconnected %s room: %s', self.request.remote_ip, self.room_id)
logger.info('Websocket disconnected %s room: %s', self.request.remote_ip, str(self.room_id))
if self.room_id is not None:
room_manager.del_client(self.room_id, self)
@ -286,3 +262,54 @@ class ChatHandler(tornado.websocket.WebSocketHandler):
if self.application.settings['debug']:
return True
return super().check_origin(origin)
# 测试用
def send_test_message(self):
base_data = {
'avatarUrl': 'https://i0.hdslb.com/bfs/face/29b6be8aa611e70a3d3ac219cdaf5e72b604f2de.jpg@48w_48h',
'timestamp': time.time(),
'authorName': 'xfgryujk',
}
text_data = {
**base_data,
'authorType': 0,
'content': '我能吞下玻璃而不伤身体',
'privilegeType': 0,
'isGiftDanmaku': False,
'authorLevel': 20,
'isNewbie': False,
'isMobileVerified': True
}
member_data = base_data
gift_data = {
**base_data,
'giftName': '摩天大楼',
'giftNum': 1,
'totalCoin': 450000
}
sc_data = {
**base_data,
'price': 30,
'content': 'The quick brown fox jumps over the lazy dog',
'id': 1
}
self.send_message(Command.ADD_TEXT, text_data)
text_data['authorName'] = '主播'
text_data['authorType'] = 3
text_data['content'] = "I can eat glass, it doesn't hurt me."
self.send_message(Command.ADD_TEXT, text_data)
self.send_message(Command.ADD_MEMBER, member_data)
self.send_message(Command.ADD_SUPER_CHAT, sc_data)
sc_data['price'] = 100
sc_data['content'] = '敏捷的棕色狐狸跳过了懒狗'
sc_data['id'] = 2
self.send_message(Command.ADD_SUPER_CHAT, sc_data)
# self.send_message(Command.DEL_SUPER_CHAT, {'ids': [1, 2]})
self.send_message(Command.ADD_GIFT, gift_data)
gift_data['giftName'] = '小电视飞船'
gift_data['totalCoin'] = 1245000
self.send_message(Command.ADD_GIFT, gift_data)
def send_message(self, cmd, data):
body = json.dumps({'cmd': cmd, 'data': data})
self.write_message(body)

Loading…
Cancel
Save