added firebase and rudimentary leaderboard support
This commit is contained in:
129
addons/http-sse-client/HTTPSSEClient.gd
Normal file
129
addons/http-sse-client/HTTPSSEClient.gd
Normal file
@@ -0,0 +1,129 @@
|
||||
@tool
|
||||
extends Node
|
||||
|
||||
signal new_sse_event(headers, event, data)
|
||||
signal connected
|
||||
signal connection_error(error)
|
||||
|
||||
const event_tag = "event:"
|
||||
const data_tag = "data:"
|
||||
const continue_internal = "continue_internal"
|
||||
|
||||
var httpclient = HTTPClient.new()
|
||||
var is_connected = false
|
||||
|
||||
var domain
|
||||
var url_after_domain
|
||||
var port
|
||||
var trusted_chain
|
||||
var common_name_override
|
||||
var told_to_connect = false
|
||||
var connection_in_progress = false
|
||||
var is_requested = false
|
||||
var response_body = PackedByteArray()
|
||||
|
||||
func connect_to_host(domain : String, url_after_domain : String, port : int = -1, trusted_chain : X509Certificate = null, common_name_override : String = ""):
|
||||
process_mode = Node.PROCESS_MODE_INHERIT
|
||||
self.domain = domain
|
||||
self.url_after_domain = url_after_domain
|
||||
self.port = port
|
||||
self.trusted_chain = trusted_chain
|
||||
self.common_name_override = common_name_override
|
||||
told_to_connect = true
|
||||
|
||||
func attempt_to_connect():
|
||||
var tls_options = TLSOptions.client(trusted_chain, common_name_override)
|
||||
var err = httpclient.connect_to_host(domain, port, tls_options)
|
||||
if err == OK:
|
||||
connected.emit()
|
||||
is_connected = true
|
||||
else:
|
||||
connection_error.emit(str(err))
|
||||
|
||||
func attempt_to_request(httpclient_status):
|
||||
if httpclient_status == HTTPClient.STATUS_CONNECTING or httpclient_status == HTTPClient.STATUS_RESOLVING:
|
||||
return
|
||||
|
||||
if httpclient_status == HTTPClient.STATUS_CONNECTED:
|
||||
var err = httpclient.request(HTTPClient.METHOD_POST, url_after_domain, ["Accept: text/event-stream"])
|
||||
if err == OK:
|
||||
is_requested = true
|
||||
|
||||
func _parse_response_body(headers):
|
||||
var body = response_body.get_string_from_utf8()
|
||||
if body:
|
||||
var event_data = get_event_data(body)
|
||||
if event_data.event != "keep-alive" and event_data.event != continue_internal:
|
||||
var result = Utilities.get_json_data(event_data.data)
|
||||
if result != null:
|
||||
var parsed_text = result
|
||||
if response_body.size() > 0: # stop here if the value doesn't parse
|
||||
response_body.resize(0)
|
||||
new_sse_event.emit(headers, event_data.event, result)
|
||||
else:
|
||||
if event_data.event != continue_internal:
|
||||
response_body.resize(0)
|
||||
|
||||
func _process(delta):
|
||||
if !told_to_connect:
|
||||
return
|
||||
|
||||
if !is_connected:
|
||||
if !connection_in_progress:
|
||||
attempt_to_connect()
|
||||
connection_in_progress = true
|
||||
return
|
||||
|
||||
httpclient.poll()
|
||||
var httpclient_status = httpclient.get_status()
|
||||
if !is_requested:
|
||||
attempt_to_request(httpclient_status)
|
||||
return
|
||||
|
||||
if httpclient.has_response() or httpclient_status == HTTPClient.STATUS_BODY:
|
||||
var headers = httpclient.get_response_headers_as_dictionary()
|
||||
|
||||
if httpclient_status == HTTPClient.STATUS_BODY:
|
||||
httpclient.poll()
|
||||
var chunk = httpclient.read_response_body_chunk()
|
||||
if(chunk.size() == 0):
|
||||
return
|
||||
else:
|
||||
response_body = response_body + chunk
|
||||
|
||||
_parse_response_body(headers)
|
||||
|
||||
elif Firebase.emulating and Firebase._config.workarounds.database_connection_closed_issue:
|
||||
# Emulation does not send the close connection header currently, so we need to manually read the response body
|
||||
# see issue https://github.com/firebase/firebase-tools/issues/3329 in firebase-tools
|
||||
# also comment https://github.com/GodotNuts/GodotFirebase/issues/154#issuecomment-831377763 which explains the issue
|
||||
while httpclient.connection.get_available_bytes():
|
||||
var data = httpclient.connection.get_partial_data(1)
|
||||
if data[0] == OK:
|
||||
response_body.append_array(data[1])
|
||||
if response_body.size() > 0:
|
||||
_parse_response_body(headers)
|
||||
|
||||
func get_event_data(body : String):
|
||||
var result = {}
|
||||
var event_idx = body.find(event_tag)
|
||||
if event_idx == -1:
|
||||
result["event"] = continue_internal
|
||||
return result
|
||||
assert(event_idx != -1)
|
||||
var data_idx = body.find(data_tag, event_idx + event_tag.length())
|
||||
assert(data_idx != -1)
|
||||
var event = body.substr(event_idx, data_idx)
|
||||
var event_value = event.replace(event_tag, "").strip_edges()
|
||||
assert(event_value)
|
||||
assert(event_value.length() > 0)
|
||||
result["event"] = event_value
|
||||
var data = body.right(body.length() - (data_idx + data_tag.length())).strip_edges()
|
||||
assert(data)
|
||||
assert(data.length() > 0)
|
||||
result["data"] = data
|
||||
return result
|
||||
|
||||
func _exit_tree():
|
||||
if httpclient:
|
||||
httpclient.close()
|
||||
Reference in New Issue
Block a user