extends Node
class_name HTTPEventSource
const URLParser = preload("./utils/urlparser.gd")
signal event(data, event, id)
signal response_started(statusCode, responseHeaders)
var http = HTTPClient.new()
var urlParser = URLParser.new()
func cancel_request():
http.close()
pass
func request(
url,
custom_headers = [],
ssl_validate_domain=true,
method =0,
request_data=""
):
var headers = ["Accept: text/event-stream"]
headers.append_array(custom_headers)
var parsedURL = urlParser.parse(url)
var use_ssl = parsedURL.protocol == 'https'
var params = {
"headers": headers,
"host": parsedURL.host,
"port": parsedURL.port,
"path": parsedURL.path,
"use_ssl": use_ssl,
"verify_host": use_ssl && ssl_validate_domain,
"method": method,
"request_data": request_data
}
print('About to request', parsedURL)
var thread = Thread.new()
thread.start(self,"_runRequest", params)
pass
func _emit_started(statusCode, responseHeaders):
print("Emitting started")
emit_signal("response_started", statusCode, responseHeaders)
func _runRequest(params):
var err = http.connect_to_host(params.host, params.port, params.use_ssl, params.verify_host)
if err != OK:
printerr('Error connecting to EventSource server')
print('Connected to host')
# Wait to establish a connection to the host
while http.get_status() == HTTPClient.STATUS_CONNECTING or http.get_status() == HTTPClient.STATUS_RESOLVING:
err = http.poll()
if err != OK:
printerr('Unable to connect to EventSource')
return
OS.delay_msec(100)
print('Able to connect, requesting')
# Start the request
err = http.request(params.method, params.path, params.headers, params.request_data)
if err != OK:
printerr('Unable to request EventSource')
return
# Wait for request to get processed and to get the body
while (http.get_status() == HTTPClient.STATUS_REQUESTING):
err = http.poll()
if err != OK:
printerr('Unable to request to EventSource')
return
OS.delay_msec(100)
if !http.has_response():
print('No Response')
http.close()
call_deferred("emit_signal", "response_finished")
return
var statusCode = http.get_response_code()
var responseHeaders = http.get_response_headers()
print('Got response ', statusCode)
call_deferred("_emit_started", statusCode, responseHeaders)
var buffer = ""
var lastChunkEmpty = false
var currentEvent = {
"event": "message",
"data": "",
"id": ""
}
while http.get_status() == HTTPClient.STATUS_BODY:
http.poll()
var chunk = http.read_response_body_chunk().get_string_from_utf8()
if(chunk.length() == 0):
var delay = 800 if lastChunkEmpty else 200
lastChunkEmpty = true
OS.delay_usec(delay)
continue
lastChunkEmpty = false
buffer = buffer + chunk
while buffer.find("\n") != -1:
var line = buffer.substr(0, buffer.find("\n"))
buffer = buffer.substr(buffer.find("\n") + 1)
if line.find("data:") == 0: currentEvent["data"] += line.trim_prefix("data:")
if line.find("id:") == 0: currentEvent["id"] = line.trim_prefix("id:")
if line.find("event:") == 0: currentEvent["event"] = line.trim_prefix("event:")
var isEmpty = line.length() == 0
if isEmpty:
call_deferred("emit_signal", "event", currentEvent.data, currentEvent.event, currentEvent.id)
currentEvent = {
"event": "message",
"data": "",
"id": ""
}
http.close()
print('Done!')
call_deferred("emit_signal", "response_finished")
pass
func _emitEvent(params):
emit_signal("event", params.data, params.name, params.id)
pass
func _exit_tree():
cancel_request()