[Bug Fix][Enhance] About Link Play

- Fix a bug that the room host will be changed late when finishing a song
- Add logging module for linkplay server
This commit is contained in:
Lost-MSth
2022-09-19 23:13:51 +08:00
parent 6298b37ea2
commit 299c8c582c
9 changed files with 52 additions and 41 deletions

View File

@@ -37,13 +37,13 @@ class Constant:
DOWNLOAD_TIME_GAP_LIMIT = Config.DOWNLOAD_TIME_GAP_LIMIT DOWNLOAD_TIME_GAP_LIMIT = Config.DOWNLOAD_TIME_GAP_LIMIT
DOWNLOAD_LINK_PREFIX = Config.DOWNLOAD_LINK_PREFIX DOWNLOAD_LINK_PREFIX = Config.DOWNLOAD_LINK_PREFIX
LINK_PLAY_UNLOCK_LENGTH = 512 # Units: bytes LINKPLAY_UNLOCK_LENGTH = 512 # Units: bytes
LINK_PLAY_TIMEOUT = 5 # Units: seconds LINKPLAY_TIMEOUT = 5 # Units: seconds
LINK_PLAY_HOST = '127.0.0.1' if Config.SET_LINK_PLAY_SERVER_AS_SUB_PROCESS else Config.LINK_PLAY_HOST LINKPLAY_HOST = '127.0.0.1' if Config.SET_LINKPLAY_SERVER_AS_SUB_PROCESS else Config.LINKPLAY_HOST
LINK_PLAY_TCP_PORT = Config.LINK_PLAY_TCP_PORT LINKPLAY_TCP_PORT = Config.LINKPLAY_TCP_PORT
LINK_PLAY_UDP_PORT = Config.LINK_PLAY_UDP_PORT LINKPLAY_UDP_PORT = Config.LINKPLAY_UDP_PORT
LINK_PLAY_AUTHENTICATION = Config.LINK_PLAY_AUTHENTICATION LINKPLAY_AUTHENTICATION = Config.LINKPLAY_AUTHENTICATION
COURSE_STAMINA_COST = 4 COURSE_STAMINA_COST = 4

View File

@@ -6,14 +6,14 @@ from core.error import ArcError, Timeout
from .constant import Constant from .constant import Constant
from .user import UserInfo from .user import UserInfo
socket.setdefaulttimeout(Constant.LINK_PLAY_TIMEOUT) socket.setdefaulttimeout(Constant.LINKPLAY_TIMEOUT)
def get_song_unlock(client_song_map: dict) -> bytes: def get_song_unlock(client_song_map: dict) -> bytes:
'''处理可用歌曲bit返回bytes''' '''处理可用歌曲bit返回bytes'''
user_song_unlock = [0] * Constant.LINK_PLAY_UNLOCK_LENGTH user_song_unlock = [0] * Constant.LINKPLAY_UNLOCK_LENGTH
for i in range(0, Constant.LINK_PLAY_UNLOCK_LENGTH*2, 2): for i in range(0, Constant.LINKPLAY_UNLOCK_LENGTH*2, 2):
x = 0 x = 0
y = 0 y = 0
if str(i) in client_song_map: if str(i) in client_song_map:
@@ -98,8 +98,8 @@ class RemoteMultiPlayer:
@staticmethod @staticmethod
def tcp(data: str) -> str: def tcp(data: str) -> str:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((Constant.LINK_PLAY_HOST, sock.connect((Constant.LINKPLAY_HOST,
Constant.LINK_PLAY_TCP_PORT)) Constant.LINKPLAY_TCP_PORT))
sock.sendall(bytes(data + "\n", "utf-8")) sock.sendall(bytes(data + "\n", "utf-8"))
try: try:
received = str(sock.recv(1024), "utf-8").strip() received = str(sock.recv(1024), "utf-8").strip()
@@ -111,7 +111,7 @@ class RemoteMultiPlayer:
def data_swap(self, data: tuple) -> tuple: def data_swap(self, data: tuple) -> tuple:
received = self.tcp(Constant.LINK_PLAY_AUTHENTICATION + received = self.tcp(Constant.LINKPLAY_AUTHENTICATION +
'|' + '|'.join([str(x) for x in data])) '|' + '|'.join([str(x) for x in data]))
self.data_recv = received.split('|') self.data_recv = received.split('|')

