mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2025-12-14 08:06:23 +08:00
[Enhance][Bug fix] Improve setting file & ...
- Fix a small bug that `best30` of API cannot have scores whose songs are not in database - At present the setting file can be a module or a file with some of options - Limiter can have multiple rules together now
This commit is contained in:
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,5 +1,19 @@
|
||||
# log files
|
||||
*.log
|
||||
|
||||
# SSL cert
|
||||
*.pem
|
||||
*.key
|
||||
|
||||
# sqlite3 database
|
||||
*.db
|
||||
*.db.bak*
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# setting/config files
|
||||
latest version/config/
|
||||
latest version/config.py
|
||||
@@ -2,10 +2,10 @@ from functools import wraps
|
||||
from traceback import format_exc
|
||||
|
||||
from core.api_user import APIUser
|
||||
from core.config_manager import Config
|
||||
from core.error import ArcError, NoAccess, PostError
|
||||
from core.sql import Connect
|
||||
from flask import current_app
|
||||
from setting import Config
|
||||
|
||||
from .api_code import error_return
|
||||
|
||||
|
||||
259
latest version/config.example.py
Normal file
259
latest version/config.example.py
Normal file
@@ -0,0 +1,259 @@
|
||||
class Config():
|
||||
'''
|
||||
This is the example setting file.
|
||||
The user's setting file's name is `config.py`.
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
主机的地址和端口号
|
||||
Host and port of your server
|
||||
'''
|
||||
HOST = '0.0.0.0'
|
||||
PORT = 80
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
游戏API地址前缀
|
||||
Game API's URL prefix
|
||||
'''
|
||||
GAME_API_PREFIX = '/join/21'
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
允许使用的游戏版本,若为空,则默认全部允许
|
||||
Allowed game versions
|
||||
If it is blank, all are allowed.
|
||||
'''
|
||||
ALLOW_APPVERSION = ['3.12.6', '3.12.6c',
|
||||
'4.0.256', '4.0.256c', '4.1.0', '4.1.0c']
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
联机功能相关设置,请确保与Link Play服务器端的设置一致
|
||||
Setting of your link play server
|
||||
Please ensure that the settings on the side of Link Play server are consistent.
|
||||
'''
|
||||
# SET_LINKPLAY_SERVER_AS_SUB_PROCESS: 是否同时在本地启动Link Play服务器
|
||||
# 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.
|
||||
SET_LINKPLAY_SERVER_AS_SUB_PROCESS = True
|
||||
# LINKPLAY_HOST: 对主服务器来说的Link Play服务器的地址
|
||||
# LINKPLAY_HOST: The address of the linkplay server based on the main server. If it is blank, the link play feature will be disabled.
|
||||
LINKPLAY_HOST = '0.0.0.0'
|
||||
LINKPLAY_UDP_PORT = 10900
|
||||
LINKPLAY_TCP_PORT = 10901
|
||||
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 = ''
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
SSL证书路径
|
||||
留空则使用HTTP
|
||||
SSL certificate path
|
||||
If left blank, use HTTP.
|
||||
'''
|
||||
SSL_CERT = '' # *.pem
|
||||
SSL_KEY = '' # *.key
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
愚人节模式开关
|
||||
Switch of April Fool's Day
|
||||
'''
|
||||
IS_APRILFOOLS = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
世界排名的最大显示数量
|
||||
The largest number of global rank
|
||||
'''
|
||||
WORLD_RANK_MAX = 200
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
世界模式当前活动图设置
|
||||
Current available maps in world mode
|
||||
'''
|
||||
AVAILABLE_MAP = [] # Ex. ['test', 'test2']
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
Web后台管理页面的用户名和密码
|
||||
Username and password of web background management page
|
||||
'''
|
||||
USERNAME = 'admin'
|
||||
PASSWORD = 'admin'
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
Web后台管理页面的session秘钥,如果不知道是什么,请不要修改
|
||||
Session key of web background management page
|
||||
If you don't know what it is, please don't modify it.
|
||||
'''
|
||||
SECRET_KEY = '1145141919810'
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
API接口完全控制权限Token,留空则不使用
|
||||
API interface full control permission Token
|
||||
If you don't want to use it, leave it blank.
|
||||
'''
|
||||
API_TOKEN = ''
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
歌曲下载地址前缀,留空则自动获取
|
||||
Song download address prefix
|
||||
If left blank, it will be obtained automatically.
|
||||
'''
|
||||
DOWNLOAD_LINK_PREFIX = '' # http://***.com/download/
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
玩家歌曲下载的24小时次数限制,每个文件算一次
|
||||
Player's song download limit times in 24 hours, once per file
|
||||
'''
|
||||
DOWNLOAD_TIMES_LIMIT = 3000
|
||||
'''
|
||||
歌曲下载链接的有效时长,单位:秒
|
||||
Effective duration of song download link, unit: seconds
|
||||
'''
|
||||
DOWNLOAD_TIME_GAP_LIMIT = 1000
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
Arcaea登录的最大允许设备数量,最小值为1
|
||||
The maximum number of devices allowed to log in Arcaea, minimum: 1
|
||||
'''
|
||||
LOGIN_DEVICE_NUMBER_LIMIT = 1
|
||||
'''
|
||||
是否允许同设备多应用共存登录
|
||||
请注意,这个选项设置为True时,下一个选项将自动变为False
|
||||
If logging in from multiple applications on the same device is allowed
|
||||
Note that when this option is set to True, the next option automatically becomes False
|
||||
'''
|
||||
ALLOW_LOGIN_SAME_DEVICE = False
|
||||
'''
|
||||
24小时内登陆设备数超过最大允许设备数量时,是否自动封号(1天、3天、7天、15天、31天)
|
||||
When the number of login devices exceeds the maximum number of devices allowed to log in Arcaea within 24 hours, whether the account will be automatically banned (1 day, 3 days, 7 days, 15 days, 31 days)
|
||||
'''
|
||||
ALLOW_BAN_MULTIDEVICE_USER_AUTO = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否记录详细的服务器日志
|
||||
If recording detailed server logs is enabled
|
||||
'''
|
||||
ALLOW_INFO_LOG = False
|
||||
ALLOW_WARNING_LOG = False
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
用户注册时的默认记忆源点数量
|
||||
The default amount of memories at the time of user registration
|
||||
'''
|
||||
DEFAULT_MEMORIES = 0
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
数据库更新时,是否采用最新的角色数据,如果你想采用最新的官方角色数据
|
||||
注意:如果是,旧的数据将丢失;如果否,某些角色的数据变动将无法同步
|
||||
If using the latest character data when updating database. If you want to only keep newest official character data, please set it `True`.
|
||||
Note: If `True`, the old data will be lost; If `False`, the data changes of some characters will not be synchronized.
|
||||
'''
|
||||
UPDATE_WITH_NEW_CHARACTER_DATA = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否全解锁搭档
|
||||
If unlocking all partners is enabled
|
||||
'''
|
||||
CHARACTER_FULL_UNLOCK = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否全解锁世界歌曲
|
||||
If unlocking all world songs is enabled
|
||||
'''
|
||||
WORLD_SONG_FULL_UNLOCK = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否全解锁世界场景
|
||||
If unlocking all world sceneries is enabled
|
||||
'''
|
||||
WORLD_SCENERY_FULL_UNLOCK = True
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
|
||||
'''
|
||||
--------------------
|
||||
是否强制使用全解锁云端存档
|
||||
If forcing full unlocked cloud save is enabled
|
||||
请注意,当前对于最终结局的判定为固定在`Testify`解锁之前
|
||||
Please note that the current setting of the finale state is before the unlock of `Testify`
|
||||
'''
|
||||
SAVE_FULL_UNLOCK = False
|
||||
'''
|
||||
--------------------
|
||||
'''
|
||||
@@ -1,6 +1,6 @@
|
||||
from setting import Config
|
||||
from .error import ArcError, InputError, NoData, ItemNotEnough
|
||||
from .config_manager import Config
|
||||
from .constant import Constant
|
||||
from .error import ArcError, InputError, ItemNotEnough, NoData
|
||||
from .item import Item, ItemCore
|
||||
|
||||
|
||||
|
||||
81
latest version/core/config_manager.py
Normal file
81
latest version/core/config_manager.py
Normal file
@@ -0,0 +1,81 @@
|
||||
class Config:
|
||||
'''
|
||||
Default config
|
||||
'''
|
||||
|
||||
HOST = '0.0.0.0'
|
||||
PORT = 80
|
||||
|
||||
GAME_API_PREFIX = '/join/21'
|
||||
|
||||
ALLOW_APPVERSION = [] # list[str]
|
||||
|
||||
SET_LINKPLAY_SERVER_AS_SUB_PROCESS = True
|
||||
|
||||
LINKPLAY_HOST = '0.0.0.0'
|
||||
LINKPLAY_UDP_PORT = 10900
|
||||
LINKPLAY_TCP_PORT = 10901
|
||||
LINKPLAY_AUTHENTICATION = 'my_link_play_server'
|
||||
LINKPLAY_DISPLAY_HOST = ''
|
||||
|
||||
SSL_CERT = ''
|
||||
SSL_KEY = ''
|
||||
|
||||
IS_APRILFOOLS = True
|
||||
|
||||
WORLD_RANK_MAX = 200
|
||||
|
||||
AVAILABLE_MAP = [] # list[str]
|
||||
|
||||
USERNAME = 'admin'
|
||||
PASSWORD = 'admin'
|
||||
|
||||
SECRET_KEY = '1145141919810'
|
||||
|
||||
API_TOKEN = ''
|
||||
|
||||
DOWNLOAD_LINK_PREFIX = ''
|
||||
|
||||
DOWNLOAD_TIMES_LIMIT = 3000
|
||||
DOWNLOAD_TIME_GAP_LIMIT = 1000
|
||||
|
||||
LOGIN_DEVICE_NUMBER_LIMIT = 1
|
||||
ALLOW_LOGIN_SAME_DEVICE = False
|
||||
ALLOW_BAN_MULTIDEVICE_USER_AUTO = True
|
||||
|
||||
ALLOW_INFO_LOG = False
|
||||
ALLOW_WARNING_LOG = False
|
||||
|
||||
DEFAULT_MEMORIES = 0
|
||||
|
||||
UPDATE_WITH_NEW_CHARACTER_DATA = True
|
||||
|
||||
CHARACTER_FULL_UNLOCK = True
|
||||
WORLD_SONG_FULL_UNLOCK = True
|
||||
WORLD_SCENERY_FULL_UNLOCK = True
|
||||
|
||||
SAVE_FULL_UNLOCK = False
|
||||
|
||||
# ------------------------------------------
|
||||
|
||||
# You can change this to make another PTT mechanism.
|
||||
BEST30_WEIGHT = 1 / 40
|
||||
RECENT10_WEIGHT = 1 / 40
|
||||
|
||||
MAX_FRIEND_COUNT = 50
|
||||
|
||||
WORLD_MAP_FOLDER_PATH = './database/map/'
|
||||
SONG_FILE_FOLDER_PATH = './database/songs/'
|
||||
SONGLIST_FILE_PATH = './database/songs/songlist'
|
||||
SQLITE_DATABASE_PATH = './database/arcaea_database.db'
|
||||
|
||||
|
||||
class ConfigManager:
|
||||
|
||||
@staticmethod
|
||||
def load(config):
|
||||
for k, v in config.__dict__.items():
|
||||
if k.startswith('__') or k.endswith('__'):
|
||||
continue
|
||||
if hasattr(Config, k):
|
||||
setattr(Config, k, v)
|
||||
@@ -1,4 +1,4 @@
|
||||
from setting import Config
|
||||
from .config_manager import Config
|
||||
|
||||
|
||||
class Constant:
|
||||
@@ -9,6 +9,8 @@ class Constant:
|
||||
|
||||
STAMINA_RECOVER_TICK = 1800000
|
||||
|
||||
COURSE_STAMINA_COST = 4
|
||||
|
||||
CORE_EXP = 250
|
||||
|
||||
LEVEL_STEPS = {1: 0, 2: 50, 3: 100, 4: 150, 5: 200, 6: 300, 7: 450, 8: 650, 9: 900, 10: 1200, 11: 1600, 12: 2100, 13: 2700, 14: 3400, 15: 4200, 16: 5100,
|
||||
@@ -19,19 +21,18 @@ class Constant:
|
||||
AYU_UNCAP_BONUS_PROGRESS = 5
|
||||
SKILL_FATALIS_WORLD_LOCKED_TIME = 3600000
|
||||
|
||||
MAX_FRIEND_COUNT = 50
|
||||
MAX_FRIEND_COUNT = Config.MAX_FRIEND_COUNT
|
||||
|
||||
MY_RANK_MAX_LOCAL_POSITION = 5
|
||||
MY_RANK_MAX_GLOBAL_POSITION = 9999
|
||||
|
||||
# You can change this to make another PTT mechanism.
|
||||
BEST30_WEIGHT = 1 / 40
|
||||
RECENT10_WEIGHT = 1 / 40
|
||||
BEST30_WEIGHT = Config.BEST30_WEIGHT
|
||||
RECENT10_WEIGHT = Config.RECENT10_WEIGHT
|
||||
|
||||
WORLD_MAP_FOLDER_PATH = './database/map/'
|
||||
SONG_FILE_FOLDER_PATH = './database/songs/'
|
||||
SONGLIST_FILE_PATH = './database/songs/songlist'
|
||||
SQLITE_DATABASE_PATH = './database/arcaea_database.db'
|
||||
WORLD_MAP_FOLDER_PATH = Config.WORLD_MAP_FOLDER_PATH
|
||||
SONG_FILE_FOLDER_PATH = Config.SONG_FILE_FOLDER_PATH
|
||||
SONGLIST_FILE_PATH = Config.SONGLIST_FILE_PATH
|
||||
SQLITE_DATABASE_PATH = Config.SQLITE_DATABASE_PATH
|
||||
|
||||
DOWNLOAD_TIMES_LIMIT = Config.DOWNLOAD_TIMES_LIMIT
|
||||
DOWNLOAD_TIME_GAP_LIMIT = Config.DOWNLOAD_TIME_GAP_LIMIT
|
||||
@@ -45,8 +46,6 @@ class Constant:
|
||||
LINKPLAY_UDP_PORT = Config.LINKPLAY_UDP_PORT
|
||||
LINKPLAY_AUTHENTICATION = Config.LINKPLAY_AUTHENTICATION
|
||||
|
||||
COURSE_STAMINA_COST = 4
|
||||
|
||||
# Well, I can't say a word when I see this.
|
||||
FINALE_SWITCH = [
|
||||
(0x0015F0, 0x00B032), (0x014C9A, 0x014408), (0x062585, 0x02783B),
|
||||
|
||||
@@ -1,91 +1,111 @@
|
||||
class ArcError(Exception):
|
||||
def __init__(self, message=None, error_code=108, api_error_code=-999, extra_data=None, status=200) -> None:
|
||||
self.message = message
|
||||
self.error_code = error_code
|
||||
self.api_error_code = api_error_code
|
||||
self.message: str = message
|
||||
self.error_code: int = error_code
|
||||
self.api_error_code: int = api_error_code
|
||||
self.extra_data = extra_data
|
||||
self.status = status
|
||||
self.status: int = status
|
||||
|
||||
def __str__(self) -> str:
|
||||
return repr(self.message)
|
||||
|
||||
|
||||
class InputError(ArcError):
|
||||
# 输入类型错误
|
||||
'''输入类型错误'''
|
||||
|
||||
def __init__(self, message=None, error_code=108, api_error_code=-100, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class DataExist(ArcError):
|
||||
# 数据存在
|
||||
'''数据存在'''
|
||||
pass
|
||||
|
||||
|
||||
class NoData(ArcError):
|
||||
# 数据不存在
|
||||
'''数据不存在'''
|
||||
|
||||
def __init__(self, message=None, error_code=108, api_error_code=-2, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class PostError(ArcError):
|
||||
# 缺少输入
|
||||
'''缺少输入'''
|
||||
|
||||
def __init__(self, message=None, error_code=108, api_error_code=-100, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class UserBan(ArcError):
|
||||
# 用户封禁
|
||||
'''用户封禁'''
|
||||
|
||||
def __init__(self, message=None, error_code=121, api_error_code=-202, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class ItemNotEnough(ArcError):
|
||||
# 物品数量不足
|
||||
'''物品数量不足'''
|
||||
|
||||
def __init__(self, message=None, error_code=-6, api_error_code=-999, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class ItemUnavailable(ArcError):
|
||||
# 物品不可用
|
||||
'''物品不可用'''
|
||||
|
||||
def __init__(self, message=None, error_code=-6, api_error_code=-999, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class RedeemUnavailable(ArcError):
|
||||
# 兑换码不可用
|
||||
'''兑换码不可用'''
|
||||
|
||||
def __init__(self, message=None, error_code=505, api_error_code=-999, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class MapLocked(ArcError):
|
||||
# 地图锁定
|
||||
'''地图锁定'''
|
||||
|
||||
def __init__(self, message=None, error_code=108, api_error_code=-999, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class StaminaNotEnough(ArcError):
|
||||
# 体力不足
|
||||
'''体力不足'''
|
||||
|
||||
def __init__(self, message=None, error_code=107, api_error_code=-999, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class TicketNotEnough(ArcError):
|
||||
# 记忆源点不足
|
||||
'''记忆源点不足'''
|
||||
|
||||
def __init__(self, message=None, error_code=-6, api_error_code=-999, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class FriendError(ArcError):
|
||||
# 好友系统出错
|
||||
'''好友系统出错'''
|
||||
|
||||
def __init__(self, message=None, error_code=108, api_error_code=-999, extra_data=None, status=200) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class NoAccess(ArcError):
|
||||
# 无权限
|
||||
pass
|
||||
'''无权限'''
|
||||
|
||||
def __init__(self, message=None, error_code=108, api_error_code=-999, extra_data=None, status=403) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
|
||||
class Timeout(ArcError):
|
||||
# 超时
|
||||
'''超时'''
|
||||
pass
|
||||
|
||||
|
||||
class RateLimit(ArcError):
|
||||
'''频率达到限制'''
|
||||
|
||||
def __init__(self, message=None, error_code=108, api_error_code=-999, extra_data=None, status=429) -> None:
|
||||
super().__init__(message, error_code, api_error_code, extra_data, status)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from .config_manager import Config
|
||||
from .error import InputError, ItemNotEnough, ItemUnavailable, NoData
|
||||
from setting import Config
|
||||
|
||||
|
||||
class Item:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from limits import parse, strategies
|
||||
from limits import parse_many, strategies
|
||||
from limits.storage import storage_from_string
|
||||
|
||||
|
||||
@@ -6,23 +6,26 @@ class ArcLimiter:
|
||||
storage = storage_from_string("memory://")
|
||||
strategy = strategies.FixedWindowRateLimiter(storage)
|
||||
|
||||
def __init__(self, limit: str = None, namespace: str = None):
|
||||
self._limit = None
|
||||
self.limit = limit
|
||||
def __init__(self, limit_str: str = None, namespace: str = None):
|
||||
self._limits = None
|
||||
self.limits = limit_str
|
||||
self.namespace = namespace
|
||||
|
||||
@property
|
||||
def limit(self):
|
||||
return self._limit
|
||||
def limits(self):
|
||||
return self._limits
|
||||
|
||||
@limit.setter
|
||||
def limit(self, value):
|
||||
@limits.setter
|
||||
def limits(self, value: str):
|
||||
if value is None:
|
||||
return
|
||||
self._limit = parse(value)
|
||||
self._limits = parse_many(value)
|
||||
|
||||
def hit(self, key: str, cost: int = 1) -> bool:
|
||||
return self.strategy.hit(self.limit, self.namespace, key, cost=cost)
|
||||
flag = True
|
||||
for limit in self.limits:
|
||||
flag &= self.strategy.hit(limit, self.namespace, key, cost)
|
||||
return flag
|
||||
|
||||
def test(self, key: str) -> bool:
|
||||
return self.strategy.test(self.limit, self.namespace, key)
|
||||
return all(self.strategy.test(limit, self.namespace, key) for limit in self.limits)
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import json
|
||||
from time import time
|
||||
|
||||
from setting import Config
|
||||
|
||||
from core.constant import Constant
|
||||
|
||||
from .config_manager import Config
|
||||
from .constant import Constant
|
||||
from .error import InputError
|
||||
from .util import md5
|
||||
|
||||
|
||||
@@ -580,4 +580,5 @@ class UserScoreList:
|
||||
for score in self.scores:
|
||||
self.c.execute(
|
||||
'''select name from chart where song_id = ?''', (score.song.song_id,))
|
||||
score.song.song_name = self.c.fetchone()[0]
|
||||
x = self.c.fetchone()
|
||||
score.song.song_name = x[0] if x else ''
|
||||
|
||||
@@ -3,9 +3,8 @@ import hashlib
|
||||
import time
|
||||
from os import urandom
|
||||
|
||||
from setting import Config
|
||||
|
||||
from .character import UserCharacter, UserCharacterList
|
||||
from .config_manager import Config
|
||||
from .constant import Constant
|
||||
from .error import (ArcError, DataExist, FriendError, InputError, NoAccess,
|
||||
NoData, UserBan)
|
||||
|
||||
@@ -207,11 +207,6 @@ def main(path='./'):
|
||||
time int,
|
||||
primary key(user_id, song_id, file_name)
|
||||
);''')
|
||||
# c.execute('''create table if not exists user_download(user_id int,
|
||||
# time int,
|
||||
# token text,
|
||||
# primary key(user_id, time, token)
|
||||
# );''')
|
||||
c.execute('''create table if not exists item(item_id text,
|
||||
type text,
|
||||
is_available int,
|
||||
|
||||
@@ -2,12 +2,19 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
from importlib import import_module
|
||||
from logging.config import dictConfig
|
||||
from multiprocessing import Process, set_start_method
|
||||
from traceback import format_exc
|
||||
|
||||
from flask import Flask, make_response, request, send_from_directory
|
||||
|
||||
from core.config_manager import Config, ConfigManager
|
||||
|
||||
if os.path.exists('config.py') or os.path.exists('config'):
|
||||
ConfigManager.load(import_module('config').Config)
|
||||
|
||||
|
||||
import api
|
||||
import server
|
||||
import server.init
|
||||
@@ -16,10 +23,9 @@ import web.login
|
||||
from core.constant import Constant
|
||||
from core.download import (UserDownload, get_only_3_song_ids,
|
||||
initialize_songfile)
|
||||
from core.error import ArcError
|
||||
from core.error import ArcError, NoAccess, RateLimit
|
||||
from core.sql import Connect
|
||||
from server.func import error_return
|
||||
from setting import Config
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@@ -31,6 +37,7 @@ app = Flask(__name__)
|
||||
|
||||
os.chdir(sys.path[0]) # 更改工作路径,以便于愉快使用相对路径
|
||||
|
||||
|
||||
app.config.from_mapping(SECRET_KEY=Config.SECRET_KEY)
|
||||
app.config['SESSION_TYPE'] = 'filesystem'
|
||||
app.register_blueprint(web.login.bp)
|
||||
@@ -62,10 +69,9 @@ def download(file_path):
|
||||
x.song_id, x.file_name = file_path.split('/', 1)
|
||||
x.select_for_check()
|
||||
if x.is_limited:
|
||||
raise ArcError(
|
||||
'You have reached the download limit.', 903, status=429)
|
||||
raise RateLimit('You have reached the download limit.', 903)
|
||||
if not x.is_valid:
|
||||
raise ArcError('Expired token.', status=403)
|
||||
raise NoAccess('Expired token.')
|
||||
x.download_hit()
|
||||
# response = make_response()
|
||||
# response.headers['Content-Type'] = 'application/octet-stream'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from core.config_manager import Config
|
||||
from flask import Blueprint
|
||||
from setting import Config
|
||||
|
||||
from . import (auth, course, friend, multiplayer, others, present, purchase,
|
||||
score, user, world)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import base64
|
||||
from functools import wraps
|
||||
|
||||
from core.config_manager import Config
|
||||
from core.error import ArcError, NoAccess
|
||||
from core.sql import Connect
|
||||
from core.user import UserAuth, UserLogin
|
||||
from flask import Blueprint, jsonify, request
|
||||
from setting import Config
|
||||
|
||||
from .func import arc_try, error_return
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from functools import wraps
|
||||
from traceback import format_exc
|
||||
|
||||
from core.config_manager import Config
|
||||
from core.error import ArcError
|
||||
from flask import current_app, jsonify
|
||||
from setting import Config
|
||||
|
||||
default_error = ArcError('Unknown Error', status=500)
|
||||
|
||||
|
||||
@@ -25,10 +25,6 @@ def check_before_run(app):
|
||||
|
||||
f = True
|
||||
|
||||
if not os.path.exists('setting.py'):
|
||||
app.logger.warning('File `setting.py` is missing.')
|
||||
f = False
|
||||
|
||||
if not os.path.exists('database'):
|
||||
app.logger.warning('Folder `database` is missing.')
|
||||
f = False
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from core.config_manager import Config
|
||||
from core.error import ArcError
|
||||
from core.linkplay import Player, RemoteMultiPlayer, Room
|
||||
from core.sql import Connect
|
||||
from flask import Blueprint, request
|
||||
from setting import Config
|
||||
|
||||
from .auth import auth_required
|
||||
from .func import arc_try, success_return
|
||||
|
||||
@@ -2,7 +2,7 @@ import json
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
from core.download import DownloadList
|
||||
from core.error import ArcError
|
||||
from core.error import RateLimit
|
||||
from core.sql import Connect
|
||||
from core.system import GameInfo
|
||||
from core.user import UserOnline
|
||||
@@ -34,7 +34,7 @@ def download_song(user_id):
|
||||
x.song_ids = request.args.getlist('sid')
|
||||
x.url_flag = json.loads(request.args.get('url', 'true'))
|
||||
if x.url_flag and x.is_limited:
|
||||
raise ArcError('You have reached the download limit.', 903)
|
||||
raise RateLimit('You have reached the download limit.', 903)
|
||||
|
||||
x.add_songs()
|
||||
return success_return(x.urls)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from core.character import UserCharacter
|
||||
from core.config_manager import Config
|
||||
from core.error import ArcError, NoAccess
|
||||
from core.item import ItemCore
|
||||
from core.save import SaveData
|
||||
from core.sql import Connect
|
||||
from core.user import User, UserLogin, UserOnline, UserRegister
|
||||
from flask import Blueprint, request
|
||||
from setting import Config
|
||||
|
||||
from .auth import auth_required
|
||||
from .func import arc_try, success_return
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#import sqlite3
|
||||
from flask import (Blueprint, flash, g, redirect,
|
||||
render_template, request, session, url_for)
|
||||
import functools
|
||||
from setting import Config
|
||||
import hashlib
|
||||
|
||||
from core.config_manager import Config
|
||||
from flask import (Blueprint, flash, g, redirect, render_template, request,
|
||||
session, url_for)
|
||||
|
||||
bp = Blueprint('login', __name__, url_prefix='/web')
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import os
|
||||
from core.sql import Connect
|
||||
import time
|
||||
import hashlib
|
||||
import os
|
||||
import time
|
||||
from random import Random
|
||||
from setting import Config
|
||||
|
||||
from core.config_manager import Config
|
||||
from core.sql import Connect
|
||||
|
||||
|
||||
def int2b(x):
|
||||
@@ -216,10 +217,10 @@ def update_database():
|
||||
update_one_table(c1, c2, 'api_login')
|
||||
update_one_table(c1, c2, 'chart')
|
||||
update_one_table(c1, c2, 'user_course')
|
||||
update_one_table(c1, c2, 'course')
|
||||
update_one_table(c1, c2, 'course_item')
|
||||
update_one_table(c1, c2, 'course_chart')
|
||||
update_one_table(c1, c2, 'course_requirement')
|
||||
# update_one_table(c1, c2, 'course')
|
||||
# update_one_table(c1, c2, 'course_item')
|
||||
# update_one_table(c1, c2, 'course_chart')
|
||||
# update_one_table(c1, c2, 'course_requirement')
|
||||
|
||||
update_one_table(c1, c2, 'user_char')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user