diff --git a/core/managers/NetworkManager.gd b/core/managers/NetworkManager.gd new file mode 100644 index 0000000..dad9ff0 --- /dev/null +++ b/core/managers/NetworkManager.gd @@ -0,0 +1,443 @@ +extends Node + +# 网络请求管理器 - 统一处理所有HTTP请求 + +# 信号定义 +signal request_completed(request_id: String, success: bool, data: Dictionary) +signal request_failed(request_id: String, error_type: String, message: String) + +# API配置 +const API_BASE_URL = "https://whaletownend.xinghangee.icu" +const DEFAULT_TIMEOUT = 30.0 + +# 请求类型枚举 +enum RequestType { + GET, + POST, + PUT, + DELETE, + PATCH +} + +# 错误类型枚举 +enum ErrorType { + NETWORK_ERROR, # 网络连接错误 + TIMEOUT_ERROR, # 请求超时 + PARSE_ERROR, # JSON解析错误 + HTTP_ERROR, # HTTP状态码错误 + BUSINESS_ERROR # 业务逻辑错误 +} + +# 请求状态 +class RequestInfo: + var id: String + var url: String + var method: RequestType + var headers: PackedStringArray + var body: String + var timeout: float + var start_time: float + var http_request: HTTPRequest + var callback: Callable + + func _init(request_id: String, request_url: String, request_method: RequestType, + request_headers: PackedStringArray = [], request_body: String = "", + request_timeout: float = DEFAULT_TIMEOUT): + id = request_id + url = request_url + method = request_method + headers = request_headers + body = request_body + timeout = request_timeout + start_time = Time.get_time_dict_from_system().hour * 3600 + Time.get_time_dict_from_system().minute * 60 + Time.get_time_dict_from_system().second + +# 活动请求管理 +var active_requests: Dictionary = {} +var request_counter: int = 0 + +func _ready(): + print("NetworkManager 已初始化") + +# ============ 公共API接口 ============ + +# 发送GET请求 +func get_request(endpoint: String, callback: Callable = Callable(), timeout: float = DEFAULT_TIMEOUT) -> String: + return send_request(endpoint, RequestType.GET, [], "", callback, timeout) + +# 发送POST请求 +func post_request(endpoint: String, data: Dictionary, callback: Callable = Callable(), timeout: float = DEFAULT_TIMEOUT) -> String: + var body = JSON.stringify(data) + var headers = ["Content-Type: application/json"] + return send_request(endpoint, RequestType.POST, headers, body, callback, timeout) + +# 发送PUT请求 +func put_request(endpoint: String, data: Dictionary, callback: Callable = Callable(), timeout: float = DEFAULT_TIMEOUT) -> String: + var body = JSON.stringify(data) + var headers = ["Content-Type: application/json"] + return send_request(endpoint, RequestType.PUT, headers, body, callback, timeout) + +# 发送DELETE请求 +func delete_request(endpoint: String, callback: Callable = Callable(), timeout: float = DEFAULT_TIMEOUT) -> String: + return send_request(endpoint, RequestType.DELETE, [], "", callback, timeout) + +# ============ 认证相关API ============ + +# 用户登录 +func login(identifier: String, password: String, callback: Callable = Callable()) -> String: + var data = { + "identifier": identifier, + "password": password + } + return post_request("/auth/login", data, callback) + +# 验证码登录 +func verification_code_login(identifier: String, verification_code: String, callback: Callable = Callable()) -> String: + var data = { + "identifier": identifier, + "verification_code": verification_code + } + return post_request("/auth/verification-code-login", data, callback) + +# 发送登录验证码 +func send_login_verification_code(identifier: String, callback: Callable = Callable()) -> String: + var data = {"identifier": identifier} + return post_request("/auth/send-login-verification-code", data, callback) + +# 用户注册 +func register(username: String, password: String, nickname: String, email: String = "", + email_verification_code: String = "", callback: Callable = Callable()) -> String: + var data = { + "username": username, + "password": password, + "nickname": nickname + } + + if email != "": + data["email"] = email + if email_verification_code != "": + data["email_verification_code"] = email_verification_code + + return post_request("/auth/register", data, callback) + +# 发送邮箱验证码 +func send_email_verification(email: String, callback: Callable = Callable()) -> String: + var data = {"email": email} + return post_request("/auth/send-email-verification", data, callback) + +# 验证邮箱 +func verify_email(email: String, verification_code: String, callback: Callable = Callable()) -> String: + var data = { + "email": email, + "verification_code": verification_code + } + return post_request("/auth/verify-email", data, callback) + +# 获取应用状态 +func get_app_status(callback: Callable = Callable()) -> String: + return get_request("/", callback) + +# 重新发送邮箱验证码 +func resend_email_verification(email: String, callback: Callable = Callable()) -> String: + var data = {"email": email} + return post_request("/auth/resend-email-verification", data, callback) + +# 忘记密码 - 发送重置验证码 +func forgot_password(identifier: String, callback: Callable = Callable()) -> String: + var data = {"identifier": identifier} + return post_request("/auth/forgot-password", data, callback) + +# 重置密码 +func reset_password(identifier: String, verification_code: String, new_password: String, callback: Callable = Callable()) -> String: + var data = { + "identifier": identifier, + "verification_code": verification_code, + "new_password": new_password + } + return post_request("/auth/reset-password", data, callback) + +# 修改密码 +func change_password(user_id: String, old_password: String, new_password: String, callback: Callable = Callable()) -> String: + var data = { + "user_id": user_id, + "old_password": old_password, + "new_password": new_password + } + return put_request("/auth/change-password", data, callback) + +# GitHub OAuth登录 +func github_login(github_id: String, username: String, nickname: String, email: String, avatar_url: String = "", callback: Callable = Callable()) -> String: + var data = { + "github_id": github_id, + "username": username, + "nickname": nickname, + "email": email + } + + if avatar_url != "": + data["avatar_url"] = avatar_url + + return post_request("/auth/github", data, callback) + +# ============ 核心请求处理 ============ + +# 发送请求的核心方法 +func send_request(endpoint: String, method: RequestType, headers: PackedStringArray, + body: String, callback: Callable, timeout: float) -> String: + # 生成请求ID + request_counter += 1 + var request_id = "req_" + str(request_counter) + + # 构建完整URL + var full_url = API_BASE_URL + endpoint + + # 创建HTTPRequest节点 + var http_request = HTTPRequest.new() + add_child(http_request) + + # 设置超时 + http_request.timeout = timeout + + # 创建请求信息 + var request_info = RequestInfo.new(request_id, full_url, method, headers, body, timeout) + request_info.http_request = http_request + request_info.callback = callback + + # 存储请求信息 + active_requests[request_id] = request_info + + # 连接信号 + http_request.request_completed.connect(func(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray): + _on_request_completed(request_id, result, response_code, headers, body) + ) + + # 发送请求 + var godot_method = _convert_to_godot_method(method) + var error = http_request.request(full_url, headers, godot_method, body) + + print("=== 发送网络请求 ===") + print("请求ID: ", request_id) + print("URL: ", full_url) + print("方法: ", RequestType.keys()[method]) + print("Headers: ", headers) + print("Body: ", body if body.length() < 200 else body.substr(0, 200) + "...") + print("发送结果: ", error) + + if error != OK: + print("请求发送失败,错误代码: ", error) + _handle_request_error(request_id, ErrorType.NETWORK_ERROR, "网络请求发送失败: " + str(error)) + return "" + + return request_id + +# 请求完成回调 +func _on_request_completed(request_id: String, result: int, response_code: int, + headers: PackedStringArray, body: PackedByteArray): + print("=== 网络请求完成 ===") + print("请求ID: ", request_id) + print("结果: ", result) + print("状态码: ", response_code) + print("响应头: ", headers) + + # 获取请求信息 + if not active_requests.has(request_id): + print("警告: 未找到请求ID ", request_id) + return + + var request_info = active_requests[request_id] + var response_text = body.get_string_from_utf8() + + print("响应体长度: ", body.size(), " 字节") + print("响应内容: ", response_text if response_text.length() < 500 else response_text.substr(0, 500) + "...") + + # 处理网络连接失败 + if response_code == 0: + _handle_request_error(request_id, ErrorType.NETWORK_ERROR, "网络连接失败,请检查网络连接") + return + + # 解析JSON响应 + var json = JSON.new() + var parse_result = json.parse(response_text) + if parse_result != OK: + _handle_request_error(request_id, ErrorType.PARSE_ERROR, "服务器响应格式错误") + return + + var response_data = json.data + + # 处理响应 + _handle_response(request_id, response_code, response_data) + +# 处理响应 - 支持API v1.1.1的状态码 +func _handle_response(request_id: String, response_code: int, data: Dictionary): + var request_info = active_requests[request_id] + + # 检查业务成功标志 + var success = data.get("success", true) # 默认true保持向后兼容 + var error_code = data.get("error_code", "") + var message = data.get("message", "") + + # 判断请求是否成功 + var is_success = false + + # HTTP成功状态码且业务成功 + if (response_code >= 200 and response_code < 300) and success: + is_success = true + # 特殊情况:206测试模式 - 根据API文档,这是成功的测试模式响应 + elif response_code == 206 and error_code == "TEST_MODE_ONLY": + is_success = true + print("🧪 测试模式响应: ", message) + # 201创建成功 + elif response_code == 201: + is_success = true + + if is_success: + print("✅ 请求成功: ", request_id) + # 发送成功信号 + request_completed.emit(request_id, true, data) + + # 调用回调函数 + if request_info.callback.is_valid(): + request_info.callback.call(true, data, {}) + else: + print("❌ 请求失败: ", request_id, " - HTTP:", response_code, " 错误码:", error_code, " 消息:", message) + + # 确定错误类型 + var error_type = _determine_error_type(response_code, error_code) + + # 发送失败信号 + request_failed.emit(request_id, ErrorType.keys()[error_type], message) + + # 调用回调函数 + if request_info.callback.is_valid(): + var error_info = { + "response_code": response_code, + "error_code": error_code, + "message": message, + "error_type": error_type + } + request_info.callback.call(false, data, error_info) + + # 清理请求 + _cleanup_request(request_id) + +# 处理请求错误 +func _handle_request_error(request_id: String, error_type: ErrorType, message: String): + print("❌ 请求错误: ", request_id, " - ", message) + + # 发送错误信号 + request_failed.emit(request_id, ErrorType.keys()[error_type], message) + + # 调用回调函数 + if active_requests.has(request_id): + var request_info = active_requests[request_id] + if request_info.callback.is_valid(): + var error_info = { + "error_type": error_type, + "message": message + } + request_info.callback.call(false, {}, error_info) + + # 清理请求 + _cleanup_request(request_id) + +# 确定错误类型 - 支持更多状态码 +func _determine_error_type(response_code: int, error_code: String) -> ErrorType: + # 根据错误码判断 + match error_code: + "SERVICE_UNAVAILABLE": + return ErrorType.BUSINESS_ERROR + "TOO_MANY_REQUESTS": + return ErrorType.BUSINESS_ERROR + "TEST_MODE_ONLY": + return ErrorType.BUSINESS_ERROR + "SEND_EMAIL_VERIFICATION_FAILED", "REGISTER_FAILED": + # 这些可能是409冲突或其他业务错误 + return ErrorType.BUSINESS_ERROR + _: + # 根据HTTP状态码判断 + match response_code: + 409: # 资源冲突 + return ErrorType.BUSINESS_ERROR + 206: # 测试模式 + return ErrorType.BUSINESS_ERROR + 429: # 频率限制 + return ErrorType.BUSINESS_ERROR + _: + if response_code >= 400 and response_code < 500: + return ErrorType.HTTP_ERROR + elif response_code >= 500: + return ErrorType.HTTP_ERROR + else: + return ErrorType.BUSINESS_ERROR + +# 清理请求资源 +func _cleanup_request(request_id: String): + if active_requests.has(request_id): + var request_info = active_requests[request_id] + + # 移除HTTPRequest节点 + if is_instance_valid(request_info.http_request): + request_info.http_request.queue_free() + + # 从活动请求中移除 + active_requests.erase(request_id) + + print("🧹 清理请求: ", request_id) + +# 转换请求方法 +func _convert_to_godot_method(method: RequestType) -> HTTPClient.Method: + match method: + RequestType.GET: + return HTTPClient.METHOD_GET + RequestType.POST: + return HTTPClient.METHOD_POST + RequestType.PUT: + return HTTPClient.METHOD_PUT + RequestType.DELETE: + return HTTPClient.METHOD_DELETE + RequestType.PATCH: + return HTTPClient.METHOD_PATCH + _: + return HTTPClient.METHOD_GET + +# ============ 工具方法 ============ + +# 取消请求 +func cancel_request(request_id: String) -> bool: + if active_requests.has(request_id): + print("🚫 取消请求: ", request_id) + _cleanup_request(request_id) + return true + return false + +# 取消所有请求 +func cancel_all_requests(): + print("🚫 取消所有请求") + var request_ids = active_requests.keys() + for request_id in request_ids: + cancel_request(request_id) + +# 获取活动请求数量 +func get_active_request_count() -> int: + return active_requests.size() + +# 检查请求是否活动 +func is_request_active(request_id: String) -> bool: + return active_requests.has(request_id) + +# 获取请求信息 +func get_request_info(request_id: String) -> Dictionary: + if active_requests.has(request_id): + var info = active_requests[request_id] + return { + "id": info.id, + "url": info.url, + "method": RequestType.keys()[info.method], + "start_time": info.start_time, + "timeout": info.timeout + } + return {} + +func _notification(what): + if what == NOTIFICATION_WM_CLOSE_REQUEST: + # 应用关闭时取消所有请求 + cancel_all_requests() \ No newline at end of file diff --git a/core/managers/NetworkManager.gd.uid b/core/managers/NetworkManager.gd.uid new file mode 100644 index 0000000..80d6695 --- /dev/null +++ b/core/managers/NetworkManager.gd.uid @@ -0,0 +1 @@ +uid://cb040lxcf4smh diff --git a/core/managers/ResponseHandler.gd b/core/managers/ResponseHandler.gd new file mode 100644 index 0000000..e3b5b66 --- /dev/null +++ b/core/managers/ResponseHandler.gd @@ -0,0 +1,590 @@ +extends Node + +# 响应处理器 - 统一处理API响应和错误 + +# 响应处理结果 +class ResponseResult: + var success: bool + var message: String + var toast_type: String # "success" 或 "error" + var data: Dictionary + var should_show_toast: bool + var custom_action: Callable + + func _init(): + success = false + message = "" + toast_type = "error" + data = {} + should_show_toast = true + custom_action = Callable() + +# 错误码映射表 - 根据API v1.1.1更新 +const ERROR_CODE_MESSAGES = { + # 登录相关 + "LOGIN_FAILED": "登录失败", + "VERIFICATION_CODE_LOGIN_FAILED": "验证码错误或已过期", + "EMAIL_NOT_VERIFIED": "请先验证邮箱", + + # 注册相关 + "REGISTER_FAILED": "注册失败", + + # 验证码相关 + "SEND_CODE_FAILED": "发送验证码失败", + "SEND_LOGIN_CODE_FAILED": "发送登录验证码失败", + "SEND_EMAIL_VERIFICATION_FAILED": "发送邮箱验证码失败", + "RESEND_EMAIL_VERIFICATION_FAILED": "重新发送验证码失败", + "EMAIL_VERIFICATION_FAILED": "邮箱验证失败", + "RESET_PASSWORD_FAILED": "重置密码失败", + "CHANGE_PASSWORD_FAILED": "修改密码失败", + "VERIFICATION_CODE_EXPIRED": "验证码已过期", + "VERIFICATION_CODE_INVALID": "验证码无效", + "VERIFICATION_CODE_ATTEMPTS_EXCEEDED": "验证码尝试次数过多", + "VERIFICATION_CODE_RATE_LIMITED": "验证码发送过于频繁", + "VERIFICATION_CODE_HOURLY_LIMIT": "验证码每小时发送次数已达上限", + + # 用户状态相关 + "USER_NOT_FOUND": "用户不存在", + "INVALID_IDENTIFIER": "请输入有效的邮箱或手机号", + "USER_STATUS_UPDATE_FAILED": "用户状态更新失败", + + # 系统状态相关 + "TEST_MODE_ONLY": "测试模式", + "TOO_MANY_REQUESTS": "请求过于频繁,请稍后再试", + "SERVICE_UNAVAILABLE": "系统维护中,请稍后再试", + + # 权限相关 + "UNAUTHORIZED": "未授权访问", + "FORBIDDEN": "权限不足", + "ADMIN_LOGIN_FAILED": "管理员登录失败", + + # 其他 + "VALIDATION_FAILED": "参数验证失败", + "UNSUPPORTED_MEDIA_TYPE": "不支持的请求格式", + "REQUEST_TIMEOUT": "请求超时" +} + +# HTTP状态码消息映射 - 根据API v1.1.1更新 +const HTTP_STATUS_MESSAGES = { + 200: "请求成功", + 201: "创建成功", + 206: "测试模式", + 400: "请求参数错误", + 401: "认证失败", + 403: "权限不足", + 404: "资源不存在", + 408: "请求超时", + 409: "资源冲突", + 415: "不支持的媒体类型", + 429: "请求过于频繁", + 500: "服务器内部错误", + 503: "服务不可用" +} + +# ============ 主要处理方法 ============ + +# 处理登录响应 +static func handle_login_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + result.success = true + result.message = "登录成功!正在进入鲸鱼镇..." + result.toast_type = "success" + result.data = data + + # 自定义动作:延迟发送登录成功信号 + result.custom_action = func(): + await Engine.get_main_loop().create_timer(1.0).timeout + # 这里可以发送登录成功信号或执行其他逻辑 + else: + result = _handle_login_error(data, error_info) + + return result + +# 处理验证码登录响应 +static func handle_verification_code_login_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + result.success = true + result.message = "验证码登录成功!正在进入鲸鱼镇..." + result.toast_type = "success" + result.data = data + + result.custom_action = func(): + await Engine.get_main_loop().create_timer(1.0).timeout + # 登录成功后的处理逻辑 + else: + result = _handle_verification_code_login_error(data, error_info) + + return result + +# 处理发送验证码响应 - 支持邮箱冲突检测 +static func handle_send_verification_code_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + var error_code = data.get("error_code", "") + if error_code == "TEST_MODE_ONLY": + result.success = true + result.message = "🧪 测试模式:验证码已生成,请查看控制台" + result.toast_type = "success" + + # 在控制台显示验证码 + if data.has("data") and data.data.has("verification_code"): + print("🔑 测试模式验证码: ", data.data.verification_code) + result.message += "\n验证码: " + str(data.data.verification_code) + else: + result.success = true + result.message = "📧 验证码已发送到您的邮箱,请查收" + result.toast_type = "success" + + # 开发环境下显示验证码 + if data.has("data") and data.data.has("verification_code"): + print("🔑 开发环境验证码: ", data.data.verification_code) + else: + result = _handle_send_code_error(data, error_info) + + return result + +# 处理发送登录验证码响应 +static func handle_send_login_code_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + var error_code = data.get("error_code", "") + if error_code == "TEST_MODE_ONLY": + result.success = true + result.message = "测试模式:登录验证码已生成,请查看控制台" + result.toast_type = "success" + + if data.has("data") and data.data.has("verification_code"): + print("测试模式登录验证码: ", data.data.verification_code) + else: + result.success = true + result.message = "登录验证码已发送,请查收" + result.toast_type = "success" + + if data.has("data") and data.data.has("verification_code"): + print("开发环境登录验证码: ", data.data.verification_code) + else: + result = _handle_send_login_code_error(data, error_info) + + return result + +# 处理注册响应 +static func handle_register_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + result.success = true + result.message = "注册成功!欢迎加入鲸鱼镇" + result.toast_type = "success" + result.data = data + + # 自定义动作:清空表单,切换到登录界面 + result.custom_action = func(): + # 这里可以执行清空表单、切换界面等操作 + pass + else: + result = _handle_register_error(data, error_info) + + return result + +# 处理邮箱验证响应 +static func handle_verify_email_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + result.success = true + result.message = "邮箱验证成功,正在注册..." + result.toast_type = "success" + result.data = data + else: + result = _handle_verify_email_error(data, error_info) + + return result + +# 处理重新发送邮箱验证码响应 +static func handle_resend_email_verification_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + var error_code = data.get("error_code", "") + if error_code == "TEST_MODE_ONLY": + result.success = true + result.message = "🧪 测试模式:验证码已重新生成,请查看控制台" + result.toast_type = "success" + + if data.has("data") and data.data.has("verification_code"): + print("🔑 测试模式重新发送验证码: ", data.data.verification_code) + else: + result.success = true + result.message = "📧 验证码已重新发送到您的邮箱,请查收" + result.toast_type = "success" + + if data.has("data") and data.data.has("verification_code"): + print("🔑 开发环境重新发送验证码: ", data.data.verification_code) + else: + result = _handle_resend_email_verification_error(data, error_info) + + return result + +# 处理忘记密码响应 +static func handle_forgot_password_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + var error_code = data.get("error_code", "") + if error_code == "TEST_MODE_ONLY": + result.success = true + result.message = "🧪 测试模式:重置验证码已生成,请查看控制台" + result.toast_type = "success" + + if data.has("data") and data.data.has("verification_code"): + print("🔑 测试模式重置验证码: ", data.data.verification_code) + else: + result.success = true + result.message = "📧 重置验证码已发送,请查收" + result.toast_type = "success" + + if data.has("data") and data.data.has("verification_code"): + print("🔑 开发环境重置验证码: ", data.data.verification_code) + else: + result = _handle_forgot_password_error(data, error_info) + + return result + +# 处理重置密码响应 +static func handle_reset_password_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + result.success = true + result.message = "🔒 密码重置成功,请使用新密码登录" + result.toast_type = "success" + result.data = data + else: + result = _handle_reset_password_error(data, error_info) + + return result + +# ============ 错误处理方法 ============ + +# 处理登录错误 +static func _handle_login_error(data: Dictionary, error_info: Dictionary) -> ResponseResult: + var result = ResponseResult.new() + var error_code = data.get("error_code", "") + var message = data.get("message", "登录失败") + + match error_code: + "LOGIN_FAILED": + # 根据消息内容进一步判断用户状态 + if "账户已锁定" in message or "locked" in message.to_lower(): + result.message = "账户已被锁定,请联系管理员" + elif "账户已禁用" in message or "banned" in message.to_lower(): + result.message = "账户已被禁用,请联系管理员" + elif "账户待审核" in message or "pending" in message.to_lower(): + result.message = "账户待审核,请等待管理员审核" + elif "邮箱未验证" in message or "inactive" in message.to_lower(): + result.message = "请先验证邮箱后再登录" + else: + result.message = "用户名或密码错误,请检查后重试" + _: + result.message = _get_error_message(error_code, message, error_info) + + return result + +# 处理验证码登录错误 +static func _handle_verification_code_login_error(data: Dictionary, error_info: Dictionary) -> ResponseResult: + var result = ResponseResult.new() + var error_code = data.get("error_code", "") + var message = data.get("message", "验证码登录失败") + + match error_code: + "VERIFICATION_CODE_LOGIN_FAILED": + result.message = "验证码错误或已过期" + "EMAIL_NOT_VERIFIED": + result.message = "邮箱未验证,请先验证邮箱后再使用验证码登录" + "USER_NOT_FOUND": + result.message = "用户不存在,请先注册" + "INVALID_IDENTIFIER": + result.message = "请输入有效的邮箱或手机号" + _: + result.message = _get_error_message(error_code, message, error_info) + + return result + +# 处理发送验证码错误 - 支持邮箱冲突检测和频率限制 +static func _handle_send_code_error(data: Dictionary, error_info: Dictionary) -> ResponseResult: + var result = ResponseResult.new() + var error_code = data.get("error_code", "") + var message = data.get("message", "发送验证码失败") + var response_code = error_info.get("response_code", 0) + + match error_code: + "SEND_EMAIL_VERIFICATION_FAILED": + # 检查是否是邮箱冲突(409状态码) + if response_code == 409: + result.message = "⚠️ 邮箱已被注册,请使用其他邮箱或直接登录" + result.toast_type = "error" + elif "邮箱格式" in message: + result.message = "📧 请输入有效的邮箱地址" + else: + result.message = message + "TOO_MANY_REQUESTS": + # 处理频率限制,提供重试建议 + result.toast_type = "error" + + # 如果有throttle_info,显示更详细的信息 + if data.has("throttle_info"): + var throttle_info = data.throttle_info + var reset_time = throttle_info.get("reset_time", "") + if reset_time != "": + var relative_time = StringUtils.get_relative_time_until(reset_time) + var local_time = StringUtils.format_utc_to_local_time(reset_time) + result.message = "⏰ 验证码发送过于频繁" + result.message += "\n请" + relative_time + "再试" + result.message += "\n重试时间: " + local_time + else: + result.message = "⏰ 验证码发送过于频繁,请稍后再试" + else: + result.message = "⏰ 验证码发送过于频繁,请稍后再试" + "VERIFICATION_CODE_RATE_LIMITED": + result.message = "⏰ 验证码发送过于频繁,请稍后再试" + "VERIFICATION_CODE_HOURLY_LIMIT": + result.message = "⏰ 每小时发送次数已达上限,请稍后再试" + _: + result.message = _get_error_message(error_code, message, error_info) + + return result + +# 处理发送登录验证码错误 +static func _handle_send_login_code_error(data: Dictionary, error_info: Dictionary) -> ResponseResult: + var result = ResponseResult.new() + var error_code = data.get("error_code", "") + var message = data.get("message", "发送登录验证码失败") + + match error_code: + "SEND_LOGIN_CODE_FAILED": + if "用户不存在" in message: + result.message = "用户不存在,请先注册" + else: + result.message = "发送登录验证码失败" + "USER_NOT_FOUND": + result.message = "用户不存在,请先注册" + "INVALID_IDENTIFIER": + result.message = "请输入有效的邮箱或手机号" + _: + result.message = _get_error_message(error_code, message, error_info) + + return result + +# 处理注册错误 - 支持409冲突状态码 +static func _handle_register_error(data: Dictionary, error_info: Dictionary) -> ResponseResult: + var result = ResponseResult.new() + var error_code = data.get("error_code", "") + var message = data.get("message", "注册失败") + var response_code = error_info.get("response_code", 0) + + match error_code: + "REGISTER_FAILED": + # 检查409冲突状态码 + if response_code == 409: + if "邮箱已存在" in message or "邮箱已被使用" in message: + result.message = "📧 邮箱已被注册,请使用其他邮箱或直接登录" + elif "用户名已存在" in message or "用户名已被使用" in message: + result.message = "👤 用户名已被使用,请换一个" + else: + result.message = "⚠️ 资源冲突:" + message + elif "邮箱验证码" in message or "verification_code" in message: + result.message = "🔑 请先获取并输入邮箱验证码" + elif "用户名" in message: + result.message = "👤 用户名格式不正确" + elif "邮箱" in message: + result.message = "📧 邮箱格式不正确" + elif "密码" in message: + result.message = "🔒 密码格式不符合要求" + elif "验证码" in message: + result.message = "🔑 验证码错误或已过期" + else: + result.message = message + _: + result.message = _get_error_message(error_code, message, error_info) + + return result + +# 处理邮箱验证错误 +static func _handle_verify_email_error(data: Dictionary, error_info: Dictionary) -> ResponseResult: + var result = ResponseResult.new() + var error_code = data.get("error_code", "") + var message = data.get("message", "邮箱验证失败") + + match error_code: + "EMAIL_VERIFICATION_FAILED": + if "验证码错误" in message: + result.message = "🔑 验证码错误" + elif "验证码已过期" in message: + result.message = "🔑 验证码已过期,请重新获取" + else: + result.message = message + "VERIFICATION_CODE_INVALID": + result.message = "🔑 验证码错误或已过期" + "VERIFICATION_CODE_EXPIRED": + result.message = "🔑 验证码已过期,请重新获取" + _: + result.message = _get_error_message(error_code, message, error_info) + + return result + +# 处理网络测试响应 +static func handle_network_test_response(success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + var result = ResponseResult.new() + + if success: + result.success = true + result.message = "🌐 网络连接正常" + result.toast_type = "success" + else: + result.success = false + result.message = "🌐 网络连接异常" + result.toast_type = "error" + + return result + +# 处理重新发送邮箱验证码错误 +static func _handle_resend_email_verification_error(data: Dictionary, error_info: Dictionary) -> ResponseResult: + var result = ResponseResult.new() + var error_code = data.get("error_code", "") + var message = data.get("message", "重新发送验证码失败") + + match error_code: + "RESEND_EMAIL_VERIFICATION_FAILED": + if "邮箱已验证" in message: + result.message = "📧 邮箱已验证,无需重复验证" + else: + result.message = message + _: + result.message = _get_error_message(error_code, message, error_info) + + return result + +# 处理忘记密码错误 +static func _handle_forgot_password_error(data: Dictionary, error_info: Dictionary) -> ResponseResult: + var result = ResponseResult.new() + var error_code = data.get("error_code", "") + var message = data.get("message", "发送重置验证码失败") + + match error_code: + "SEND_CODE_FAILED": + if "用户不存在" in message: + result.message = "👤 用户不存在,请检查邮箱或手机号" + else: + result.message = message + "USER_NOT_FOUND": + result.message = "👤 用户不存在,请检查邮箱或手机号" + _: + result.message = _get_error_message(error_code, message, error_info) + + return result + +# 处理重置密码错误 +static func _handle_reset_password_error(data: Dictionary, error_info: Dictionary) -> ResponseResult: + var result = ResponseResult.new() + var error_code = data.get("error_code", "") + var message = data.get("message", "重置密码失败") + + match error_code: + "RESET_PASSWORD_FAILED": + if "验证码" in message: + result.message = "🔑 验证码错误或已过期" + else: + result.message = message + _: + result.message = _get_error_message(error_code, message, error_info) + + return result + +# ============ 工具方法 ============ + +# 获取错误消息 - 支持更多状态码和错误处理 +static func _get_error_message(error_code: String, original_message: String, error_info: Dictionary) -> String: + # 优先使用错误码映射 + if ERROR_CODE_MESSAGES.has(error_code): + return ERROR_CODE_MESSAGES[error_code] + + # 处理频率限制 + if error_code == "TOO_MANY_REQUESTS": + return _handle_rate_limit_message(original_message, error_info) + + # 处理维护模式 + if error_code == "SERVICE_UNAVAILABLE": + return _handle_maintenance_message(original_message, error_info) + + # 处理测试模式 + if error_code == "TEST_MODE_ONLY": + return "🧪 测试模式:" + original_message + + # 根据HTTP状态码处理 + if error_info.has("response_code"): + var response_code = error_info.response_code + match response_code: + 409: + return "⚠️ 资源冲突:" + original_message + 206: + return "🧪 测试模式:" + original_message + 429: + return "⏰ 请求过于频繁,请稍后再试" + _: + if HTTP_STATUS_MESSAGES.has(response_code): + return HTTP_STATUS_MESSAGES[response_code] + ":" + original_message + + # 返回原始消息 + return original_message if original_message != "" else "操作失败" + +# 处理频率限制消息 +static func _handle_rate_limit_message(message: String, error_info: Dictionary) -> String: + # 可以根据throttle_info提供更详细的信息 + return message + ",请稍后再试" + +# 处理维护模式消息 +static func _handle_maintenance_message(message: String, error_info: Dictionary) -> String: + # 可以根据maintenance_info提供更详细的信息 + return "系统维护中,请稍后再试" + +# 通用响应处理器 - 支持更多操作类型 +static func handle_response(operation_type: String, success: bool, data: Dictionary, error_info: Dictionary = {}) -> ResponseResult: + match operation_type: + "login": + return handle_login_response(success, data, error_info) + "verification_code_login": + return handle_verification_code_login_response(success, data, error_info) + "send_code": + return handle_send_verification_code_response(success, data, error_info) + "send_login_code": + return handle_send_login_code_response(success, data, error_info) + "register": + return handle_register_response(success, data, error_info) + "verify_email": + return handle_verify_email_response(success, data, error_info) + "resend_email_verification": + return handle_resend_email_verification_response(success, data, error_info) + "forgot_password": + return handle_forgot_password_response(success, data, error_info) + "reset_password": + return handle_reset_password_response(success, data, error_info) + "network_test": + return handle_network_test_response(success, data, error_info) + _: + # 通用处理 + var result = ResponseResult.new() + if success: + result.success = true + result.message = "✅ 操作成功" + result.toast_type = "success" + else: + result.success = false + result.message = _get_error_message(data.get("error_code", ""), data.get("message", "操作失败"), error_info) + result.toast_type = "error" + return result \ No newline at end of file diff --git a/core/managers/ResponseHandler.gd.uid b/core/managers/ResponseHandler.gd.uid new file mode 100644 index 0000000..cafebb1 --- /dev/null +++ b/core/managers/ResponseHandler.gd.uid @@ -0,0 +1 @@ +uid://ee8i4pdpdlsf