View File

@@ -1,6 +1,3 @@
from telnetlib import AUTHENTICATION
class Config: class Config:
''' '''
Link Play server configuration Link Play server configuration

View File

@@ -1,4 +1,5 @@
import base64 import base64
import logging
import random import random
import socketserver import socketserver
import threading import threading
@@ -19,6 +20,9 @@ player_dict = {} # 'player_id' : Player
clean_timer = 0 clean_timer = 0
lock = threading.RLock() lock = threading.RLock()
logging.basicConfig(format='[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
level=logging.INFO)
def random_room_code(): def random_room_code():
# 随机生成房间号 # 随机生成房间号
@@ -102,7 +106,7 @@ class UDP_handler(socketserver.BaseRequestHandler):
plaintext = decrypt(user['key'], b'', iv, ciphertext, tag) plaintext = decrypt(user['key'], b'', iv, ciphertext, tag)
except Exception as e: except Exception as e:
print(e) logging.error(e)
return None return None
# print(binascii.b2a_hex(plaintext)) # print(binascii.b2a_hex(plaintext))
@@ -135,11 +139,14 @@ class TCP_handler(socketserver.StreamRequestHandler):
data = message.split('|') data = message.split('|')
if data[0] != Config.AUTHENTICATION: if data[0] != Config.AUTHENTICATION:
self.wfile.write(b'No authentication') self.wfile.write(b'No authentication')
logging.warning('TCP-%s-No authentication' %
self.client_address[0])
return None return None
global clean_timer global clean_timer
now = round(time.time() * 1000) now = round(time.time() * 1000)
if now - clean_timer >= Config.TIME_LIMIT: if now - clean_timer >= Config.TIME_LIMIT:
logging.info('Start cleaning memory...')
clean_timer = now clean_timer = now
memory_clean(now) memory_clean(now)
@@ -186,6 +193,7 @@ def data_swap(data: list) -> str:
'player_index': 0, 'player_index': 0,
'player_id': player_id} 'player_id': player_id}
logging.info('TCP-Create room `%s` by player `%s`' % (room_code, name))
return '|'.join([str(x) for x in (0, room_code, room_id, token, base64.b64encode(key).decode('utf-8'), player_id)]) return '|'.join([str(x) for x in (0, room_code, room_id, token, base64.b64encode(key).decode('utf-8'), player_id)])
elif data[0] == '2': elif data[0] == '2':
@@ -230,6 +238,7 @@ def data_swap(data: list) -> str:
'player_index': player_index, 'player_index': player_index,
'player_id': player_id} 'player_id': player_id}
logging.info('TCP-Player `%s` joins room `%s`' % (name, room_code))
return '|'.join([str(x) for x in (0, room_code, room.room_id, token, base64.b64encode(key).decode('utf-8'), player_id, base64.b64encode(room.song_unlock).decode('utf-8'))]) return '|'.join([str(x) for x in (0, room_code, room.room_id, token, base64.b64encode(key).decode('utf-8'), player_id, base64.b64encode(room.song_unlock).decode('utf-8'))])
elif data[0] == '3': elif data[0] == '3':
@@ -238,6 +247,7 @@ def data_swap(data: list) -> str:
token = int(data[1]) token = int(data[1])
if token in link_play_data: if token in link_play_data:
r = link_play_data[token] r = link_play_data[token]
logging.info('TCP-Room `%s` info update' % room_code)
return '|'.join([str(x) for x in (0, r['room'].room_code, r['room'].room_id, base64.b64encode(r['key']).decode('utf-8'), r['room'].players[r['player_index']].player_id, base64.b64encode(r['room'].song_unlock).decode('utf-8'))]) return '|'.join([str(x) for x in (0, r['room'].room_code, r['room'].room_id, base64.b64encode(r['key']).decode('utf-8'), r['room'].players[r['player_index']].player_id, base64.b64encode(r['room'].song_unlock).decode('utf-8'))])
else: else:
return '108' return '108'

View File

