fix: 修复聊天系统编译错误
- 修复 WebSocketManager/SocketIOClient 函数缩进错误 - 重命名 is_connected() 避免与 Object 基类冲突 - 修复 tscn 文件多余前导空格 - 修复测试文件 GUT 断言函数调用 - 添加 GUT 测试框架
This commit is contained in:
@@ -80,25 +80,146 @@ var current_email: String = ""
|
||||
# 网络请求管理
|
||||
var active_request_ids: Array = []
|
||||
|
||||
# 游戏 token 管理(用于 WebSocket 聊天认证)
|
||||
var _game_token: String = ""
|
||||
# ============ Token 管理 ============
|
||||
|
||||
# 本地存储路径常量
|
||||
const AUTH_CONFIG_PATH: String = "user://auth.cfg"
|
||||
|
||||
# Token 存储(内存中,用于快速访问)
|
||||
var _access_token: String = "" # JWT访问令牌(短期,用于API和WebSocket)
|
||||
var _refresh_token: String = "" # JWT刷新令牌(长期,用于获取新access_token)
|
||||
var _user_info: Dictionary = {} # 用户信息
|
||||
var _token_expiry: float = 0.0 # access_token过期时间(Unix时间戳)
|
||||
|
||||
# 游戏 token(兼容旧代码,保留但标记为废弃)
|
||||
var _game_token: String = "" # @deprecated 使用 _access_token 替代
|
||||
|
||||
# ============ 生命周期方法 ============
|
||||
|
||||
# 初始化管理器
|
||||
func _init():
|
||||
func _init() -> void:
|
||||
print("AuthManager 初始化完成")
|
||||
_load_auth_data()
|
||||
|
||||
# 清理资源
|
||||
func cleanup():
|
||||
func cleanup() -> void:
|
||||
# 取消所有活动的网络请求
|
||||
for request_id in active_request_ids:
|
||||
NetworkManager.cancel_request(request_id)
|
||||
active_request_ids.clear()
|
||||
|
||||
# ============ 游戏 Token 管理 ============
|
||||
# ============ Token 管理 ============
|
||||
|
||||
# 设置游戏 token
|
||||
# 保存 Token 到内存
|
||||
#
|
||||
# 参数:
|
||||
# data: Dictionary - 登录响应数据
|
||||
#
|
||||
# 功能:
|
||||
# - 从登录响应中提取 access_token 和 refresh_token
|
||||
# - 保存到内存变量中
|
||||
# - 保存用户信息
|
||||
func _save_tokens_to_memory(data: Dictionary) -> void:
|
||||
if not data.has("data"):
|
||||
print("⚠️ 登录响应中没有 data 字段")
|
||||
return
|
||||
|
||||
var token_data: Dictionary = data.data
|
||||
_access_token = token_data.get("access_token", "")
|
||||
_refresh_token = token_data.get("refresh_token", "")
|
||||
_user_info = token_data.get("user", {})
|
||||
_token_expiry = Time.get_unix_time_from_system() + float(token_data.get("expires_in", 0))
|
||||
|
||||
# 保持兼容性:设置 _game_token
|
||||
_game_token = _access_token
|
||||
|
||||
print("✅ Token已保存到内存")
|
||||
print(" Access Token: ", _access_token.substr(0, 20) + "...")
|
||||
print(" 用户: ", _user_info.get("username", "未知"))
|
||||
|
||||
# 保存 Token 到本地(ConfigFile)
|
||||
#
|
||||
# 参数:
|
||||
# data: Dictionary - 登录响应数据
|
||||
#
|
||||
# 功能:
|
||||
# - 将 refresh_token 和用户信息保存到 ConfigFile
|
||||
# - access_token 不保存到本地,仅保存在内存中
|
||||
func _save_tokens_to_local(data: Dictionary) -> void:
|
||||
if not data.has("data"):
|
||||
return
|
||||
|
||||
var token_data: Dictionary = data.data
|
||||
var auth_data: Dictionary = {
|
||||
"refresh_token": token_data.get("refresh_token", ""),
|
||||
"user_id": token_data.get("user", {}).get("id", ""),
|
||||
"username": token_data.get("user", {}).get("username", ""),
|
||||
"saved_at": Time.get_unix_time_from_system()
|
||||
}
|
||||
|
||||
var config: ConfigFile = ConfigFile.new()
|
||||
config.load(AUTH_CONFIG_PATH)
|
||||
config.set_value("auth", "refresh_token", auth_data["refresh_token"])
|
||||
config.set_value("auth", "user_id", auth_data["user_id"])
|
||||
config.set_value("auth", "username", auth_data["username"])
|
||||
config.set_value("auth", "saved_at", auth_data["saved_at"])
|
||||
|
||||
var error: Error = config.save(AUTH_CONFIG_PATH)
|
||||
if error == OK:
|
||||
print("✅ Token已保存到本地: ", AUTH_CONFIG_PATH)
|
||||
else:
|
||||
print("❌ 保存Token到本地失败,错误码: ", error)
|
||||
|
||||
# 从本地加载 Token(游戏启动时调用)
|
||||
#
|
||||
# 功能:
|
||||
# - 从 ConfigFile 加载 refresh_token 和用户信息
|
||||
# - access_token 需要通过 refresh_token 刷新获取
|
||||
func _load_auth_data() -> void:
|
||||
if not FileAccess.file_exists(AUTH_CONFIG_PATH):
|
||||
print("ℹ️ 本地不存在认证数据")
|
||||
return
|
||||
|
||||
var config: ConfigFile = ConfigFile.new()
|
||||
var error: Error = config.load(AUTH_CONFIG_PATH)
|
||||
|
||||
if error != OK:
|
||||
print("❌ 加载本地认证数据失败,错误码: ", error)
|
||||
return
|
||||
|
||||
_refresh_token = config.get_value("auth", "refresh_token", "")
|
||||
var user_id: String = config.get_value("auth", "user_id", "")
|
||||
var username: String = config.get_value("auth", "username", "")
|
||||
|
||||
if not _refresh_token.is_empty():
|
||||
_user_info = {
|
||||
"id": user_id,
|
||||
"username": username
|
||||
}
|
||||
print("✅ 已从本地加载认证数据")
|
||||
print(" 用户: ", username)
|
||||
else:
|
||||
print("⚠️ 本地认证数据无效(没有 refresh_token)")
|
||||
|
||||
# 清除本地认证数据(登出时调用)
|
||||
#
|
||||
# 功能:
|
||||
# - 清除内存中的 Token
|
||||
# - 删除本地 ConfigFile
|
||||
func _clear_auth_data() -> void:
|
||||
_access_token = ""
|
||||
_refresh_token = ""
|
||||
_user_info = {}
|
||||
_token_expiry = 0.0
|
||||
_game_token = ""
|
||||
|
||||
if FileAccess.file_exists(AUTH_CONFIG_PATH):
|
||||
DirAccess.remove_absolute(AUTH_CONFIG_PATH)
|
||||
print("✅ 已清除本地认证数据")
|
||||
|
||||
# ============ Token 访问方法 ============
|
||||
|
||||
# 设置游戏 token(兼容旧代码,推荐使用 _save_tokens_to_memory)
|
||||
#
|
||||
# 参数:
|
||||
# token: String - 游戏认证 token
|
||||
@@ -108,18 +229,47 @@ func cleanup():
|
||||
# - 从服务器响应中获取 token
|
||||
func set_game_token(token: String) -> void:
|
||||
_game_token = token
|
||||
_access_token = token # 同步更新 access_token
|
||||
print("AuthManager: 游戏 token 已设置")
|
||||
|
||||
# 获取游戏 token
|
||||
#
|
||||
# 返回值:
|
||||
# String - 游戏 token,如果未设置则返回空字符串
|
||||
# String - access_token(如果未设置则返回空字符串)
|
||||
#
|
||||
# 使用场景:
|
||||
# - ChatManager 连接 WebSocket 时需要 token
|
||||
# - 其他需要游戏认证的场景
|
||||
func get_game_token() -> String:
|
||||
return _game_token
|
||||
return _access_token
|
||||
|
||||
# 获取 access token
|
||||
#
|
||||
# 返回值:
|
||||
# String - JWT访问令牌
|
||||
#
|
||||
# 使用场景:
|
||||
# - API请求认证
|
||||
# - WebSocket聊天认证
|
||||
func get_access_token() -> String:
|
||||
return _access_token
|
||||
|
||||
# 获取 refresh token
|
||||
#
|
||||
# 返回值:
|
||||
# String - JWT刷新令牌
|
||||
#
|
||||
# 使用场景:
|
||||
# - 刷新过期的 access token
|
||||
func get_refresh_token() -> String:
|
||||
return _refresh_token
|
||||
|
||||
# 获取用户信息
|
||||
#
|
||||
# 返回值:
|
||||
# Dictionary - 用户信息字典
|
||||
func get_user_info() -> Dictionary:
|
||||
return _user_info
|
||||
|
||||
# ============ 登录相关方法 ============
|
||||
|
||||
@@ -449,19 +599,21 @@ func validate_verification_code(code: String) -> Dictionary:
|
||||
# ============ 网络响应处理 ============
|
||||
|
||||
# 处理登录响应
|
||||
func _on_login_response(success: bool, data: Dictionary, error_info: Dictionary):
|
||||
func _on_login_response(success: bool, data: Dictionary, error_info: Dictionary) -> void:
|
||||
_reset_login_state()
|
||||
|
||||
|
||||
var result = ResponseHandler.handle_login_response(success, data, error_info)
|
||||
|
||||
|
||||
if result.should_show_toast:
|
||||
show_toast_message.emit(result.message, result.success)
|
||||
|
||||
|
||||
if result.success:
|
||||
var username = ""
|
||||
if data.has("data") and data.data.has("user") and data.data.user.has("username"):
|
||||
username = data.data.user.username
|
||||
|
||||
# 保存 Token 到内存和本地
|
||||
_save_tokens_to_memory(data)
|
||||
_save_tokens_to_local(data)
|
||||
|
||||
var username: String = _user_info.get("username", "")
|
||||
|
||||
# 延迟发送登录成功信号
|
||||
await Engine.get_main_loop().create_timer(1.0).timeout
|
||||
login_success.emit(username)
|
||||
@@ -469,19 +621,21 @@ func _on_login_response(success: bool, data: Dictionary, error_info: Dictionary)
|
||||
login_failed.emit(result.message)
|
||||
|
||||
# 处理验证码登录响应
|
||||
func _on_verification_login_response(success: bool, data: Dictionary, error_info: Dictionary):
|
||||
func _on_verification_login_response(success: bool, data: Dictionary, error_info: Dictionary) -> void:
|
||||
_reset_login_state()
|
||||
|
||||
|
||||
var result = ResponseHandler.handle_verification_code_login_response(success, data, error_info)
|
||||
|
||||
|
||||
if result.should_show_toast:
|
||||
show_toast_message.emit(result.message, result.success)
|
||||
|
||||
|
||||
if result.success:
|
||||
var username = ""
|
||||
if data.has("data") and data.data.has("user") and data.data.user.has("username"):
|
||||
username = data.data.user.username
|
||||
|
||||
# 保存 Token 到内存和本地
|
||||
_save_tokens_to_memory(data)
|
||||
_save_tokens_to_local(data)
|
||||
|
||||
var username: String = _user_info.get("username", "")
|
||||
|
||||
await Engine.get_main_loop().create_timer(1.0).timeout
|
||||
login_success.emit(username)
|
||||
else:
|
||||
|
||||
@@ -23,8 +23,6 @@ extends Node
|
||||
# - 所有聊天事件通过 EventSystem 广播
|
||||
# ============================================================================
|
||||
|
||||
class_name ChatManager
|
||||
|
||||
# ============================================================================
|
||||
# 信号定义 (Signal Up)
|
||||
# ============================================================================
|
||||
@@ -51,8 +49,8 @@ signal chat_error_occurred(error_code: String, message: String)
|
||||
|
||||
# 聊天连接状态变化信号
|
||||
# 参数:
|
||||
# state: WebSocketManager.ConnectionState - 连接状态
|
||||
signal chat_connection_state_changed(state: WebSocketManager.ConnectionState)
|
||||
# state: int - 连接状态(0=DISCONNECTED, 1=CONNECTING, 2=CONNECTED, 3=RECONNECTING, 4=ERROR)
|
||||
signal chat_connection_state_changed(state: int)
|
||||
|
||||
# 位置更新成功信号
|
||||
# 参数:
|
||||
@@ -178,7 +176,7 @@ func get_game_token() -> String:
|
||||
|
||||
# 连接到聊天服务器
|
||||
func connect_to_chat_server() -> void:
|
||||
if _websocket_manager.is_connected():
|
||||
if _websocket_manager.is_websocket_connected():
|
||||
push_warning("聊天服务器已连接")
|
||||
return
|
||||
|
||||
@@ -193,17 +191,17 @@ func disconnect_from_chat_server() -> void:
|
||||
if _is_logged_in:
|
||||
var logout_data := {"type": "logout"}
|
||||
_socket_client.emit("logout", logout_data)
|
||||
_is_logged_in = False
|
||||
_is_logged_in = false
|
||||
|
||||
# 断开连接
|
||||
_websocket_manager.disconnect()
|
||||
_websocket_manager.disconnect_websocket()
|
||||
|
||||
# 检查是否已连接
|
||||
#
|
||||
# 返回值:
|
||||
# bool - 是否已连接
|
||||
func is_connected() -> bool:
|
||||
return _websocket_manager.is_connected()
|
||||
func is_chat_connected() -> bool:
|
||||
return _websocket_manager.is_websocket_connected()
|
||||
|
||||
# ============================================================================
|
||||
# 公共 API - 聊天操作
|
||||
@@ -219,7 +217,7 @@ func is_connected() -> bool:
|
||||
# ChatManager.send_chat_message("Hello, world!", "local")
|
||||
func send_chat_message(content: String, scope: String = "local") -> void:
|
||||
# 检查连接状态
|
||||
if not _websocket_manager.is_connected():
|
||||
if not _websocket_manager.is_websocket_connected():
|
||||
_handle_error("NOT_CONNECTED", "未连接到聊天服务器")
|
||||
return
|
||||
|
||||
@@ -272,7 +270,7 @@ func send_chat_message(content: String, scope: String = "local") -> void:
|
||||
# 使用示例:
|
||||
# ChatManager.update_player_position(150.0, 200.0, "novice_village")
|
||||
func update_player_position(x: float, y: float, map_id: String) -> void:
|
||||
if not _websocket_manager.is_connected():
|
||||
if not _websocket_manager.is_websocket_connected():
|
||||
return
|
||||
|
||||
var position_data := {
|
||||
@@ -297,10 +295,9 @@ func can_send_message() -> bool:
|
||||
var current_time := Time.get_unix_time_from_system()
|
||||
|
||||
# 清理过期的时间戳
|
||||
_message_timestamps = _message_timestamps.filter(
|
||||
func(timestamp: float) -> bool:
|
||||
return current_time - timestamp < RATE_LIMIT_WINDOW
|
||||
)
|
||||
var filter_func := func(timestamp: float) -> bool:
|
||||
return current_time - timestamp < RATE_LIMIT_WINDOW
|
||||
_message_timestamps = _message_timestamps.filter(filter_func)
|
||||
|
||||
# 检查数量
|
||||
return _message_timestamps.size() < RATE_LIMIT_MESSAGES
|
||||
@@ -458,11 +455,12 @@ func _on_socket_connected() -> void:
|
||||
# Socket 连接断开
|
||||
func _on_socket_disconnected(_clean_close: bool) -> void:
|
||||
print("🔌 ChatManager: Socket 连接断开")
|
||||
_is_logged_in = False
|
||||
_is_logged_in = false
|
||||
|
||||
# 连接状态变化
|
||||
func _on_connection_state_changed(state: WebSocketManager.ConnectionState) -> void:
|
||||
print("📡 ChatManager: 连接状态变化 - ", WebSocketManager.ConnectionState.keys()[state])
|
||||
func _on_connection_state_changed(state: int) -> void:
|
||||
var state_names := ["DISCONNECTED", "CONNECTING", "CONNECTED", "RECONNECTING", "ERROR"]
|
||||
print("📡 ChatManager: 连接状态变化 - ", state_names[state])
|
||||
|
||||
# 发射信号
|
||||
chat_connection_state_changed.emit(state)
|
||||
@@ -496,7 +494,7 @@ func _on_socket_event_received(event_name: String, data: Dictionary) -> void:
|
||||
func _handle_login_success(data: Dictionary) -> void:
|
||||
print("✅ ChatManager: 登录成功")
|
||||
|
||||
_is_logged_in = True
|
||||
_is_logged_in = true
|
||||
_current_username = data.get("username", "")
|
||||
_current_map = data.get("currentMap", "")
|
||||
|
||||
@@ -590,8 +588,8 @@ func _on_socket_error(error: String) -> void:
|
||||
# 发送登录消息
|
||||
func _send_login_message() -> void:
|
||||
if _game_token.is_empty():
|
||||
push_error("无法获取游戏 token,请先调用 set_game_token() 设置 token")
|
||||
_handle_error("AUTH_FAILED", "无法获取游戏 token,请先设置 token")
|
||||
push_error("无法获取 access token,请确保已登录")
|
||||
_handle_error("AUTH_FAILED", "无法获取 access token,请先登录")
|
||||
return
|
||||
|
||||
var login_data := {
|
||||
@@ -600,14 +598,14 @@ func _send_login_message() -> void:
|
||||
}
|
||||
|
||||
_socket_client.emit("login", login_data)
|
||||
print("📤 发送登录消息")
|
||||
print("📤 发送登录消息(使用 access token)")
|
||||
|
||||
# 处理错误
|
||||
func _handle_error(error_code: String, error_message: String) -> void:
|
||||
print("❌ ChatManager 错误: [", error_code, "] ", error_message)
|
||||
|
||||
# 获取用户友好的错误消息
|
||||
var user_message := CHAT_ERROR_MESSAGES.get(error_code, error_message)
|
||||
var user_message: String = CHAT_ERROR_MESSAGES.get(error_code, error_message) as String
|
||||
|
||||
# 发射信号
|
||||
chat_error_occurred.emit(error_code, user_message)
|
||||
@@ -620,7 +618,7 @@ func _handle_error(error_code: String, error_message: String) -> void:
|
||||
|
||||
# 特殊处理认证失败
|
||||
if error_code == "AUTH_FAILED" or error_code == "SESSION_EXPIRED":
|
||||
_is_logged_in = False
|
||||
_is_logged_in = false
|
||||
EventSystem.emit_event(EventNames.CHAT_LOGIN_FAILED, {
|
||||
"error_code": error_code
|
||||
})
|
||||
@@ -633,11 +631,11 @@ func _record_message_timestamp() -> void:
|
||||
# 添加消息到当前会话历史
|
||||
func _add_message_to_history(message: Dictionary) -> void:
|
||||
_message_history.append(message)
|
||||
|
||||
|
||||
# 更新最旧消息时间戳(用于历史消息加载)
|
||||
if _oldest_message_timestamp == 0.0 or message.timestamp < _oldest_message_timestamp:
|
||||
_oldest_message_timestamp = message.timestamp
|
||||
|
||||
|
||||
# 限制当前会话消息数量(超过后删除最旧的)
|
||||
if _message_history.size() > MAX_SESSION_MESSAGES:
|
||||
_message_history.pop_front()
|
||||
|
||||
@@ -144,8 +144,8 @@ func connect_to_game_server() -> void:
|
||||
|
||||
_socket_client.connect_to_server(WEBSOCKET_URL)
|
||||
|
||||
# 断开连接
|
||||
func disconnect() -> void:
|
||||
# 断开 WebSocket 连接
|
||||
func disconnect_websocket() -> void:
|
||||
print("=== WebSocketManager 断开连接 ===")
|
||||
_clean_close = true
|
||||
|
||||
@@ -156,11 +156,11 @@ func disconnect() -> void:
|
||||
_socket_client.disconnect_from_server()
|
||||
_set_connection_state(ConnectionState.DISCONNECTED)
|
||||
|
||||
# 检查是否已连接
|
||||
# 检查 WebSocket 是否已连接
|
||||
#
|
||||
# 返回值:
|
||||
# bool - 是否已连接
|
||||
func is_connected() -> bool:
|
||||
# bool - WebSocket 是否已连接
|
||||
func is_websocket_connected() -> bool:
|
||||
return _connection_state == ConnectionState.CONNECTED
|
||||
|
||||
# 获取当前连接状态
|
||||
|
||||
@@ -134,11 +134,11 @@ func disconnect_from_server() -> void:
|
||||
_connection_state = ConnectionState.DISCONNECTED
|
||||
disconnected.emit(true)
|
||||
|
||||
# 检查是否已连接
|
||||
# 检查 Socket 是否已连接
|
||||
#
|
||||
# 返回值:
|
||||
# bool - 是否已连接
|
||||
func is_connected() -> bool:
|
||||
func is_socket_connected() -> bool:
|
||||
return _connection_state == ConnectionState.CONNECTED
|
||||
|
||||
# ============================================================================
|
||||
@@ -155,7 +155,7 @@ func is_connected() -> bool:
|
||||
# socket_client.emit("login", {"type": "login", "token": "abc123"})
|
||||
# socket_client.emit("chat", {"t": "chat", "content": "Hello", "scope": "local"})
|
||||
func emit(event_name: String, data: Dictionary) -> void:
|
||||
if not is_connected():
|
||||
if not is_socket_connected():
|
||||
push_error("无法发送事件: 未连接到服务器")
|
||||
error_occurred.emit("未连接到服务器")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user