[Enhance][Bug fix] Add log db & log bug

- Add a log database to record all playing scores
- Fix a bug that if an exception is raised before flask app runs, logger will not work well.
This commit is contained in:
Lost-MSth
2022-11-26 21:03:29 +08:00
parent 84b0e869a5
commit a7a9a4ba3d
8 changed files with 92 additions and 18 deletions

View File

@@ -77,6 +77,7 @@ class Config:
SQLITE_DATABASE_PATH = './database/arcaea_database.db'
SQLITE_DATABASE_BACKUP_FOLDER_PATH = './database/backup/'
DATABASE_INIT_PATH = './database/init/'
SQLITE_LOG_DATABASE_PATH = './database/arcaea_log.db'
GAME_LOGIN_RATE_LIMIT = '30/5 minutes'
API_LOGIN_RATE_LIMIT = '10/5 minutes'

View File

@@ -35,6 +35,7 @@ class Constant:
SONG_FILE_FOLDER_PATH = Config.SONG_FILE_FOLDER_PATH
SONGLIST_FILE_PATH = Config.SONGLIST_FILE_PATH
SQLITE_DATABASE_PATH = Config.SQLITE_DATABASE_PATH
SQLITE_LOG_DATABASE_PATH = Config.SQLITE_LOG_DATABASE_PATH
DOWNLOAD_TIMES_LIMIT = Config.DOWNLOAD_TIMES_LIMIT
DOWNLOAD_TIME_GAP_LIMIT = Config.DOWNLOAD_TIME_GAP_LIMIT

View File

