shine-runners-test/addons/very-simple-twitch/network_call.gd
2025-04-21 00:17:07 +10:00

198 lines
5.5 KiB
GDScript

@tool
class_name VSTNetwork_Call extends Node
const CACHE_TIME_IN_SECONDS = 300
# TODO: add dynamic version here
const USER_AGENT = {"User-Agent": "VSTC/0.1.0 (Godot Engine)"}
const CACHE_PATH = "user://very-simple-chat/cache"
var url: String
var timeout: float
var body: String
var headers: Dictionary
var get_params: Dictionary
var on_call_success: Callable
var on_call_fail: Callable
var method: HTTPClient.Method
var use_cache: bool
func _init():
headers = {}
get_params = {}
timeout = 0.0
use_cache = true
func to(url_request: String) -> VSTNetwork_Call:
url = url_request
return self
func with(body_object) -> VSTNetwork_Call:
body = JSON.stringify(body_object)
return self
func in_time(timeout_request: float) -> VSTNetwork_Call:
timeout = timeout_request
return self
func verb(method_request: HTTPClient.Method) -> VSTNetwork_Call:
method = method_request
return self
func no_cache() -> VSTNetwork_Call:
use_cache = false
return self
func add_header(key_header: String, value_header: String) -> VSTNetwork_Call:
headers[key_header] = value_header
return self
func add_all_headers(headers_dic: Dictionary) -> VSTNetwork_Call:
for key in headers_dic:
headers[key] = headers_dic[key]
return self
func add_get_param(key_get_param:String, value_get_param) -> VSTNetwork_Call:
get_params[key_get_param] = str(value_get_param)
return self
func add_all_get_params(get_params_dic: Dictionary) -> VSTNetwork_Call:
for key in get_params_dic:
get_params[key] = get_params_dic[key]
return self
func set_on_call_success(on_call_success_request: Callable) -> VSTNetwork_Call:
on_call_success = on_call_success_request
return self
func set_on_call_fail(on_call_fail_request: Callable) -> VSTNetwork_Call:
on_call_fail = on_call_fail_request
return self
func _pile_headers(headers_to_pile: Dictionary) -> PackedStringArray:
var array:PackedStringArray = []
for key in headers_to_pile:
array.append("%s: %s" % [key, headers_to_pile[key]])
for key in USER_AGENT:
array.append("%s: %s" % [key, USER_AGENT[key]])
return array
func _compile_url(host: String, params_to_pile: Dictionary) -> String:
var final_url:String = host.strip_edges()+"?"
for key in params_to_pile:
var value_safe = str(params_to_pile[key]).uri_encode()
var key_safe = str(key).uri_encode()
final_url += "&%s=%s" % [key_safe, value_safe]
return final_url
func launch_request(parent: Node):
if method == HTTPClient.Method.METHOD_GET:
var final_url = _compile_url(url, get_params)
if use_cache:
var cached_data = read_from_cache(get_key_from_url(final_url))
if !cached_data.is_empty() && on_call_success != null:
on_call_success.call(cached_data)
return
_launch_network_request(parent)
func _launch_network_request(parent: Node):
var data_error = check_request_data()
if data_error != "":
var error:VSTError = VSTError.new(VSTError.VSTCodeError.PARAM_ERROR, data_error)
on_call_fail.call(error)
return
parent.add_child(self)
await get_tree().process_frame
var final_url = _compile_url(url, get_params)
var client = HTTPRequest.new()
client.timeout = timeout
client.request_completed.connect(func():
on_request_completed.bind(final_url)
client.queue_free()
)
add_child(client)
await get_tree().process_frame
var request_error = client.request(final_url, _pile_headers(headers), method, body)
if request_error != OK:
var error:VSTError = VSTError.new(VSTError.VSTCodeError.PARAM_ERROR, "The request can't be archieved reason: "+str(request_error))
on_call_fail.call(error)
client.queue_free()
return
func check_request_data() -> String:
if timeout < 0.0:
push_warning("Timeout can't be less than 0. Setted to 0")
timeout = 0
if !method:
method = HTTPClient.Method.METHOD_GET
if url == null or url.strip_edges() == "":
return "Url can't be empty"
return ""
func get_key_from_url(url:String) -> String:
var last_part_url:String = url.substr(url.rfind("/"))
return last_part_url.sha256_text()
func on_request_completed(_result: int, status: int, _headers: PackedStringArray, body: PackedByteArray, url_request: String):
if (status >= 200 and status < 400):
if method == HTTPClient.Method.METHOD_GET: update_cache(body, get_key_from_url(url_request))
if on_call_success: on_call_success.call(body)
elif (status >= 400 and status < 500):
if on_call_fail:
var info = "%s -> %s" % [str(status), body.get_string_from_utf8()]
var error:VSTError = VSTError.new(VSTError.VSTCodeError.NETWORK_ERROR, info)
on_call_fail.call(error)
elif (status >= 500):
if on_call_fail:
var info = "%s -> %s" % [str(status), body.get_string_from_utf8()]
var error:VSTError = VSTError.new(VSTError.VSTCodeError.SERVER_ERROR, info)
on_call_fail.call(error)
call_deferred("queue_free")
func read_from_cache(key:String) -> PackedByteArray:
var filename: String = CACHE_PATH.path_join(key)
if FileAccess.file_exists(filename): # is a hit on cache?
if FileAccess.get_modified_time(filename)+CACHE_TIME_IN_SECONDS > Time.get_unix_time_from_system(): # is expired?
return FileAccess.get_file_as_bytes(filename)
return []
func update_cache(content:PackedByteArray, key:String):
var filename: String = CACHE_PATH.path_join(key)
DirAccess.make_dir_recursive_absolute(filename.get_base_dir())
var file = FileAccess.open(filename, FileAccess.WRITE)
file.store_buffer(content)
file.close()
func clear_cache():
DirAccess.make_dir_recursive_absolute(CACHE_PATH)
var files:PackedStringArray = DirAccess.get_files_at(CACHE_PATH)
for file in files:
DirAccess.remove_absolute(CACHE_PATH.path_join(file))