extends Node const EndpointConfig := preload("res://scripts/autoload/api_endpoint_config.gd") const DEFAULT_API_URL := "https://us3q.ranaze.com/api/dynamic-questions" signal status_loaded(status: Dictionary) signal question_loaded(question: Dictionary) signal attempt_completed(result: Dictionary) signal report_submitted(question_id: String, report_id: String) signal report_failed(question_id: String, message: String) signal request_failed(message: String) var api_url := DEFAULT_API_URL var run_token := "" var generation_token := "" var current_envelope := {} var _request: HTTPRequest var _operation := "" var _report_question_id := "" func _ready() -> void: api_url = EndpointConfig.resolve( str(ProjectSettings.get_setting("step3/dynamic_questions_api_url", DEFAULT_API_URL)), "/api/dynamic-questions") _request = HTTPRequest.new() _request.timeout = 30.0 _request.request_completed.connect(_on_completed) add_child(_request) func load_status() -> void: _send("status", HTTPClient.METHOD_GET, "/status", {}) func load_next() -> void: _send("next", HTTPClient.METHOD_POST, "/next", {"runToken": run_token}) func submit_attempt(choice_id: String, duration_seconds: int, is_skip := false) -> void: _send("attempt", HTTPClient.METHOD_POST, "/attempt", { "generationToken": generation_token, "choiceId": choice_id, "isSkip": is_skip, "durationSeconds": duration_seconds }) func submit_report(question_id: String, category: String, details: String) -> void: _report_question_id = question_id _send("report", HTTPClient.METHOD_POST, "/report", { "generationToken": generation_token, "category": category, "details": details }) func reset_run() -> void: run_token = "" generation_token = "" current_envelope = {} func _send(operation: String, method: int, suffix: String, payload: Dictionary) -> void: if not AuthState.can_send_authenticated_request(): request_failed.emit("Log in to use Dynamic Questions.") return if _request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED: return _operation = operation var headers := PackedStringArray([ "Content-Type: application/json", "Authorization: Bearer %s" % AuthState.access_token ]) var body := "" if method == HTTPClient.METHOD_GET else JSON.stringify(payload) var error := _request.request(api_url + suffix, headers, method, body) if error != OK: _operation = "" request_failed.emit("Could not connect to Dynamic Questions.") func _on_completed(_result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void: var operation := _operation _operation = "" var parsed: Variant = JSON.parse_string(body.get_string_from_utf8()) if response_code < 200 or response_code >= 300 or typeof(parsed) != TYPE_DICTIONARY: var message := str(parsed) if parsed != null else "Dynamic Questions request failed." if operation == "report": report_failed.emit(_report_question_id, message) else: request_failed.emit(message) return var data: Dictionary = parsed match operation: "status": status_loaded.emit(data) "next": run_token = str(data.get("runToken", "")) generation_token = str(data.get("generationToken", "")) current_envelope = data var question := QuestionBankService.normalize_api_question(data.get("question", {})) question["_dynamic_objective_id"] = str(data.get("objectiveId", "")) question["_dynamic_objective_title"] = str(data.get("objectiveTitle", "")) question_loaded.emit(question) "attempt": attempt_completed.emit(data) "report": report_submitted.emit(_report_question_id, str(data.get("id", "")))