-
Notifications
You must be signed in to change notification settings - Fork 5
/
HTTPSSEClient.gd
119 lines (101 loc) · 3.74 KB
/
HTTPSSEClient.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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 use_ssl
var verify_host
var told_to_connect = false
var connection_in_progress = false
var request_in_progress = false
var is_requested = false
var response_body = PoolByteArray()
func connect_to_host(domain : String, url_after_domain : String, port : int = -1, use_ssl : bool = false, verify_host : bool = true):
self.domain = domain
self.url_after_domain = url_after_domain
self.port = port
self.use_ssl = use_ssl
self.verify_host = verify_host
told_to_connect = true
func attempt_to_connect():
var err = httpclient.connect_to_host(domain, port, use_ssl, verify_host)
if err == OK:
emit_signal("connected")
is_connected = true
else:
emit_signal("connection_error", 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 _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:
if !request_in_progress:
attempt_to_request(httpclient_status)
return
var httpclient_has_response = httpclient.has_response()
if httpclient_has_response or httpclient_status == HTTPClient.STATUS_BODY:
var headers = httpclient.get_response_headers_as_dictionary()
httpclient.poll()
var chunk = httpclient.read_response_body_chunk()
if(chunk.size() == 0):
return
else:
response_body = response_body + chunk
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 = JSON.parse(event_data.data).result
if response_body.size() > 0 and result: # stop here if the value doesn't parse
response_body.resize(0)
emit_signal("new_sse_event", headers, event_data.event, result)
else:
if event_data.event != continue_internal:
response_body.resize(0)
func get_event_data(body : String) -> Dictionary:
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)
event = event.replace(event_tag, "").strip_edges()
assert(event)
assert(event.length() > 0)
result["event"] = event
var data = body.right(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()
func _notification(what):
if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
if httpclient:
httpclient.close()
get_tree().quit()