Closes #38, #39 and #40; adds the client side of #41. - Every request goes to /api/v1. MusicServerClient gets a token with Settings.api_password the first time one is needed, reuses it, and on a 401 gets a new one and sends the request once more. Switching server gets a new token too. Callers never see the token. - Sync is started with POST, as MusicServer 5.0 requires. - The client has every endpoint in the server's OpenAPI spec, including statistics, soundtracks and songs by UUID, version, downloads and tokens. - tools/generate_api_types.gd generates a typed class per schema in server/openapi.json into server/generated/. Song info, statistics and versions are passed to callers as these classes. A list the server sends as null is an empty list. - FakeHttpTransport hands out tokens and answers 401 without one, so every test goes through the token flow. New tests cover the token handling, every endpoint and each generated class.
51 lines
1.7 KiB
GDScript
51 lines
1.7 KiB
GDScript
class_name HttpTransport
|
|
extends RefCounted
|
|
## Sends HTTP requests for [code]MusicServerClient[/code] using [HTTPRequest] nodes.
|
|
##
|
|
## Tests subclass this to answer requests without a network connection.
|
|
|
|
## Seconds before a request is given up and reported as failed. This covers the whole
|
|
## download, so it is generous enough for long songs on a slow connection.
|
|
|
|
var timeout_seconds: float = 120.0
|
|
var _owner: Node
|
|
|
|
|
|
func _init(owner: Node) -> void:
|
|
_owner = owner
|
|
|
|
|
|
## Requests [param url] and calls [param on_complete] with
|
|
## [code](response_code: int, body: PackedByteArray)[/code]. Connection errors and
|
|
## timeouts are reported with response code 0. [param headers] are sent as-is; a
|
|
## [param body] is sent as JSON.
|
|
func request(
|
|
url: String,
|
|
method: int,
|
|
on_complete: Callable,
|
|
headers: PackedStringArray = PackedStringArray(),
|
|
body: String = "",
|
|
) -> void:
|
|
var http_request: HTTPRequest = HTTPRequest.new()
|
|
http_request.timeout = timeout_seconds
|
|
_owner.add_child(http_request)
|
|
http_request.request_completed.connect(
|
|
func(
|
|
result: int,
|
|
response_code: int,
|
|
_headers: PackedStringArray,
|
|
response_body: PackedByteArray,
|
|
) -> void:
|
|
http_request.queue_free()
|
|
on_complete.call(response_code if result == HTTPRequest.RESULT_SUCCESS else 0,
|
|
response_body)
|
|
)
|
|
var all_headers: PackedStringArray = headers.duplicate()
|
|
if method == HTTPClient.METHOD_PUT || !body.is_empty():
|
|
all_headers.append("Content-Type: application/json")
|
|
var error: int = http_request.request(url, all_headers, method, body)
|
|
if error != OK:
|
|
http_request.queue_free()
|
|
push_error("Could not send request to %s (error %d)" % [url, error])
|
|
on_complete.call(0, PackedByteArray())
|