1186 lines
40 KiB
Python
1186 lines
40 KiB
Python
"""
|
||
数据存储系统模块
|
||
负责持久化存储用户数据和游戏状态
|
||
"""
|
||
|
||
import time
|
||
import threading
|
||
import json
|
||
import os
|
||
import sqlite3
|
||
from typing import Dict, Any, List, Optional
|
||
|
||
class StorageManager:
|
||
"""
|
||
数据存储管理器
|
||
负责持久化存储用户数据和游戏状态
|
||
"""
|
||
|
||
def __init__(self, plugin):
|
||
"""
|
||
初始化数据存储管理器
|
||
|
||
Args:
|
||
plugin: 服务器架构插件实例
|
||
"""
|
||
self.plugin = plugin
|
||
self.enabled = False
|
||
self.initialized = False
|
||
|
||
# 存储配置
|
||
self.storage_config = {
|
||
"database_path": "/home/hello/EG/plugins/user/server_architecture/data/server_database.db",
|
||
"enable_caching": True,
|
||
"cache_size": 1000,
|
||
"enable_compression": True,
|
||
"backup_interval": 3600, # 1小时
|
||
"enable_auto_backup": True,
|
||
"max_backups": 10,
|
||
"enable_encryption": False,
|
||
"enable_async_writes": True
|
||
}
|
||
|
||
# 数据库连接
|
||
self.db_connection = None
|
||
|
||
# 缓存管理
|
||
self.data_cache = {}
|
||
self.cache_lock = threading.RLock()
|
||
|
||
# 存储统计
|
||
self.storage_stats = {
|
||
"reads": 0,
|
||
"writes": 0,
|
||
"cache_hits": 0,
|
||
"cache_misses": 0,
|
||
"backups_created": 0,
|
||
"errors": 0,
|
||
"bytes_read": 0,
|
||
"bytes_written": 0
|
||
}
|
||
|
||
# 异步写入队列
|
||
self.write_queue = []
|
||
self.write_queue_lock = threading.RLock()
|
||
self.write_thread = None
|
||
self.write_thread_running = False
|
||
|
||
# 回调函数
|
||
self.storage_callbacks = {
|
||
"data_saved": [],
|
||
"data_loaded": [],
|
||
"backup_created": [],
|
||
"storage_error": []
|
||
}
|
||
|
||
# 时间戳记录
|
||
self.last_backup = 0.0
|
||
self.last_write = 0.0
|
||
self.last_read = 0.0
|
||
|
||
print("✓ 数据存储管理器已创建")
|
||
|
||
def initialize(self) -> bool:
|
||
"""
|
||
初始化数据存储管理器
|
||
|
||
Returns:
|
||
是否初始化成功
|
||
"""
|
||
try:
|
||
print("正在初始化数据存储管理器...")
|
||
|
||
# 创建数据目录
|
||
data_dir = os.path.dirname(self.storage_config["database_path"])
|
||
if not os.path.exists(data_dir):
|
||
os.makedirs(data_dir)
|
||
|
||
# 初始化数据库
|
||
self._initialize_database()
|
||
|
||
# 启动异步写入线程
|
||
if self.storage_config["enable_async_writes"]:
|
||
self._start_write_thread()
|
||
|
||
self.initialized = True
|
||
print("✓ 数据存储管理器初始化完成")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 数据存储管理器初始化失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def _initialize_database(self):
|
||
"""初始化数据库"""
|
||
try:
|
||
# 连接到SQLite数据库
|
||
self.db_connection = sqlite3.connect(
|
||
self.storage_config["database_path"],
|
||
check_same_thread=False
|
||
)
|
||
|
||
# 创建表
|
||
cursor = self.db_connection.cursor()
|
||
|
||
# 用户表
|
||
cursor.execute('''
|
||
CREATE TABLE IF NOT EXISTS users (
|
||
user_id TEXT PRIMARY KEY,
|
||
username TEXT UNIQUE NOT NULL,
|
||
email TEXT,
|
||
password_hash TEXT,
|
||
created_time REAL,
|
||
last_login REAL,
|
||
user_data TEXT
|
||
)
|
||
''')
|
||
|
||
# 房间表
|
||
cursor.execute('''
|
||
CREATE TABLE IF NOT EXISTS rooms (
|
||
room_id TEXT PRIMARY KEY,
|
||
room_name TEXT NOT NULL,
|
||
host_user_id TEXT,
|
||
created_time REAL,
|
||
room_settings TEXT,
|
||
room_state TEXT
|
||
)
|
||
''')
|
||
|
||
# 游戏状态表
|
||
cursor.execute('''
|
||
CREATE TABLE IF NOT EXISTS game_states (
|
||
state_id TEXT PRIMARY KEY,
|
||
room_id TEXT,
|
||
state_data TEXT,
|
||
timestamp REAL,
|
||
FOREIGN KEY (room_id) REFERENCES rooms (room_id)
|
||
)
|
||
''')
|
||
|
||
# 用户房间关系表
|
||
cursor.execute('''
|
||
CREATE TABLE IF NOT EXISTS user_rooms (
|
||
user_id TEXT,
|
||
room_id TEXT,
|
||
join_time REAL,
|
||
PRIMARY KEY (user_id, room_id),
|
||
FOREIGN KEY (user_id) REFERENCES users (user_id),
|
||
FOREIGN KEY (room_id) REFERENCES rooms (room_id)
|
||
)
|
||
''')
|
||
|
||
# 系统配置表
|
||
cursor.execute('''
|
||
CREATE TABLE IF NOT EXISTS system_config (
|
||
config_key TEXT PRIMARY KEY,
|
||
config_value TEXT,
|
||
updated_time REAL
|
||
)
|
||
''')
|
||
|
||
# 日志表
|
||
cursor.execute('''
|
||
CREATE TABLE IF NOT EXISTS logs (
|
||
log_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
log_level TEXT,
|
||
log_message TEXT,
|
||
timestamp REAL,
|
||
user_id TEXT
|
||
)
|
||
''')
|
||
|
||
# 提交更改
|
||
self.db_connection.commit()
|
||
|
||
print("✓ 数据库初始化完成")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 数据库初始化失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
raise
|
||
|
||
def _start_write_thread(self):
|
||
"""启动异步写入线程"""
|
||
try:
|
||
self.write_thread_running = True
|
||
self.write_thread = threading.Thread(target=self._write_thread_loop, daemon=True)
|
||
self.write_thread.start()
|
||
print("✓ 异步写入线程已启动")
|
||
except Exception as e:
|
||
print(f"✗ 异步写入线程启动失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
|
||
def _write_thread_loop(self):
|
||
"""异步写入线程循环"""
|
||
try:
|
||
while self.write_thread_running:
|
||
try:
|
||
# 处理写入队列
|
||
self._process_write_queue()
|
||
|
||
# 短暂休眠
|
||
time.sleep(0.1)
|
||
|
||
except Exception as e:
|
||
print(f"✗ 异步写入循环错误: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
time.sleep(1.0) # 出错时延长休眠
|
||
|
||
except Exception as e:
|
||
print(f"✗ 异步写入线程失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
|
||
def _process_write_queue(self):
|
||
"""处理写入队列"""
|
||
try:
|
||
if not self.write_queue:
|
||
return
|
||
|
||
with self.write_queue_lock:
|
||
write_items = self.write_queue[:]
|
||
self.write_queue.clear()
|
||
|
||
# 执行写入操作
|
||
for item in write_items:
|
||
try:
|
||
operation = item["operation"]
|
||
if operation == "save_user":
|
||
self._save_user_internal(item["user_id"], item["user_data"])
|
||
elif operation == "save_room":
|
||
self._save_room_internal(item["room_id"], item["room_data"])
|
||
elif operation == "save_game_state":
|
||
self._save_game_state_internal(item["state_id"], item["state_data"])
|
||
|
||
except Exception as e:
|
||
print(f"✗ 队列写入操作失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
|
||
except Exception as e:
|
||
print(f"✗ 写入队列处理失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
|
||
def enable(self) -> bool:
|
||
"""
|
||
启用数据存储管理器
|
||
|
||
Returns:
|
||
是否启用成功
|
||
"""
|
||
try:
|
||
if not self.initialized:
|
||
print("✗ 数据存储管理器未初始化")
|
||
return False
|
||
|
||
self.enabled = True
|
||
print("✓ 数据存储管理器已启用")
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 数据存储管理器启用失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
import traceback
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def disable(self):
|
||
"""禁用数据存储管理器"""
|
||
try:
|
||
self.enabled = False
|
||
|
||
# 停止异步写入线程
|
||
if self.write_thread_running:
|
||
self.write_thread_running = False
|
||
if self.write_thread and self.write_thread.is_alive():
|
||
self.write_thread.join(timeout=5.0)
|
||
|
||
# 处理剩余的写入队列
|
||
self._process_write_queue()
|
||
|
||
# 关闭数据库连接
|
||
if self.db_connection:
|
||
self.db_connection.close()
|
||
self.db_connection = None
|
||
|
||
print("✓ 数据存储管理器已禁用")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 数据存储管理器禁用失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def finalize(self):
|
||
"""清理数据存储管理器资源"""
|
||
try:
|
||
# 禁用管理器
|
||
if self.enabled:
|
||
self.disable()
|
||
|
||
# 清理缓存和回调
|
||
with self.cache_lock:
|
||
self.data_cache.clear()
|
||
self.storage_callbacks.clear()
|
||
|
||
self.initialized = False
|
||
print("✓ 数据存储管理器资源已清理")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 数据存储管理器资源清理失败: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def update(self, dt: float):
|
||
"""
|
||
更新数据存储管理器状态
|
||
|
||
Args:
|
||
dt: 时间增量(秒)
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return
|
||
|
||
current_time = time.time()
|
||
|
||
# 定期创建备份
|
||
if (self.storage_config["enable_auto_backup"] and
|
||
current_time - self.last_backup > self.storage_config["backup_interval"]):
|
||
self._create_backup()
|
||
self.last_backup = current_time
|
||
|
||
except Exception as e:
|
||
print(f"✗ 数据存储管理器更新失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
def _create_backup(self):
|
||
"""创建数据库备份"""
|
||
try:
|
||
if not self.db_connection:
|
||
return
|
||
|
||
# 创建备份文件名
|
||
backup_dir = os.path.dirname(self.storage_config["database_path"])
|
||
backup_filename = f"backup_{int(time.time())}.db"
|
||
backup_path = os.path.join(backup_dir, backup_filename)
|
||
|
||
# 复制数据库文件
|
||
import shutil
|
||
shutil.copy2(self.storage_config["database_path"], backup_path)
|
||
|
||
self.storage_stats["backups_created"] += 1
|
||
|
||
# 清理旧备份
|
||
self._cleanup_old_backups()
|
||
|
||
# 触发备份创建回调
|
||
self._trigger_storage_callback("backup_created", {
|
||
"backup_path": backup_path,
|
||
"timestamp": time.time()
|
||
})
|
||
|
||
print(f"✓ 数据库备份已创建: {backup_path}")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 数据库备份创建失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
|
||
def _cleanup_old_backups(self):
|
||
"""清理旧备份"""
|
||
try:
|
||
backup_dir = os.path.dirname(self.storage_config["database_path"])
|
||
backup_files = []
|
||
|
||
# 查找备份文件
|
||
for filename in os.listdir(backup_dir):
|
||
if filename.startswith("backup_") and filename.endswith(".db"):
|
||
filepath = os.path.join(backup_dir, filename)
|
||
backup_files.append((filepath, os.path.getmtime(filepath)))
|
||
|
||
# 按修改时间排序
|
||
backup_files.sort(key=lambda x: x[1], reverse=True)
|
||
|
||
# 删除多余的备份
|
||
for filepath, _ in backup_files[self.storage_config["max_backups"]:]:
|
||
try:
|
||
os.remove(filepath)
|
||
print(f"✓ 旧备份已删除: {filepath}")
|
||
except Exception as e:
|
||
print(f"✗ 旧备份删除失败: {filepath} - {e}")
|
||
|
||
except Exception as e:
|
||
print(f"✗ 旧备份清理失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
|
||
def save_user(self, user_id: str, user_data: Dict[str, Any]) -> bool:
|
||
"""
|
||
保存用户数据
|
||
|
||
Args:
|
||
user_id: 用户ID
|
||
user_data: 用户数据
|
||
|
||
Returns:
|
||
是否保存成功
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return False
|
||
|
||
# 更新缓存
|
||
if self.storage_config["enable_caching"]:
|
||
with self.cache_lock:
|
||
self.data_cache[f"user_{user_id}"] = {
|
||
"data": user_data.copy(),
|
||
"timestamp": time.time()
|
||
}
|
||
|
||
# 保持缓存大小
|
||
if len(self.data_cache) > self.storage_config["cache_size"]:
|
||
# 移除最旧的缓存项
|
||
oldest_key = min(self.data_cache.keys(),
|
||
key=lambda k: self.data_cache[k]["timestamp"])
|
||
del self.data_cache[oldest_key]
|
||
|
||
# 异步写入
|
||
if self.storage_config["enable_async_writes"]:
|
||
with self.write_queue_lock:
|
||
self.write_queue.append({
|
||
"operation": "save_user",
|
||
"user_id": user_id,
|
||
"user_data": user_data
|
||
})
|
||
return True
|
||
else:
|
||
# 同步写入
|
||
return self._save_user_internal(user_id, user_data)
|
||
|
||
except Exception as e:
|
||
print(f"✗ 保存用户数据失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def _save_user_internal(self, user_id: str, user_data: Dict[str, Any]) -> bool:
|
||
"""
|
||
内部保存用户数据
|
||
|
||
Args:
|
||
user_id: 用户ID
|
||
user_data: 用户数据
|
||
|
||
Returns:
|
||
是否保存成功
|
||
"""
|
||
try:
|
||
if not self.db_connection:
|
||
return False
|
||
|
||
cursor = self.db_connection.cursor()
|
||
|
||
# 序列化用户数据
|
||
user_data_json = json.dumps(user_data, ensure_ascii=False)
|
||
|
||
# 插入或更新用户数据
|
||
cursor.execute('''
|
||
INSERT OR REPLACE INTO users
|
||
(user_id, username, email, password_hash, created_time, last_login, user_data)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||
''', (
|
||
user_id,
|
||
user_data.get("username", ""),
|
||
user_data.get("email", ""),
|
||
user_data.get("password_hash", ""),
|
||
user_data.get("created_time", time.time()),
|
||
user_data.get("last_login", 0),
|
||
user_data_json
|
||
))
|
||
|
||
self.db_connection.commit()
|
||
self.storage_stats["writes"] += 1
|
||
self.last_write = time.time()
|
||
|
||
# 触发数据保存回调
|
||
self._trigger_storage_callback("data_saved", {
|
||
"data_type": "user",
|
||
"user_id": user_id,
|
||
"timestamp": self.last_write
|
||
})
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 内部保存用户数据失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def load_user(self, user_id: str) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
加载用户数据
|
||
|
||
Args:
|
||
user_id: 用户ID
|
||
|
||
Returns:
|
||
用户数据或None
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return None
|
||
|
||
# 检查缓存
|
||
if self.storage_config["enable_caching"]:
|
||
cache_key = f"user_{user_id}"
|
||
with self.cache_lock:
|
||
if cache_key in self.data_cache:
|
||
self.storage_stats["cache_hits"] += 1
|
||
cached_data = self.data_cache[cache_key]
|
||
return cached_data["data"].copy()
|
||
else:
|
||
self.storage_stats["cache_misses"] += 1
|
||
|
||
# 从数据库加载
|
||
if not self.db_connection:
|
||
return None
|
||
|
||
cursor = self.db_connection.cursor()
|
||
cursor.execute('SELECT user_data FROM users WHERE user_id = ?', (user_id,))
|
||
result = cursor.fetchone()
|
||
|
||
if result:
|
||
user_data = json.loads(result[0])
|
||
self.storage_stats["reads"] += 1
|
||
self.last_read = time.time()
|
||
|
||
# 更新缓存
|
||
if self.storage_config["enable_caching"]:
|
||
with self.cache_lock:
|
||
self.data_cache[f"user_{user_id}"] = {
|
||
"data": user_data,
|
||
"timestamp": self.last_read
|
||
}
|
||
|
||
# 触发数据加载回调
|
||
self._trigger_storage_callback("data_loaded", {
|
||
"data_type": "user",
|
||
"user_id": user_id,
|
||
"timestamp": self.last_read
|
||
})
|
||
|
||
return user_data
|
||
else:
|
||
return None
|
||
|
||
except Exception as e:
|
||
print(f"✗ 加载用户数据失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return None
|
||
|
||
def save_room(self, room_id: str, room_data: Dict[str, Any]) -> bool:
|
||
"""
|
||
保存房间数据
|
||
|
||
Args:
|
||
room_id: 房间ID
|
||
room_data: 房间数据
|
||
|
||
Returns:
|
||
是否保存成功
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return False
|
||
|
||
# 更新缓存
|
||
if self.storage_config["enable_caching"]:
|
||
with self.cache_lock:
|
||
self.data_cache[f"room_{room_id}"] = {
|
||
"data": room_data.copy(),
|
||
"timestamp": time.time()
|
||
}
|
||
|
||
# 异步写入
|
||
if self.storage_config["enable_async_writes"]:
|
||
with self.write_queue_lock:
|
||
self.write_queue.append({
|
||
"operation": "save_room",
|
||
"room_id": room_id,
|
||
"room_data": room_data
|
||
})
|
||
return True
|
||
else:
|
||
# 同步写入
|
||
return self._save_room_internal(room_id, room_data)
|
||
|
||
except Exception as e:
|
||
print(f"✗ 保存房间数据失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def _save_room_internal(self, room_id: str, room_data: Dict[str, Any]) -> bool:
|
||
"""
|
||
内部保存房间数据
|
||
|
||
Args:
|
||
room_id: 房间ID
|
||
room_data: 房间数据
|
||
|
||
Returns:
|
||
是否保存成功
|
||
"""
|
||
try:
|
||
if not self.db_connection:
|
||
return False
|
||
|
||
cursor = self.db_connection.cursor()
|
||
|
||
# 序列化房间数据
|
||
room_settings_json = json.dumps(room_data.get("settings", {}), ensure_ascii=False)
|
||
room_state_json = json.dumps(room_data.get("state", {}), ensure_ascii=False)
|
||
|
||
# 插入或更新房间数据
|
||
cursor.execute('''
|
||
INSERT OR REPLACE INTO rooms
|
||
(room_id, room_name, host_user_id, created_time, room_settings, room_state)
|
||
VALUES (?, ?, ?, ?, ?, ?)
|
||
''', (
|
||
room_id,
|
||
room_data.get("room_name", ""),
|
||
room_data.get("host_user_id"),
|
||
room_data.get("created_time", time.time()),
|
||
room_settings_json,
|
||
room_state_json
|
||
))
|
||
|
||
self.db_connection.commit()
|
||
self.storage_stats["writes"] += 1
|
||
self.last_write = time.time()
|
||
|
||
# 触发数据保存回调
|
||
self._trigger_storage_callback("data_saved", {
|
||
"data_type": "room",
|
||
"room_id": room_id,
|
||
"timestamp": self.last_write
|
||
})
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 内部保存房间数据失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def load_room(self, room_id: str) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
加载房间数据
|
||
|
||
Args:
|
||
room_id: 房间ID
|
||
|
||
Returns:
|
||
房间数据或None
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return None
|
||
|
||
# 检查缓存
|
||
if self.storage_config["enable_caching"]:
|
||
cache_key = f"room_{room_id}"
|
||
with self.cache_lock:
|
||
if cache_key in self.data_cache:
|
||
self.storage_stats["cache_hits"] += 1
|
||
cached_data = self.data_cache[cache_key]
|
||
return cached_data["data"].copy()
|
||
else:
|
||
self.storage_stats["cache_misses"] += 1
|
||
|
||
# 从数据库加载
|
||
if not self.db_connection:
|
||
return None
|
||
|
||
cursor = self.db_connection.cursor()
|
||
cursor.execute('''
|
||
SELECT room_name, host_user_id, created_time, room_settings, room_state
|
||
FROM rooms WHERE room_id = ?
|
||
''', (room_id,))
|
||
result = cursor.fetchone()
|
||
|
||
if result:
|
||
room_data = {
|
||
"room_id": room_id,
|
||
"room_name": result[0],
|
||
"host_user_id": result[1],
|
||
"created_time": result[2],
|
||
"settings": json.loads(result[3]) if result[3] else {},
|
||
"state": json.loads(result[4]) if result[4] else {}
|
||
}
|
||
|
||
self.storage_stats["reads"] += 1
|
||
self.last_read = time.time()
|
||
|
||
# 更新缓存
|
||
if self.storage_config["enable_caching"]:
|
||
with self.cache_lock:
|
||
self.data_cache[f"room_{room_id}"] = {
|
||
"data": room_data,
|
||
"timestamp": self.last_read
|
||
}
|
||
|
||
# 触发数据加载回调
|
||
self._trigger_storage_callback("data_loaded", {
|
||
"data_type": "room",
|
||
"room_id": room_id,
|
||
"timestamp": self.last_read
|
||
})
|
||
|
||
return room_data
|
||
else:
|
||
return None
|
||
|
||
except Exception as e:
|
||
print(f"✗ 加载房间数据失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return None
|
||
|
||
def save_game_state(self, state_id: str, state_data: Dict[str, Any]) -> bool:
|
||
"""
|
||
保存游戏状态数据
|
||
|
||
Args:
|
||
state_id: 状态ID
|
||
state_data: 游戏状态数据
|
||
|
||
Returns:
|
||
是否保存成功
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return False
|
||
|
||
# 异步写入
|
||
if self.storage_config["enable_async_writes"]:
|
||
with self.write_queue_lock:
|
||
self.write_queue.append({
|
||
"operation": "save_game_state",
|
||
"state_id": state_id,
|
||
"state_data": state_data
|
||
})
|
||
return True
|
||
else:
|
||
# 同步写入
|
||
return self._save_game_state_internal(state_id, state_data)
|
||
|
||
except Exception as e:
|
||
print(f"✗ 保存游戏状态数据失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def _save_game_state_internal(self, state_id: str, state_data: Dict[str, Any]) -> bool:
|
||
"""
|
||
内部保存游戏状态数据
|
||
|
||
Args:
|
||
state_id: 状态ID
|
||
state_data: 游戏状态数据
|
||
|
||
Returns:
|
||
是否保存成功
|
||
"""
|
||
try:
|
||
if not self.db_connection:
|
||
return False
|
||
|
||
cursor = self.db_connection.cursor()
|
||
|
||
# 序列化游戏状态数据
|
||
state_data_json = json.dumps(state_data, ensure_ascii=False)
|
||
|
||
# 插入或更新游戏状态数据
|
||
cursor.execute('''
|
||
INSERT OR REPLACE INTO game_states
|
||
(state_id, room_id, state_data, timestamp)
|
||
VALUES (?, ?, ?, ?)
|
||
''', (
|
||
state_id,
|
||
state_data.get("room_id"),
|
||
state_data_json,
|
||
state_data.get("timestamp", time.time())
|
||
))
|
||
|
||
self.db_connection.commit()
|
||
self.storage_stats["writes"] += 1
|
||
self.last_write = time.time()
|
||
|
||
# 触发数据保存回调
|
||
self._trigger_storage_callback("data_saved", {
|
||
"data_type": "game_state",
|
||
"state_id": state_id,
|
||
"timestamp": self.last_write
|
||
})
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 内部保存游戏状态数据失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def load_game_state(self, state_id: str) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
加载游戏状态数据
|
||
|
||
Args:
|
||
state_id: 状态ID
|
||
|
||
Returns:
|
||
游戏状态数据或None
|
||
"""
|
||
try:
|
||
if not self.enabled:
|
||
return None
|
||
|
||
# 从数据库加载
|
||
if not self.db_connection:
|
||
return None
|
||
|
||
cursor = self.db_connection.cursor()
|
||
cursor.execute('SELECT room_id, state_data, timestamp FROM game_states WHERE state_id = ?', (state_id,))
|
||
result = cursor.fetchone()
|
||
|
||
if result:
|
||
state_data = {
|
||
"state_id": state_id,
|
||
"room_id": result[0],
|
||
"data": json.loads(result[1]) if result[1] else {},
|
||
"timestamp": result[2]
|
||
}
|
||
|
||
self.storage_stats["reads"] += 1
|
||
self.last_read = time.time()
|
||
|
||
# 触发数据加载回调
|
||
self._trigger_storage_callback("data_loaded", {
|
||
"data_type": "game_state",
|
||
"state_id": state_id,
|
||
"timestamp": self.last_read
|
||
})
|
||
|
||
return state_data
|
||
else:
|
||
return None
|
||
|
||
except Exception as e:
|
||
print(f"✗ 加载游戏状态数据失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return None
|
||
|
||
def get_user_rooms(self, user_id: str) -> List[str]:
|
||
"""
|
||
获取用户所在的房间列表
|
||
|
||
Args:
|
||
user_id: 用户ID
|
||
|
||
Returns:
|
||
房间ID列表
|
||
"""
|
||
try:
|
||
if not self.db_connection:
|
||
return []
|
||
|
||
cursor = self.db_connection.cursor()
|
||
cursor.execute('SELECT room_id FROM user_rooms WHERE user_id = ?', (user_id,))
|
||
results = cursor.fetchall()
|
||
|
||
return [row[0] for row in results]
|
||
|
||
except Exception as e:
|
||
print(f"✗ 获取用户房间列表失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return []
|
||
|
||
def add_user_to_room(self, user_id: str, room_id: str) -> bool:
|
||
"""
|
||
添加用户到房间
|
||
|
||
Args:
|
||
user_id: 用户ID
|
||
room_id: 房间ID
|
||
|
||
Returns:
|
||
是否添加成功
|
||
"""
|
||
try:
|
||
if not self.db_connection:
|
||
return False
|
||
|
||
cursor = self.db_connection.cursor()
|
||
cursor.execute('''
|
||
INSERT OR IGNORE INTO user_rooms (user_id, room_id, join_time)
|
||
VALUES (?, ?, ?)
|
||
''', (user_id, room_id, time.time()))
|
||
|
||
self.db_connection.commit()
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 添加用户到房间失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def remove_user_from_room(self, user_id: str, room_id: str) -> bool:
|
||
"""
|
||
从房间移除用户
|
||
|
||
Args:
|
||
user_id: 用户ID
|
||
room_id: 房间ID
|
||
|
||
Returns:
|
||
是否移除成功
|
||
"""
|
||
try:
|
||
if not self.db_connection:
|
||
return False
|
||
|
||
cursor = self.db_connection.cursor()
|
||
cursor.execute('DELETE FROM user_rooms WHERE user_id = ? AND room_id = ?', (user_id, room_id))
|
||
|
||
self.db_connection.commit()
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 从房间移除用户失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def save_system_config(self, config_key: str, config_value: Any) -> bool:
|
||
"""
|
||
保存系统配置
|
||
|
||
Args:
|
||
config_key: 配置键
|
||
config_value: 配置值
|
||
|
||
Returns:
|
||
是否保存成功
|
||
"""
|
||
try:
|
||
if not self.db_connection:
|
||
return False
|
||
|
||
cursor = self.db_connection.cursor()
|
||
config_value_str = json.dumps(config_value, ensure_ascii=False)
|
||
|
||
cursor.execute('''
|
||
INSERT OR REPLACE INTO system_config (config_key, config_value, updated_time)
|
||
VALUES (?, ?, ?)
|
||
''', (config_key, config_value_str, time.time()))
|
||
|
||
self.db_connection.commit()
|
||
self.storage_stats["writes"] += 1
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 保存系统配置失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def load_system_config(self, config_key: str, default_value: Any = None) -> Any:
|
||
"""
|
||
加载系统配置
|
||
|
||
Args:
|
||
config_key: 配置键
|
||
default_value: 默认值
|
||
|
||
Returns:
|
||
配置值或默认值
|
||
"""
|
||
try:
|
||
if not self.db_connection:
|
||
return default_value
|
||
|
||
cursor = self.db_connection.cursor()
|
||
cursor.execute('SELECT config_value FROM system_config WHERE config_key = ?', (config_key,))
|
||
result = cursor.fetchone()
|
||
|
||
if result:
|
||
return json.loads(result[0])
|
||
else:
|
||
return default_value
|
||
|
||
except Exception as e:
|
||
print(f"✗ 加载系统配置失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return default_value
|
||
|
||
def add_log(self, log_level: str, log_message: str, user_id: str = None) -> bool:
|
||
"""
|
||
添加日志
|
||
|
||
Args:
|
||
log_level: 日志级别
|
||
log_message: 日志消息
|
||
user_id: 用户ID(可选)
|
||
|
||
Returns:
|
||
是否添加成功
|
||
"""
|
||
try:
|
||
if not self.db_connection:
|
||
return False
|
||
|
||
cursor = self.db_connection.cursor()
|
||
cursor.execute('''
|
||
INSERT INTO logs (log_level, log_message, timestamp, user_id)
|
||
VALUES (?, ?, ?, ?)
|
||
''', (log_level, log_message, time.time(), user_id))
|
||
|
||
self.db_connection.commit()
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"✗ 添加日志失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
return False
|
||
|
||
def get_storage_stats(self) -> Dict[str, Any]:
|
||
"""
|
||
获取存储统计信息
|
||
|
||
Returns:
|
||
存储统计字典
|
||
"""
|
||
return {
|
||
"stats": self.storage_stats.copy(),
|
||
"config": self.storage_config.copy(),
|
||
"cache_size": len(self.data_cache),
|
||
"write_queue_size": len(self.write_queue)
|
||
}
|
||
|
||
def reset_stats(self):
|
||
"""重置存储统计信息"""
|
||
try:
|
||
self.storage_stats = {
|
||
"reads": 0,
|
||
"writes": 0,
|
||
"cache_hits": 0,
|
||
"cache_misses": 0,
|
||
"backups_created": 0,
|
||
"errors": 0,
|
||
"bytes_read": 0,
|
||
"bytes_written": 0
|
||
}
|
||
print("✓ 存储统计信息已重置")
|
||
except Exception as e:
|
||
print(f"✗ 存储统计信息重置失败: {e}")
|
||
|
||
def set_storage_config(self, config: Dict[str, Any]) -> bool:
|
||
"""
|
||
设置存储配置
|
||
|
||
Args:
|
||
config: 存储配置字典
|
||
|
||
Returns:
|
||
是否设置成功
|
||
"""
|
||
try:
|
||
old_async = self.storage_config["enable_async_writes"]
|
||
new_async = config.get("enable_async_writes", old_async)
|
||
|
||
# 如果异步写入设置发生变化,处理线程
|
||
if old_async != new_async:
|
||
if new_async and not self.write_thread_running:
|
||
self._start_write_thread()
|
||
elif not new_async and self.write_thread_running:
|
||
self.write_thread_running = False
|
||
if self.write_thread and self.write_thread.is_alive():
|
||
self.write_thread.join(timeout=2.0)
|
||
|
||
self.storage_config.update(config)
|
||
print(f"✓ 存储配置已更新: {self.storage_config}")
|
||
return True
|
||
except Exception as e:
|
||
print(f"✗ 存储配置设置失败: {e}")
|
||
return False
|
||
|
||
def get_storage_config(self) -> Dict[str, Any]:
|
||
"""
|
||
获取存储配置
|
||
|
||
Returns:
|
||
存储配置字典
|
||
"""
|
||
return self.storage_config.copy()
|
||
|
||
def clear_cache(self):
|
||
"""清空缓存"""
|
||
try:
|
||
with self.cache_lock:
|
||
self.data_cache.clear()
|
||
print("✓ 存储缓存已清空")
|
||
except Exception as e:
|
||
print(f"✗ 存储缓存清空失败: {e}")
|
||
self.storage_stats["errors"] += 1
|
||
|
||
def _trigger_storage_callback(self, callback_type: str, data: Dict[str, Any]):
|
||
"""
|
||
触发存储回调
|
||
|
||
Args:
|
||
callback_type: 回调类型
|
||
data: 回调数据
|
||
"""
|
||
try:
|
||
if callback_type in self.storage_callbacks:
|
||
for callback in self.storage_callbacks[callback_type]:
|
||
try:
|
||
callback(data)
|
||
except Exception as e:
|
||
print(f"✗ 存储回调执行失败: {callback_type} - {e}")
|
||
except Exception as e:
|
||
print(f"✗ 存储回调触发失败: {e}")
|
||
|
||
def register_storage_callback(self, callback_type: str, callback: callable):
|
||
"""
|
||
注册存储回调
|
||
|
||
Args:
|
||
callback_type: 回调类型
|
||
callback: 回调函数
|
||
"""
|
||
try:
|
||
if callback_type in self.storage_callbacks:
|
||
self.storage_callbacks[callback_type].append(callback)
|
||
print(f"✓ 存储回调已注册: {callback_type}")
|
||
else:
|
||
print(f"✗ 无效的回调类型: {callback_type}")
|
||
except Exception as e:
|
||
print(f"✗ 存储回调注册失败: {e}")
|
||
|
||
def unregister_storage_callback(self, callback_type: str, callback: callable):
|
||
"""
|
||
注销存储回调
|
||
|
||
Args:
|
||
callback_type: 回调类型
|
||
callback: 回调函数
|
||
"""
|
||
try:
|
||
if callback_type in self.storage_callbacks:
|
||
if callback in self.storage_callbacks[callback_type]:
|
||
self.storage_callbacks[callback_type].remove(callback)
|
||
print(f"✓ 存储回调已注销: {callback_type}")
|
||
else:
|
||
print(f"✗ 无效的回调类型: {callback_type}")
|
||
except Exception as e:
|
||
print(f"✗ 存储回调注销失败: {e}")
|
||
|