@@ -230,6 +230,9 @@ class CommandParser:
self.room.countdown = Config.COUNTDOWM_TIME self.room.countdown = Config.COUNTDOWM_TIME
self.room.timestamp = round(time.time() * 1000) self.room.timestamp = round(time.time() * 1000)
self.room.state = 4 self.room.state = 4
if self.room.round_switch == 1:
# 将换房主时间提前到此刻
self.room.make_round()
if self.room.state == 4 or self.room.state == 5 or self.room.state == 6: if self.room.state == 4 or self.room.state == 5 or self.room.state == 6:
timestamp = round(time.time() * 1000) timestamp = round(time.time() * 1000)
@@ -279,8 +282,6 @@ class CommandParser:
flag_13 = True flag_13 = True
self.room.state = 1 self.room.state = 1
self.room.song_idx = 0xffff self.room.song_idx = 0xffff
if self.room.round_switch == 1:
self.room.make_round()
for i in self.room.players: for i in self.room.players:
i.timer = 0 i.timer = 0

View File

@@ -142,15 +142,15 @@ def main():
except: except:
app.logger.warning('Initialization error!') app.logger.warning('Initialization error!')
if Config.LINK_PLAY_HOST and Config.SET_LINK_PLAY_SERVER_AS_SUB_PROCESS: if Config.LINKPLAY_HOST and Config.SET_LINKPLAY_SERVER_AS_SUB_PROCESS:
from linkplay_server import link_play from linkplay_server import link_play
process = [Process(target=link_play, args=( process = [Process(target=link_play, args=(
Config.LINK_PLAY_HOST, int(Config.LINK_PLAY_UDP_PORT), int(Config.LINK_PLAY_TCP_PORT)))] Config.LINKPLAY_HOST, int(Config.LINKPLAY_UDP_PORT), int(Config.LINKPLAY_TCP_PORT)))]
[p.start() for p in process] [p.start() for p in process]
app.logger.info("Link Play UDP server is running on " + app.logger.info("Link Play UDP server is running on " +
Config.LINK_PLAY_HOST + ':' + str(Config.LINK_PLAY_UDP_PORT) + " ...") Config.LINKPLAY_HOST + ':' + str(Config.LINKPLAY_UDP_PORT) + " ...")
app.logger.info("Link Play TCP server is running on " + app.logger.info("Link Play TCP server is running on " +
Config.LINK_PLAY_HOST + ':' + str(Config.LINK_PLAY_TCP_PORT) + " ...") Config.LINKPLAY_HOST + ':' + str(Config.LINKPLAY_TCP_PORT) + " ...")
tcp_server_run() tcp_server_run()
[p.join() for p in process] [p.join() for p in process]
else: else:

View File

@@ -1,2 +1,2 @@
flask>=2.0.2 flask>=2.0.2
cryptography cryptography>=35.0.0

View File

