🎨 使用Python包管理和模块访问

🎨 重构数据库结构, 使用集中式服务定位器与数据库交互
🎨 更改部分代码逻辑, 减小内存消耗
This commit is contained in:
2025-11-30 16:45:13 +08:00
parent b4d3baebe6
commit a6691595e5
29 changed files with 1356 additions and 885 deletions
+25
View File
@@ -0,0 +1,25 @@
from .database import g_pSqlManager
from .dbServiceLocator import g_pDBlocator
from .plant import CPlantManager
from .user import CUserDB
from .userItem import CUserItemDB
from .userPlant import CUserPlantDB
from .userPlantCount import CUserPlantCountDB
from .userSeed import CUserSeedDB
from .userSign import CUserSignDB
from .userSoil import CUserSoilDB
from .userSteal import CUserStealDB
__all__ = [
"CPlantManager",
"CUserDB",
"CUserItemDB",
"CUserPlantCountDB",
"CUserPlantDB",
"CUserSeedDB",
"CUserSignDB",
"CUserSoilDB",
"CUserStealDB",
"g_pDBlocator",
"g_pSqlManager",
]
+171 -57
View File
@@ -1,60 +1,188 @@
from abc import ABC
from contextlib import asynccontextmanager
import os
from pathlib import Path
import re
from typing import Any
from typing import Any, ClassVar
import aiosqlite
from zhenxun.services.log import logger
from ...utils.config import g_sDBFilePath, g_sDBPath
from ...utils import config
from .dbServiceLocator import g_pDBlocator
class CSqlManager:
class CSqlManager(ABC):
"""
数据库管理器基类
所有具体的数据管理器都应该继承这个类
"""
m_pDB: ClassVar[aiosqlite.Connection | None] = None
def __init__(self):
dbPath = Path(g_sDBPath)
if dbPath and not dbPath.exists():
os.makedirs(dbPath, exist_ok=True)
self.m_sTableName: str | None = None
self.m_bInitialized: bool = False
@classmethod
async def cleanup(cls):
if hasattr(cls, "m_pDB") and cls.m_pDB:
await cls.m_pDB.close()
self.m_pDBPath = Path(config.g_sDBPath)
if self.m_pDBPath and not self.m_pDBPath.exists():
os.makedirs(self.m_pDBPath, exist_ok=True)
@classmethod
async def init(cls) -> bool:
try:
cls.m_pDB = await aiosqlite.connect(g_sDBFilePath)
cls.m_pDB.row_factory = aiosqlite.Row
return True
if cls.m_pDB is None:
cls.m_pDB = await aiosqlite.connect(config.g_sDBFilePath)
cls.m_pDB.row_factory = aiosqlite.Row
logger.info("真寻农场数据库连接初始化成功")
return True
else:
logger.info("真寻农场数据库连接已存在,跳过初始化")
return True
except Exception as e:
logger.debug("真寻农场初始化总数据库失败", e=e)
logger.error(f"真寻农场数据库连接初始化失败: {e}")
return False
@classmethod
async def cleanup(cls):
if cls.m_pDB:
await cls.m_pDB.close()
cls.m_pDB = None
logger.info("真寻农场数据库连接已关闭")
@classmethod
def getDB(cls) -> aiosqlite.Connection:
if cls.m_pDB is None:
raise RuntimeError("数据库连接未初始化,请先调用 init_global_db()")
return cls.m_pDB
@classmethod
def getPlantManager(cls) -> Any:
return g_pDBlocator.getPlantManager()
@classmethod
def getUserManager(cls) -> Any:
return g_pDBlocator.getUserManager()
@classmethod
def getUserSoilManager(cls) -> Any:
return g_pDBlocator.getUserSoilManager()
@classmethod
def getUserSeedManager(cls) -> Any:
return g_pDBlocator.getUserSeedManager()
@classmethod
def getUserItemManager(cls) -> Any:
return g_pDBlocator.getUserItemManager()
@classmethod
def getUserStealManager(cls) -> Any:
return g_pDBlocator.getUserStealManager()
@classmethod
def getUserSignManager(cls) -> Any:
return g_pDBlocator.getUserSignManager()
@classmethod
def getUserPlantCountManager(cls) -> Any:
return g_pDBlocator.getUserPlantCountManager()
def isInitialized(self) -> bool:
"""检查是否已初始化"""
return self.m_bInitialized
def setInitialized(self) -> None:
"""标记为已初始化"""
self.m_bInitialized = True
@classmethod
@asynccontextmanager
async def _transaction(cls):
await cls.m_pDB.execute("BEGIN;")
await cls.getDB().execute("BEGIN;")
try:
yield
except:
await cls.m_pDB.execute("ROLLBACK;")
await cls.getDB().execute("ROLLBACK;")
raise
else:
await cls.m_pDB.execute("COMMIT;")
await cls.getDB().execute("COMMIT;")
@classmethod
async def getTableInfo(cls, tableName: str) -> list:
if not re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", tableName):
raise ValueError(f"Illegal table name: {tableName}")
try:
cursor = await cls.m_pDB.execute(f'PRAGMA table_info("{tableName}")')
cursor = await cls.getDB().execute(f'PRAGMA table_info("{tableName}")')
rows = await cursor.fetchall()
return [{"name": row[1], "type": row[2]} for row in rows]
except aiosqlite.Error:
return []
# @classmethod
# async def ensureTableSchema(cls, tableName: str, columns: dict) -> bool:
# """由AI生成
# 创建表或为已存在表添加缺失字段。
# 返回 True 表示有变更(创建或新增列),False 则无操作
# Args:
# tableName (str): 表名
# columns (dict): 字典
# Returns:
# bool:
# """
# info = await cls.getTableInfo(tableName)
# existing = {col["name"]: col["type"].upper() for col in info}
# desired = {k: v.upper() for k, v in columns.items() if k != "PRIMARY KEY"}
# primaryKey = columns.get("PRIMARY KEY", "")
# if not existing:
# colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items())
# if primaryKey:
# colsDef += f", PRIMARY KEY {primaryKey}"
# await cls.getDB().execute(f'CREATE TABLE "{tableName}" ({colsDef});')
# return True
# toAdd = [k for k in desired if k not in existing]
# toRemove = [k for k in existing if k not in desired]
# typeMismatch = [
# k for k in desired if k in existing and existing[k] != desired[k]
# ]
# if toAdd and not toRemove and not typeMismatch:
# for col in toAdd:
# await cls.getDB().execute(
# f'ALTER TABLE "{tableName}" ADD COLUMN "{col}" {columns[col]}'
# )
# return True
# async with cls._transaction():
# tmpTable = f"{tableName}_new"
# colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items())
# if primaryKey:
# colsDef += f", PRIMARY KEY {primaryKey}"
# await cls.getDB().execute(f'CREATE TABLE "{tmpTable}" ({colsDef});')
# commonCols = [k for k in desired if k in existing]
# if commonCols:
# colsStr = ", ".join(f'"{c}"' for c in commonCols)
# sql = (
# f'INSERT INTO "{tmpTable}" ({colsStr}) '
# f"SELECT {colsStr} "
# f'FROM "{tableName}";'
# )
# await cls.getDB().execute(sql)
# await cls.getDB().execute(f'DROP TABLE "{tableName}";')
# await cls.getDB().execute(
# f'ALTER TABLE "{tmpTable}" RENAME TO "{tableName}";'
# )
# return True
@classmethod
async def ensureTableSchema(cls, tableName: str, columns: dict) -> bool:
"""由AI生成
@@ -62,13 +190,12 @@ class CSqlManager:
返回 True 表示有变更(创建或新增列),False 则无操作
Args:
tableName (_type_): 表名
columns (_type_): 字典
tableName (str): 表名
columns (dict): 字典
Returns:
_type_: _description_
bool:
"""
info = await cls.getTableInfo(tableName)
existing = {col["name"]: col["type"].upper() for col in info}
desired = {k: v.upper() for k, v in columns.items() if k != "PRIMARY KEY"}
@@ -78,7 +205,7 @@ class CSqlManager:
colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items())
if primaryKey:
colsDef += f", PRIMARY KEY {primaryKey}"
await cls.m_pDB.execute(f'CREATE TABLE "{tableName}" ({colsDef});')
await cls.getDB().execute(f'CREATE TABLE "{tableName}" ({colsDef});')
return True
toAdd = [k for k in desired if k not in existing]
@@ -87,36 +214,23 @@ class CSqlManager:
k for k in desired if k in existing and existing[k] != desired[k]
]
if toAdd and not toRemove and not typeMismatch:
if toRemove or typeMismatch:
return False
if toAdd:
for col in toAdd:
await cls.m_pDB.execute(
f'ALTER TABLE "{tableName}" ADD COLUMN "{col}" {columns[col]}'
)
try:
await cls.getDB().execute(
f'ALTER TABLE "{tableName}" ADD COLUMN "{col}" {columns[col]}'
)
except aiosqlite.OperationalError as e:
if "duplicate column name" in str(e).lower():
continue
else:
raise
return True
async with cls._transaction():
tmpTable = f"{tableName}_new"
colsDef = ", ".join(f'"{k}" {v}' for k, v in desired.items())
if primaryKey:
colsDef += f", PRIMARY KEY {primaryKey}"
await cls.m_pDB.execute(f'CREATE TABLE "{tmpTable}" ({colsDef});')
commonCols = [k for k in desired if k in existing]
if commonCols:
colsStr = ", ".join(f'"{c}"' for c in commonCols)
sql = (
f'INSERT INTO "{tmpTable}" ({colsStr}) '
f"SELECT {colsStr} "
f'FROM "{tableName}";'
)
await cls.m_pDB.execute(sql)
await cls.m_pDB.execute(f'DROP TABLE "{tableName}";')
await cls.m_pDB.execute(
f'ALTER TABLE "{tmpTable}" RENAME TO "{tableName}";'
)
return True
return False
@classmethod
async def executeDB(cls, command: str) -> bool:
@@ -133,7 +247,7 @@ class CSqlManager:
try:
async with cls._transaction():
await cls.m_pDB.execute(command)
await cls.getDB().execute(command)
return True
except Exception:
return False
@@ -162,7 +276,7 @@ class CSqlManager:
sql = f'INSERT INTO "{tableName}" ({columns}) VALUES ({placeholders})'
async with cls._transaction():
await cls.m_pDB.execute(sql, values)
await cls.getDB().execute(sql, values)
return True
except Exception as e:
logger.debug("真寻农场插入数据失败!", e=e)
@@ -191,7 +305,7 @@ class CSqlManager:
sql = f'INSERT INTO "{tableName}" ({columns}) VALUES ({placeholders})'
async with cls._transaction():
await cls.m_pDB.executemany(
await cls.getDB().executemany(
sql, [list(data.values()) for data in data_list]
)
return True
@@ -255,7 +369,7 @@ class CSqlManager:
if limit:
sql += f" LIMIT {limit}"
cursor = await cls.m_pDB.execute(sql, params)
cursor = await cls.getDB().execute(sql, params)
rows = await cursor.fetchall()
# 转换为字典列表
@@ -304,7 +418,7 @@ class CSqlManager:
sql = f'UPDATE "{tableName}" SET {", ".join(set_conditions)} WHERE {" AND ".join(where_conditions)}'
async with cls._transaction():
cursor = await cls.m_pDB.execute(sql, params)
cursor = await cls.getDB().execute(sql, params)
# 检查是否影响了行
return cursor.rowcount > 0
except Exception as e:
@@ -337,7 +451,7 @@ class CSqlManager:
sql = f'DELETE FROM "{tableName}" WHERE {" AND ".join(where_conditions)}'
async with cls._transaction():
cursor = await cls.m_pDB.execute(sql, params)
cursor = await cls.getDB().execute(sql, params)
# 检查是否影响了行
return cursor.rowcount > 0
except Exception as e:
@@ -388,7 +502,7 @@ class CSqlManager:
sql += " WHERE " + " AND ".join(where_conditions)
cursor = await cls.m_pDB.execute(sql, params)
cursor = await cls.getDB().execute(sql, params)
row = await cursor.fetchone()
return row["count"] if row else 0
except Exception as e:
+85
View File
@@ -0,0 +1,85 @@
from typing import Any, Optional
from zhenxun.services.log import logger
class CDBServiceLocator:
"""
数据库服务定位器
负责管理所有数据库服务实例,提供统一的访问接口
"""
m_pInstance: Optional["CDBServiceLocator"] = None
def __init__(self):
self.m_pServices: dict[str, Any] = {}
self.m_bInitialized = False
@classmethod
def getInstance(cls) -> "CDBServiceLocator":
"""
获取单例实例
"""
if cls.m_pInstance is None:
cls.m_pInstance = cls()
return cls.m_pInstance
def register(self, name: str, service: Any) -> None:
"""
注册服务实例
"""
if name in self.m_pServices:
logger.error(f"真寻农场服务 {name} 已经注册")
self.m_pServices[name] = service
def get(self, name: str) -> Any:
"""
获取服务实例
"""
if name not in self.m_pServices:
raise KeyError(f"服务 {name} 未注册")
return self.m_pServices[name]
def getPlantManager(self):
return self.get("plant")
def getUserManager(self):
return self.get("user")
def getUserSoilManager(self):
return self.get("userSoil")
def getUserPlantManager(self):
return self.get("userPlant")
def getUserSeedManager(self):
return self.get("userSeed")
def getUserItemManager(self):
return self.get("userItem")
def getUserStealManager(self):
return self.get("userSteal")
def getUserSignManager(self):
return self.get("userSign")
def getUserPlantCountManager(self):
return self.get("userPlantCount")
def markInitialized(self):
"""
标记初始化完成
"""
self.m_bInitialized = True
@property
def initialized(self) -> bool:
"""
检查是否已初始化
"""
return self.m_bInitialized
# 全局服务定位器实例
g_pDBlocator = CDBServiceLocator.getInstance()
+19 -10
View File
@@ -6,14 +6,16 @@ import aiosqlite
from zhenxun.configs.config import Config
from zhenxun.services.log import logger
from ...utils.config import g_bIsDebug, g_sPlantPath, g_sResourcePath
from ...utils.request import g_pRequestManager
from ...utils import config, getRequestManager
class CPlantManager:
def __init__(self):
self.m_sTableName = "plant"
self.m_bInitialized = False
try:
os.mkdir(g_sPlantPath)
os.mkdir(config.g_sPlantPath)
except FileExistsError:
pass
@@ -23,14 +25,14 @@ class CPlantManager:
async def init(self) -> bool:
try:
_ = os.path.exists(g_sPlantPath)
_ = os.path.exists(config.g_sPlantPath)
if g_bIsDebug:
if config.g_bIsDebug:
self.m_pDB = await aiosqlite.connect(
str(g_sPlantPath.parent / "plant-test.db")
str(config.g_sPlantPath.parent / "plant-test.db")
)
else:
self.m_pDB = await aiosqlite.connect(str(g_sPlantPath))
self.m_pDB = await aiosqlite.connect(str(config.g_sPlantPath))
self.m_pDB.row_factory = aiosqlite.Row
return True
@@ -38,6 +40,9 @@ class CPlantManager:
logger.warning("初始化植物数据库失败", e=e)
return False
async def initDB(self):
self.m_bInitialized = True
@asynccontextmanager
async def _transaction(self):
await self.m_pDB.execute("BEGIN;")
@@ -254,7 +259,7 @@ class CPlantManager:
for plant in plants:
name = plant["name"]
phaseCount = await self.getPlantPhaseNumberByName(name)
saveDir = os.path.join(g_sResourcePath, "plant", name)
saveDir = os.path.join(config.g_sResourcePath, "plant", name)
begin = 0 if plant["general"] == 0 else 1
for idx in range(begin, phaseCount + 1):
@@ -265,14 +270,18 @@ class CPlantManager:
continue
url = f"{baseUrl}/{name}/{idx}.png"
if not await g_pRequestManager.download(url, saveDir, f"{idx}.png"):
if not await getRequestManager().download(
url, saveDir, f"{idx}.png"
):
success = False
iconName = "icon.png"
iconPath = os.path.join(saveDir, iconName)
if not os.path.exists(iconPath):
iconUrl = f"{baseUrl}/{name}/{iconName}"
if not await g_pRequestManager.download(iconUrl, saveDir, iconName):
if not await getRequestManager().download(
iconUrl, saveDir, iconName
):
success = False
return success
+6 -3
View File
@@ -1,11 +1,13 @@
import math
from ...utils.tool import g_pToolManager
from ...utils import getToolManager
from .database import CSqlManager
class CUserDB(CSqlManager):
def __init__(self):
super().__init__()
self.m_sTableName = "user"
self.currencies: list[str] = ["point", "vipPoint"]
async def initDB(self):
@@ -21,6 +23,7 @@ class CUserDB(CSqlManager):
}
await self.ensureTableSchema("user", userInfo)
self.setInitialized()
async def initUserInfo(self, uid: str, name: str) -> bool:
"""初始化用户信息
@@ -32,7 +35,7 @@ class CUserDB(CSqlManager):
Returns:
bool: 是否成功初始化用户信息
"""
nowStr = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d")
nowStr = getToolManager().dateTime().date().today().strftime("%Y-%m-%d")
result = await self.insert(
"user",
@@ -125,7 +128,7 @@ class CUserDB(CSqlManager):
Returns:
bool: 是否成功更新农场名称
"""
safeName = g_pToolManager.sanitize_username(name)
safeName = getToolManager().sanitize_username(name)
if safeName == "神秘农夫":
return "error"
+16 -12
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserItemDB(CSqlManager):
@classmethod
async def initDB(cls):
def __init__(self):
super().__init__()
self.m_sTableName = "userItem"
async def initDB(self):
userItem = {
"uid": "TEXT NOT NULL", # 用户Uid
"item": "TEXT NOT NULL", # 物品名称
@@ -13,7 +16,8 @@ class CUserItemDB(CSqlManager):
"PRIMARY KEY": "(uid, item)",
}
await cls.ensureTableSchema("userItem", userItem)
await self.ensureTableSchema("userItem", userItem)
self.setInitialized()
@classmethod
async def getUserItemByName(cls, uid: str, item: str) -> int | None:
@@ -29,7 +33,7 @@ class CUserItemDB(CSqlManager):
if not uid or not item:
return None
try:
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT count FROM userItem WHERE uid = ? AND item = ?", (uid, item)
) as cursor:
row = await cursor.fetchone()
@@ -51,7 +55,7 @@ class CUserItemDB(CSqlManager):
if not uid:
return {}
try:
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
"SELECT item, count FROM userItem WHERE uid = ?", (uid,)
)
rows = await cursor.fetchall()
@@ -75,7 +79,7 @@ class CUserItemDB(CSqlManager):
return False
try:
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item)
)
return True
@@ -100,11 +104,11 @@ class CUserItemDB(CSqlManager):
try:
async with cls._transaction():
if count <= 0:
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userItem WHERE uid = ? AND item = ?", (uid, item)
)
else:
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userItem SET count = ? WHERE uid = ? AND item = ?",
(count, uid, item),
)
@@ -129,7 +133,7 @@ class CUserItemDB(CSqlManager):
return False
try:
async with cls._transaction():
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT count FROM userItem WHERE uid = ? AND item = ?", (uid, item)
) as cursor:
row = await cursor.fetchone()
@@ -137,18 +141,18 @@ class CUserItemDB(CSqlManager):
if row:
newCount = row[0] + count
if newCount <= 0:
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userItem WHERE uid = ? AND item = ?",
(uid, item),
)
else:
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userItem SET count = ? WHERE uid = ? AND item = ?",
(newCount, uid, item),
)
else:
if count > 0:
await cls.m_pDB.execute(
await cls.getDB().execute(
"INSERT INTO userItem (uid, item, count) VALUES (?, ?, ?)",
(uid, item, count),
)
+17 -13
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserPlantDB(CSqlManager):
@classmethod
async def initDB(cls):
def __init__(self):
super().__init__()
self.m_sTableName = "userPlant"
async def initDB(self):
userPlant = {
"uid": "TEXT NOT NULL", # 用户Uid
"plant": "TEXT NOT NULL", # 作物名称
@@ -14,7 +17,8 @@ class CUserPlantDB(CSqlManager):
"PRIMARY KEY": "(uid, plant)",
}
await cls.ensureTableSchema("userPlant", userPlant)
await self.ensureTableSchema("userPlant", userPlant)
self.setInitialized()
@classmethod
async def addUserPlantByUid(cls, uid: str, plant: str, count: int = 1) -> bool:
@@ -31,7 +35,7 @@ class CUserPlantDB(CSqlManager):
try:
async with cls._transaction():
# 检查是否已存在该作物
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT count FROM userPlant WHERE uid = ? AND plant = ?",
(uid, plant),
) as cursor:
@@ -40,13 +44,13 @@ class CUserPlantDB(CSqlManager):
if row:
# 如果作物已存在,则更新数量
new_count = row[0] + count
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?",
(new_count, uid, plant),
)
else:
# 如果作物不存在,则插入新记录
await cls.m_pDB.execute(
await cls.getDB().execute(
"INSERT INTO userPlant (uid, plant, count) VALUES (?, ?, ?)",
(uid, plant, count),
)
@@ -65,7 +69,7 @@ class CUserPlantDB(CSqlManager):
Returns:
Dict[str, int]: 作物名称和数量
"""
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
"SELECT plant, count FROM userPlant WHERE uid=?", (uid,)
)
rows = await cursor.fetchall()
@@ -83,7 +87,7 @@ class CUserPlantDB(CSqlManager):
Optional[int]: 作物数量
"""
try:
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT count FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
) as cursor:
row = await cursor.fetchone()
@@ -104,7 +108,7 @@ class CUserPlantDB(CSqlManager):
bool: 是否存在
"""
try:
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT * FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
) as cursor:
row = await cursor.fetchone()
@@ -130,7 +134,7 @@ class CUserPlantDB(CSqlManager):
return await cls.deleteUserPlantByName(uid, plant)
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userPlant SET count = ? WHERE uid = ? AND plant = ?",
(count, uid, plant),
)
@@ -153,7 +157,7 @@ class CUserPlantDB(CSqlManager):
"""
try:
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userPlant SET isLock = ? WHERE uid = ? AND plant = ?",
(lock, uid, plant),
)
@@ -174,7 +178,7 @@ class CUserPlantDB(CSqlManager):
bool: 是否加锁
"""
try:
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT isLock FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
) as cursor:
row = await cursor.fetchone()
@@ -196,7 +200,7 @@ class CUserPlantDB(CSqlManager):
"""
try:
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userPlant WHERE uid = ? AND plant = ?", (uid, plant)
)
return True
+15 -11
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserPlantCountDB(CSqlManager):
@classmethod
async def initDB(cls):
def __init__(self):
super().__init__()
self.m_sTableName = "userPlantCount"
async def initDB(self):
userPlantCount = {
"uid": "TEXT NOT NULL", # 用户Uid
"plant": "TEXT NOT NULL", # 植物名称
@@ -13,7 +16,8 @@ class CUserPlantCountDB(CSqlManager):
"PRIMARY KEY": "(uid, plant)",
}
await cls.ensureTableSchema("userPlantCount", userPlantCount)
await self.ensureTableSchema("userPlantCount", userPlantCount)
self.setInitialized()
@classmethod
async def addUserPlantCountByUid(cls, uid: str, plant: str, count: int = 1) -> bool:
@@ -29,7 +33,7 @@ class CUserPlantCountDB(CSqlManager):
"""
try:
async with cls._transaction():
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT count FROM userPlantCount WHERE uid = ? AND plant = ?",
(uid, plant),
) as cursor:
@@ -37,19 +41,19 @@ class CUserPlantCountDB(CSqlManager):
if row:
newCount = row[0] + count
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?",
(newCount, uid, plant),
)
else:
newCount = count
await cls.m_pDB.execute(
await cls.getDB().execute(
"INSERT INTO userPlantCount (uid, plant, count) VALUES (?, ?, ?)",
(uid, plant, count),
)
if newCount <= 0:
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userPlantCount WHERE uid = ? AND plant = ?",
(uid, plant),
)
@@ -69,7 +73,7 @@ class CUserPlantCountDB(CSqlManager):
dict: 植物信息
"""
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
"SELECT plant, count FROM userPlantCount WHERE uid=?", (uid,)
)
rows = await cursor.fetchall()
@@ -86,7 +90,7 @@ class CUserPlantCountDB(CSqlManager):
Returns:
int: 收获次数
"""
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
"SELECT count FROM userPlantCount WHERE uid = ? AND plant = ?",
(uid, plant),
)
@@ -110,7 +114,7 @@ class CUserPlantCountDB(CSqlManager):
return await cls.deleteUserPlantCountByName(uid, plant)
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userPlantCount SET count = ? WHERE uid = ? AND plant = ?",
(count, uid, plant),
)
@@ -132,7 +136,7 @@ class CUserPlantCountDB(CSqlManager):
"""
try:
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userPlantCount WHERE uid = ? AND plant = ?",
(uid, plant),
)
+18 -14
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserSeedDB(CSqlManager):
@classmethod
async def initDB(cls):
def __init__(self):
super().__init__()
self.m_sTableName = "userSeed"
async def initDB(self):
userSeed = {
"uid": "TEXT NOT NULL", # 用户Uid
"seed": "TEXT NOT NULL", # 种子名称
@@ -13,7 +16,8 @@ class CUserSeedDB(CSqlManager):
"PRIMARY KEY": "(uid, seed)",
}
await cls.ensureTableSchema("userSeed", userSeed)
await self.ensureTableSchema("userSeed", userSeed)
self.setInitialized()
@classmethod
async def addUserSeedByUid(cls, uid: str, seed: str, count: int = 1) -> bool:
@@ -29,26 +33,26 @@ class CUserSeedDB(CSqlManager):
"""
try:
async with cls._transaction():
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
) as cursor:
row = await cursor.fetchone()
if row:
newCount = row[0] + count
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(newCount, uid, seed),
)
else:
newCount = count
await cls.m_pDB.execute(
await cls.getDB().execute(
"INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)",
(uid, seed, count),
)
if newCount <= 0:
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
)
return True
@@ -66,7 +70,7 @@ class CUserSeedDB(CSqlManager):
if existing is not None:
await cls._updateUserSeedByName(uid, seed, newCount)
else:
await cls.m_pDB.execute(
await cls.getDB().execute(
"INSERT INTO userSeed (uid, seed, count) VALUES (?, ?, ?)",
(uid, seed, newCount),
)
@@ -92,7 +96,7 @@ class CUserSeedDB(CSqlManager):
"""
try:
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT count FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
) as cursor:
row = await cursor.fetchone()
@@ -112,7 +116,7 @@ class CUserSeedDB(CSqlManager):
dict: 种子信息
"""
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
"SELECT seed, count FROM userSeed WHERE uid=?", (uid,)
)
rows = await cursor.fetchall()
@@ -135,7 +139,7 @@ class CUserSeedDB(CSqlManager):
return await cls.deleteUserSeedByName(uid, seed)
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(count, uid, seed),
)
@@ -161,7 +165,7 @@ class CUserSeedDB(CSqlManager):
return await cls.deleteUserSeedByName(uid, seed)
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"UPDATE userSeed SET count = ? WHERE uid = ? AND seed = ?",
(count, uid, seed),
)
@@ -183,7 +187,7 @@ class CUserSeedDB(CSqlManager):
"""
try:
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
)
return True
@@ -203,7 +207,7 @@ class CUserSeedDB(CSqlManager):
bool: 是否成功
"""
try:
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userSeed WHERE uid = ? AND seed = ?", (uid, seed)
)
return True
+26 -23
View File
@@ -5,16 +5,16 @@ import random
from zhenxun.services.log import logger
from zhenxun.utils._build_image import BuildImage
from ...utils.config import g_bIsDebug
from ...utils.json import g_pJsonManager
from ...utils.tool import g_pToolManager
from ..dbService import g_pDBService
from ...utils import config, getJsonManager, getToolManager
from .database import CSqlManager
class CUserSignDB(CSqlManager):
@classmethod
async def initDB(cls):
def __init__(self):
super().__init__()
self.m_sTableName = "userSign"
async def initDB(self):
# userSignLog 表结构,每条为一次签到事件
userSignLog = {
"uid": "TEXT NOT NULL", # 用户ID
@@ -38,8 +38,9 @@ class CUserSignDB(CSqlManager):
"updatedAt": "DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime'))", # 更新时间 # noqa: E501
}
await cls.ensureTableSchema("userSignLog", userSignLog)
await cls.ensureTableSchema("userSignSummary", userSignSummary)
await self.ensureTableSchema("userSignLog", userSignLog)
await self.ensureTableSchema("userSignSummary", userSignSummary)
self.setInitialized()
@classmethod
async def getUserSignRewardByDate(cls, uid: str, date: str) -> tuple[int, int]:
@@ -54,7 +55,7 @@ class CUserSignDB(CSqlManager):
"""
try:
async with cls._transaction():
async with cls.m_pDB.execute(
async with cls.getDB().execute(
"SELECT exp, point FROM userSignLog WHERE uid=? AND signDate=?",
(uid, date),
) as cursor:
@@ -85,7 +86,7 @@ class CUserSignDB(CSqlManager):
try:
sql = "SELECT COUNT(*) FROM userSignLog WHERE uid=? AND signDate LIKE ?"
param = f"{monthStr}-%"
async with cls.m_pDB.execute(sql, (uid, param)) as cursor:
async with cls.getDB().execute(sql, (uid, param)) as cursor:
row = await cursor.fetchone()
return row[0] if row else 0
except Exception as e:
@@ -105,7 +106,7 @@ class CUserSignDB(CSqlManager):
"""
try:
sql = "SELECT 1 FROM userSignLog WHERE uid=? AND signDate=? LIMIT 1"
async with cls.m_pDB.execute(sql, (uid, signDate)) as cursor:
async with cls.getDB().execute(sql, (uid, signDate)) as cursor:
row = await cursor.fetchone()
return row is not None
except Exception as e:
@@ -124,19 +125,21 @@ class CUserSignDB(CSqlManager):
int: 0: 签到失败 1: 签到成功 2: 重复签到
"""
try:
player = await g_pToolManager.getPlayerByUid(uid)
player = await getToolManager().getPlayerByUid(uid)
if not player:
return 0
if not signDate:
signDate = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d")
signDate = (
getToolManager().dateTime().date().today().strftime("%Y-%m-%d")
)
if await cls.hasSigned(uid, signDate):
return 2
todayStr = g_pToolManager.dateTime().date().today().strftime("%Y-%m-%d")
todayStr = getToolManager().dateTime().date().today().strftime("%Y-%m-%d")
isSupplement = 0 if signDate == todayStr else 1
sign = await g_pJsonManager.getSign()
sign = await getJsonManager().getSign()
expMax, expMin, pointMax, pointMin = [
sign.get(key, default)
@@ -153,12 +156,12 @@ class CUserSignDB(CSqlManager):
vipPoint = 0
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"INSERT INTO userSignLog (uid, signDate, isSupplement, exp, point) VALUES (?, ?, ?, ?, ?)",
(uid, signDate, isSupplement, exp, point),
)
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
"SELECT * FROM userSignSummary WHERE uid=?", (uid,)
)
row = await cursor.fetchone()
@@ -171,7 +174,7 @@ class CUserSignDB(CSqlManager):
else 1
)
prevDate = (
g_pToolManager.dateTime().strptime(signDate, "%Y-%m-%d")
getToolManager().dateTime().strptime(signDate, "%Y-%m-%d")
- timedelta(days=1)
).strftime("%Y-%m-%d")
continuousDays = (
@@ -184,7 +187,7 @@ class CUserSignDB(CSqlManager):
if isSupplement
else row["supplementCount"]
)
await cls.m_pDB.execute(
await cls.getDB().execute(
"""
UPDATE userSignSummary
SET totalSignDays=totalSignDays+1,
@@ -206,7 +209,7 @@ class CUserSignDB(CSqlManager):
)
else:
monthSignDays = 1
await cls.m_pDB.execute(
await cls.getDB().execute(
"""
INSERT INTO userSignSummary
(uid, totalSignDays, currentMonth, monthSignDays, lastSignDate, continuousDays, supplementCount)
@@ -233,9 +236,9 @@ class CUserSignDB(CSqlManager):
plant = reward.get("plant", {})
if plant:
for key, value in plant.items():
await g_pDBService.userSeed.addUserSeedByUid(uid, key, value)
await cls.getUserSeedManager().addUserSeedByUid(uid, key, value)
if g_bIsDebug:
if config.g_bIsDebug:
exp += 9999
# 向数据库更新
@@ -268,7 +271,7 @@ class CUserSignDB(CSqlManager):
monthStr = f"{year:04d}-{month:02d}"
try:
sql = "SELECT signDate FROM userSignLog WHERE uid=? AND signDate LIKE ?"
async with cls.m_pDB.execute(sql, (uid, f"{monthStr}-%")) as cursor:
async with cls.getDB().execute(sql, (uid, f"{monthStr}-%")) as cursor:
rows = await cursor.fetchall()
signedDays = {int(r[0][-2:]) for r in rows if r[0][-2:].isdigit()}
except Exception as e:
+33 -31
View File
@@ -3,15 +3,16 @@ import re
from zhenxun.services.log import logger
from ...utils.config import g_bIsDebug
from ...utils.tool import g_pToolManager
from ..dbService import g_pDBService
from ...utils import config, getToolManager
from .database import CSqlManager
class CUserSoilDB(CSqlManager):
@classmethod
async def initDB(cls):
def __init__(self):
super().__init__()
self.m_sTableName = "userSoil"
async def initDB(self):
userSoil = {
"uid": "TEXT NOT NULL",
"soilIndex": "INTEGER NOT NULL", # 地块索引从1开始
@@ -29,7 +30,8 @@ class CUserSoilDB(CSqlManager):
"PRIMARY KEY": "(uid, soilIndex)",
}
await cls.ensureTableSchema("userSoil", userSoil)
await self.ensureTableSchema("userSoil", userSoil)
self.setInitialized()
@classmethod
async def nextPhase(cls, uid: str, soilIndex: int):
@@ -38,7 +40,7 @@ class CUserSoilDB(CSqlManager):
Args:
soilIndex (int): 地块索引 从1开始
"""
if not g_bIsDebug:
if not config.g_bIsDebug:
return
soilInfo = await cls.getUserSoil(uid, soilIndex)
@@ -46,13 +48,15 @@ class CUserSoilDB(CSqlManager):
if not soilInfo:
return
plantInfo = await g_pDBService.plant.getPlantByName(soilInfo["plantName"])
plantInfo = await cls.getPlantManager().getPlantByName(soilInfo["plantName"])
if not plantInfo:
return
currentTime = g_pToolManager.dateTime().now().timestamp()
phaseList = await g_pDBService.plant.getPlantPhaseByName(soilInfo["plantName"])
currentTime = getToolManager().dateTime().now().timestamp()
phaseList = await cls.getPlantManager().getPlantPhaseByName(
soilInfo["plantName"]
)
if currentTime >= soilInfo["matureTime"]:
return
@@ -88,11 +92,11 @@ class CUserSoilDB(CSqlManager):
if not plantName:
return
plantInfo = await g_pDBService.plant.getPlantByName(plantName)
plantInfo = await cls.getPlantManager().getPlantByName(plantName)
if not plantInfo:
return
currentTime = int(g_pToolManager.dateTime().now().timestamp())
currentTime = int(getToolManager().dateTime().now().timestamp())
# 如果当前时间已经超过或等于成熟时间,则作物已成熟或可收获
if currentTime >= soilInfo["matureTime"]:
return
@@ -110,7 +114,7 @@ class CUserSoilDB(CSqlManager):
Returns:
dict: 包含字段名-值的字典; 若无数据则返回空字典
"""
cursor = await cls.m_pDB.execute("SELECT * FROM soil WHERE uid = ?", (uid,))
cursor = await cls.getDB().execute("SELECT * FROM soil WHERE uid = ?", (uid,))
row = await cursor.fetchone()
if not row:
@@ -129,7 +133,7 @@ class CUserSoilDB(CSqlManager):
None
"""
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"""
INSERT INTO userSoil
(uid, soilIndex, plantName, plantTime, matureTime,
@@ -164,7 +168,7 @@ class CUserSoilDB(CSqlManager):
Returns:
None
"""
await cls.m_pDB.execute(
await cls.getDB().execute(
"""
INSERT INTO userSoil
(uid, soilIndex, plantName, plantTime, matureTime,
@@ -201,7 +205,7 @@ class CUserSoilDB(CSqlManager):
dict: 记录存在返回字段-值字典,否则返回 None
"""
async with cls._transaction():
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
"SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?",
(uid, soilIndex),
)
@@ -222,7 +226,7 @@ class CUserSoilDB(CSqlManager):
Returns:
dict | None: 记录存在返回字段-值字典,否则返回 None
"""
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
"SELECT * FROM userSoil WHERE uid = ? AND soilIndex = ?",
(uid, soilIndex),
)
@@ -244,7 +248,7 @@ class CUserSoilDB(CSqlManager):
int: 符合条件的土地数量
"""
async with cls._transaction():
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
"SELECT COUNT(*) FROM userSoil WHERE uid = ? AND soilLevel = ?",
(uid, soilLevel),
)
@@ -265,7 +269,7 @@ class CUserSoilDB(CSqlManager):
None
"""
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?",
(value, uid, soilIndex),
)
@@ -283,7 +287,7 @@ class CUserSoilDB(CSqlManager):
Returns:
None
"""
await cls.m_pDB.execute(
await cls.getDB().execute(
f"UPDATE userSoil SET {field} = ? WHERE uid = ? AND soilIndex = ?",
(value, uid, soilIndex),
)
@@ -331,7 +335,7 @@ class CUserSoilDB(CSqlManager):
try:
async with cls._transaction():
await cls.m_pDB.execute(sql, tuple(values))
await cls.getDB().execute(sql, tuple(values))
return True
except Exception as e:
logger.error(f"批量更新土地字段失败: {e}")
@@ -349,7 +353,7 @@ class CUserSoilDB(CSqlManager):
None
"""
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex)
)
@@ -364,7 +368,7 @@ class CUserSoilDB(CSqlManager):
Returns:
None
"""
await cls.m_pDB.execute(
await cls.getDB().execute(
"DELETE FROM userSoil WHERE uid = ? AND soilIndex = ?", (uid, soilIndex)
)
@@ -386,12 +390,12 @@ class CUserSoilDB(CSqlManager):
return False
# 获取植物配置""" """
plantCfg = await g_pDBService.plant.getPlantByName(plantName)
plantCfg = await cls.getPlantManager().getPlantByName(plantName)
if not plantCfg:
logger.error(f"未知植物: {plantName}")
return False
nowTs = int(g_pToolManager.dateTime().now().timestamp())
nowTs = int(getToolManager().dateTime().now().timestamp())
time = int(plantCfg.get("time", 0))
percent = await cls.getSoilLevelTime(soilInfo.get("soilLevel", 0))
@@ -413,11 +417,9 @@ class CUserSoilDB(CSqlManager):
base_name = plantName[len(m.group(0)) :]
# 只有当存在一星升级配置时才尝试按收获次数升级
if await g_pDBService.plant.existsPlant("一星" + base_name):
harvestCounts = (
await g_pDBService.userPlantCount.getUserPlantCountByPlantName(
uid, base_name
)
if await cls.getPlantManager().existsPlant("一星" + base_name):
harvestCounts = await cls.getUserPlantCountManager().getUserPlantCountByPlantName(
uid, base_name
)
# 根据阈值设定最高星级(避免重复拼接)
prefix = ""
@@ -455,7 +457,7 @@ class CUserSoilDB(CSqlManager):
@classmethod
async def getUserSoilStatus(cls, uid: str, soilIndex: int) -> str:
status = []
soilInfo = await g_pDBService.userSoil.getUserSoil(uid, soilIndex)
soilInfo = await cls.getUserSoilManager().getUserSoil(uid, soilIndex)
if not soilInfo:
return ""
+15 -11
View File
@@ -4,8 +4,11 @@ from .database import CSqlManager
class CUserStealDB(CSqlManager):
@classmethod
async def initDB(cls):
def __init__(self):
super().__init__()
self.m_sTableName = "userSteal"
async def initDB(self):
userSteal = {
"uid": "TEXT NOT NULL", # 被偷用户Uid
"soilIndex": "INTEGER NOT NULL", # 被偷的地块索引 从1开始
@@ -14,7 +17,8 @@ class CUserStealDB(CSqlManager):
"stealTime": "INTEGER NOT NULL", # 被偷时间
"PRIMARY KEY": "(uid, soilIndex, stealerUid)",
}
await cls.ensureTableSchema("userSteal", userSteal)
await self.ensureTableSchema("userSteal", userSteal)
self.setInitialized()
@classmethod
async def addStealRecord(
@@ -34,7 +38,7 @@ class CUserStealDB(CSqlManager):
"""
try:
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
'INSERT INTO "userSteal"(uid, soilIndex, stealerUid, stealCount, stealTime) VALUES(?, ?, ?, ?, ?);',
(uid, soilIndex, stealerUid, stealCount, stealTime),
)
@@ -55,7 +59,7 @@ class CUserStealDB(CSqlManager):
"""
try:
async with cls._transaction():
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
'SELECT soilIndex, stealerUid, stealCount, stealTime FROM "userSteal" WHERE uid=?;',
(uid,),
)
@@ -83,7 +87,7 @@ class CUserStealDB(CSqlManager):
"""
try:
async with cls._transaction():
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
'SELECT stealerUid, stealCount, stealTime FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex),
)
@@ -115,7 +119,7 @@ class CUserStealDB(CSqlManager):
"""
try:
async with cls._transaction():
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
'SELECT SUM(stealCount) FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex),
)
@@ -138,7 +142,7 @@ class CUserStealDB(CSqlManager):
"""
try:
async with cls._transaction():
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
'SELECT COUNT(DISTINCT stealerUid) FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex),
)
@@ -162,7 +166,7 @@ class CUserStealDB(CSqlManager):
"""
try:
async with cls._transaction():
cursor = await cls.m_pDB.execute(
cursor = await cls.getDB().execute(
'SELECT 1 FROM "userSteal" WHERE uid=? AND soilIndex=? AND stealerUid=? LIMIT 1;',
(uid, soilIndex, stealerUid),
)
@@ -190,7 +194,7 @@ class CUserStealDB(CSqlManager):
"""
try:
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
'UPDATE "userSteal" SET stealCount=?, stealTime=? WHERE uid=? AND soilIndex=? AND stealerUid=?;',
(stealCount, stealTime, uid, soilIndex, stealerUid),
)
@@ -212,7 +216,7 @@ class CUserStealDB(CSqlManager):
"""
try:
async with cls._transaction():
await cls.m_pDB.execute(
await cls.getDB().execute(
'DELETE FROM "userSteal" WHERE uid=? AND soilIndex=?;',
(uid, soilIndex),
)