198 lines
5.5 KiB
GDScript
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))
|