extends Node signal missions_changed signal missions_failed(message: String) const EndpointConfig := preload("res://scripts/autoload/api_endpoint_config.gd") const DEFAULT_URL := "https://us3q.ranaze.com/api/daily-missions" var api_url := DEFAULT_URL var request: HTTPRequest var state: Dictionary = {} var loading := false var pending_action := "" func _ready() -> void: api_url = EndpointConfig.resolve(DEFAULT_URL, "/api/daily-missions") request = HTTPRequest.new() request.timeout = 20.0 request.request_completed.connect(_on_completed) add_child(request) AuthState.auth_changed.connect(_on_auth_changed) set_process(true) func refresh() -> void: if loading or not AuthState.can_send_authenticated_request(): return _send("refresh", HTTPClient.METHOD_GET, "") func replace(mission_id: String) -> void: if loading or mission_id.is_empty() or not AuthState.can_send_authenticated_request(): return _send("replace", HTTPClient.METHOD_POST, "/%s/replace" % mission_id.uri_encode()) func apply_response(parsed: Dictionary) -> void: var next_state: Variant = parsed.get("dailyMissions", null) if typeof(next_state) == TYPE_DICTIONARY: state = next_state missions_changed.emit() func _send(action: String, method: int, suffix: String) -> void: loading = true pending_action = action var headers := PackedStringArray(["Authorization: Bearer %s" % AuthState.access_token]) var error := request.request(api_url + suffix, headers, method) if error != OK: loading = false pending_action = "" missions_failed.emit("Daily missions could not be loaded.") func _on_completed(result: int, response_code: int, _headers: PackedStringArray, body: PackedByteArray) -> void: loading = false pending_action = "" if response_code == 401: AuthState.handle_unauthorized(AuthState.access_token) return if result != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300: missions_failed.emit("Daily mission request failed.") return var parsed: Variant = JSON.parse_string(body.get_string_from_utf8()) if typeof(parsed) != TYPE_DICTIONARY or typeof(parsed.get("state", null)) != TYPE_DICTIONARY: missions_failed.emit("The daily mission response was invalid.") return state = parsed.get("state", {}) CreditsService.apply_award_response(parsed) missions_changed.emit() func _process(_delta: float) -> void: if state.is_empty() or loading or not AuthState.can_send_authenticated_request(): return var expires := Time.get_unix_time_from_datetime_string(str(state.get("expiresUtc", "")).trim_suffix("Z")) if expires > 0 and Time.get_unix_time_from_system() >= expires: state = {} refresh() func _on_auth_changed() -> void: if not AuthState.is_logged_in: state = {} loading = false if request.get_http_client_status() != HTTPClient.STATUS_DISCONNECTED: request.cancel_request()