@@ -157,35 +157,70 @@ class DatabaseInit:
self.admin_init()
class LogDatabaseInit:
def __init__(self, db_path: str = Config.SQLITE_LOG_DATABASE_PATH, init_folder_path: str = Config.DATABASE_INIT_PATH) -> None:
self.db_path = db_path
self.init_folder_path = init_folder_path
self.c = None
@property
def sql_path(self) -> str:
return os.path.join(self.init_folder_path, 'log_tables.sql')
def table_init(self) -> None:
'''初始化数据库结构'''
with open(self.sql_path, 'r') as f:
self.c.executescript(f.read())
self.c.execute(
'''insert into cache values("version", :a, -1);''', {'a': ARCAEA_SERVER_VERSION})
def init(self) -> None:
with Connect(self.db_path) as c:
self.c = c
self.table_init()
class FileChecker:
def __init__(self, app=None):
self.app = app
def __init__(self, logger=None):
self.logger = logger
def check_file(self, file_path: str) -> bool:
f = os.path.isfile(file_path)
if not f:
self.app.logger.warning('File `%s` is missing.' % file_path)
self.logger.warning('File `%s` is missing.' % file_path)
return f
def check_folder(self, folder_path: str) -> bool:
f = os.path.isdir(folder_path)
if not f:
self.app.logger.warning('Folder `%s` is missing.' % folder_path)
self.logger.warning('Folder `%s` is missing.' % folder_path)
return f
def check_update_database(self) -> bool:
if not self.check_file(Config.SQLITE_LOG_DATABASE_PATH):
# 新建日志数据库
try:
self.logger.info(
f'Try to new the file {Config.SQLITE_LOG_DATABASE_PATH}')
LogDatabaseInit().init()
self.logger.info(
f'Success to new the file {Config.SQLITE_LOG_DATABASE_PATH}')
except:
self.logger.error(
f'Failed to new the file {Config.SQLITE_LOG_DATABASE_PATH}')
return False
if not self.check_file(Config.SQLITE_DATABASE_PATH):
# 新建数据库
try:
self.app.logger.info(
self.logger.info(
'Try to new the file `%s`.' % Config.SQLITE_DATABASE_PATH)
DatabaseInit().init()
self.app.logger.info(
self.logger.info(
'Success to new the file `%s`.' % Config.SQLITE_DATABASE_PATH)
except:
self.app.logger.warning(
'Fail to new the file `%s`.' % Config.SQLITE_DATABASE_PATH)
self.logger.warning(
'Failed to new the file `%s`.' % Config.SQLITE_DATABASE_PATH)
return False
else:
# 检查更新
@@ -197,10 +232,10 @@ class FileChecker:
x = None
# 数据库自动更新,不强求
if not x or x[0] != ARCAEA_SERVER_VERSION:
self.app.logger.warning(
self.logger.warning(
'Maybe the file `%s` is an old version.' % Config.SQLITE_DATABASE_PATH)
try:
self.app.logger.info(
self.logger.info(
'Try to update the file `%s`.' % Config.SQLITE_DATABASE_PATH)
if not os.path.isdir(Config.SQLITE_DATABASE_BACKUP_FOLDER_PATH):
@@ -224,11 +259,11 @@ class FileChecker:
DatabaseInit().init()
self.update_database(temp_path)
self.app.logger.info(
self.logger.info(
'Success to update the file `%s`.' % Config.SQLITE_DATABASE_PATH)
except ValueError:
self.app.logger.warning(
self.logger.warning(
'Fail to update the file `%s`.' % Config.SQLITE_DATABASE_PATH)
return True

View File

@@ -23,6 +23,7 @@ class RefreshAllScoreRating(BaseOperation):
def run(self):
# 追求效率不用Song类尽量不用对象
# 但其实还是很慢
with Connect() as c:
c.execute(
'''select song_id, rating_pst, rating_prs, rating_ftr, rating_byn from chart''')

View File

@@ -7,7 +7,7 @@ from .course import CoursePlay
from .error import NoData, StaminaNotEnough
from .item import ItemCore
from .song import Chart
from .sql import Query, Sql
from .sql import Connect, Query, Sql
from .util import md5
from .world import WorldPlay
@@ -408,6 +408,12 @@ class UserPlay(UserScore):
self.ptt.insert_recent_30()
def record_score(self) -> None:
'''向log数据库记录分数请注意列名不同'''
with Connect(Constant.SQLITE_LOG_DATABASE_PATH) as c2:
c2.execute('''insert into user_score values(?,?,?,?,?,?,?,?,?,?,?,?,?)''', (self.user.user_id, self.song.song_id, self.song.difficulty, self.time_played,
self.score, self.shiny_perfect_count, self.perfect_count, self.near_count, self.miss_count, self.health, self.modifier, self.clear_type, self.rating))
def upload_score(self) -> None:
'''上传分数包括user的recent更新best更新recent30更新世界模式计算'''
self.get_play_state()
@@ -420,6 +426,9 @@ class UserPlay(UserScore):
self.time_played = int(time())
# 记录分数
self.record_score()
# recent更新
self.c.execute('''update user set song_id = :b, difficulty = :c, score = :d, shiny_perfect_count = :e, perfect_count = :f, near_count = :g, miss_count = :h, health = :i, modifier = :j, clear_type = :k, rating = :l, time_played = :m where user_id = :a''', {
'a': self.user.user_id, 'b': self.song.song_id, 'c': self.song.difficulty, 'd': self.score, 'e': self.shiny_perfect_count, 'f': self.perfect_count, 'g': self.near_count, 'h': self.miss_count, 'i': self.health, 'j': self.modifier, 'k': self.clear_type, 'l': self.rating, 'm': self.time_played * 1000})

View File

@@ -2,16 +2,15 @@ import sqlite3
import traceback
from atexit import register
from flask import current_app
from .constant import Constant
from .error import ArcError, InputError
class Connect:
# 数据库连接类,上下文管理
logger = None
def __init__(self, file_path: str = Constant.SQLITE_DATABASE_PATH, in_memory: bool = False):
def __init__(self, file_path: str = Constant.SQLITE_DATABASE_PATH, in_memory: bool = False, logger=None) -> None:
"""
数据库连接默认连接arcaea_database.db\
接受:文件路径\
@@ -19,6 +18,8 @@ class Connect:
"""
self.file_path = file_path
self.in_memory: bool = in_memory
if logger is not None:
self.logger = logger
def __enter__(self) -> sqlite3.Cursor:
if self.in_memory:
@@ -37,7 +38,7 @@ class Connect:
else:
self.conn.rollback()
current_app.logger.error(
self.logger.error(
traceback.format_exception(exc_type, exc_val, exc_tb))
self.conn.commit()

View File

@@ -0,0 +1,25 @@
create table if not exists cache(key text primary key,
value text,
expire_time int
);
create table if not exists user_score(user_id int,
song_id text,
difficulty int,
time_played int,
score int,
shiny_perfect_count int,
perfect_count int,
near_count int,
miss_count int,
health int,
modifier int,
clear_type int,
rating real,
primary key(user_id, song_id, difficulty, time_played)
);
create index if not exists user_score_1 on user_score (song_id, difficulty);
create index if not exists user_score_2 on user_score (time_played);
PRAGMA journal_mode = WAL;
PRAGMA default_cache_size = 4000;

View File

@@ -182,7 +182,8 @@ def main():
dictConfig(log_dict)
if not FileChecker(app).check_before_run():
Connect.logger = app.logger
if not FileChecker(app.logger).check_before_run():
app.logger.error('Something wrong. The server will not run.')
input('Press ENTER key to exit.')
sys.exit()