""" 数据存储系统模块 负责持久化存储用户数据和游戏状态 """ 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}")