@@ -14,7 +14,7 @@ bp = Blueprint('multiplayer', __name__, url_prefix='/multiplayer')
@auth_required(request) @auth_required(request)
@arc_try @arc_try
def room_create(user_id): def room_create(user_id):
if not Config.LINK_PLAY_HOST: if not Config.LINKPLAY_HOST:
raise ArcError('The link play server is unavailable.', 151, status=404) raise ArcError('The link play server is unavailable.', 151, status=404)
with Connect() as c: with Connect() as c:
@@ -24,8 +24,8 @@ def room_create(user_id):
x.create_room(user) x.create_room(user)
r = x.to_dict() r = x.to_dict()
r['endPoint'] = request.host.split( r['endPoint'] = request.host.split(
':')[0] if Config.LINK_PLAY_DISPLAY_HOST == '' else Config.LINK_PLAY_DISPLAY_HOST ':')[0] if Config.LINKPLAY_DISPLAY_HOST == '' else Config.LINKPLAY_DISPLAY_HOST
r['port'] = int(Config.LINK_PLAY_UDP_PORT) r['port'] = int(Config.LINKPLAY_UDP_PORT)
return success_return(r) return success_return(r)
@@ -33,7 +33,7 @@ def room_create(user_id):
@auth_required(request) @auth_required(request)
@arc_try @arc_try
def room_join(user_id, room_code): def room_join(user_id, room_code):
if not Config.LINK_PLAY_HOST: if not Config.LINKPLAY_HOST:
raise ArcError('The link play server is unavailable.', 151, status=404) raise ArcError('The link play server is unavailable.', 151, status=404)
with Connect() as c: with Connect() as c:
@@ -45,8 +45,8 @@ def room_join(user_id, room_code):
x.join_room(room, user) x.join_room(room, user)
r = x.to_dict() r = x.to_dict()
r['endPoint'] = request.host.split( r['endPoint'] = request.host.split(
':')[0] if Config.LINK_PLAY_DISPLAY_HOST == '' else Config.LINK_PLAY_DISPLAY_HOST ':')[0] if Config.LINKPLAY_DISPLAY_HOST == '' else Config.LINKPLAY_DISPLAY_HOST
r['port'] = int(Config.LINK_PLAY_UDP_PORT) r['port'] = int(Config.LINKPLAY_UDP_PORT)
return success_return(r) return success_return(r)
@@ -54,7 +54,7 @@ def room_join(user_id, room_code):
@auth_required(request) @auth_required(request)
@arc_try @arc_try
def multiplayer_update(user_id): def multiplayer_update(user_id):
if not Config.LINK_PLAY_HOST: if not Config.LINKPLAY_HOST:
raise ArcError('The link play server is unavailable.', 151, status=404) raise ArcError('The link play server is unavailable.', 151, status=404)
with Connect() as c: with Connect() as c:
@@ -64,6 +64,6 @@ def multiplayer_update(user_id):
x.update_room(user) x.update_room(user)
r = x.to_dict() r = x.to_dict()
r['endPoint'] = request.host.split( r['endPoint'] = request.host.split(
':')[0] if Config.LINK_PLAY_DISPLAY_HOST == '' else Config.LINK_PLAY_DISPLAY_HOST ':')[0] if Config.LINKPLAY_DISPLAY_HOST == '' else Config.LINKPLAY_DISPLAY_HOST
r['port'] = int(Config.LINK_PLAY_UDP_PORT) r['port'] = int(Config.LINKPLAY_UDP_PORT)
return success_return(r) return success_return(r)

View File

@@ -42,15 +42,18 @@ class Config():
Setting of your link play server Setting of your link play server
Please ensure that the settings on the side of Link Play server are consistent. Please ensure that the settings on the side of Link Play server are consistent.
''' '''
# SET_LINK_PLAY_SERVER_AS_SUB_PROCESS: If it is `True`, the link play server will run with the main server locally at the same time. # SET_LINKPLAY_SERVER_AS_SUB_PROCESS: 是否同时在本地启动Link Play服务器
SET_LINK_PLAY_SERVER_AS_SUB_PROCESS = True # SET_LINKPLAY_SERVER_AS_SUB_PROCESS: If it is `True`, the link play server will run with the main server locally at the same time.
# LINK_PLAY_HOST: If it is blank, the link play feature will be disabled. SET_LINKPLAY_SERVER_AS_SUB_PROCESS = True
LINK_PLAY_HOST = '0.0.0.0' # LINKPLAY_HOST: 对主服务器来说的Link Play服务器的地址
LINK_PLAY_UDP_PORT = 10900 # LINKPLAY_HOST: The address of the linkplay server based on the main server. If it is blank, the link play feature will be disabled.
LINK_PLAY_TCP_PORT = 10901 LINKPLAY_HOST = '0.0.0.0'
LINK_PLAY_AUTHENTICATION = 'my_link_play_server' LINKPLAY_UDP_PORT = 10900
# LINK_PLAY_DISPLAY_HOST: If it is blank, the host of link play server for the client will be obtained automatically. LINKPLAY_TCP_PORT = 10901
LINK_PLAY_DISPLAY_HOST = '' LINKPLAY_AUTHENTICATION = 'my_link_play_server'
# LINKPLAY_DISPLAY_HOST: 对客户端来说的Link Play服务器地址如果为空则自动获取
# LINKPLAY_DISPLAY_HOST: The address of the linkplay server based on the client. If it is blank, the host of link play server for the client will be obtained automatically.
LINKPLAY_DISPLAY_HOST = ''
''' '''
-------------------- --------------------
''' '''