OverviewFilesCommitsIssuesDocsReleasesPeers

hypergodot commits / 345fc40

Added HTTPEventSource, HyperEventSource, updated notes to listen to changes
345fc40235494a540b8fa4a855d8f385e04fbbed
by mauve <ranger@mauve.moe> · 2021-07-23T19:30:34.000Z

Changed files (14) +348 -35

project.godot +28 -0
……@@ -8,6 +8,34 @@
88
99config_version=4
1010
11_global_script_classes=[ {
12"base": "Node",
13"class": "HTTPEventSource",
14"language": "GDScript",
15"path": "res://src/HTTPEventSource.gd"
16}, {
17"base": "HTTPEventSource",
18"class": "HyperEventSource",
19"language": "GDScript",
20"path": "res://src/HyperRequest/HyperEventSource.gd"
21}, {
22"base": "Node",
23"class": "HyperGateway",
24"language": "GDScript",
25"path": "res://src/HyperGateway/HyperGateway.gd"
26}, {
27"base": "HTTPRequest",
28"class": "HyperRequest",
29"language": "GDScript",
30"path": "res://src/HyperRequest/HyperRequest.gd"
31} ]
32_global_script_class_icons={
33"HTTPEventSource": "",
34"HyperEventSource": "",
35"HyperGateway": "",
36"HyperRequest": ""
37}
38
1139[application]
1240
1341config/name="HyperGodot"
src/EventSourceListener/EventSourceListener.gd +31 -0
……@@ -0,0 +1,31 @@
1extends "res://src/ResizeRoot.gd"
2
3onready var output = $ScrollContainer/Output
4onready var urlInput = $HBoxContainer/URLInput
5onready var source = $HTTPEventSource
6
7func _on_URLInput_text_entered(_new_text):
8 connectSource()
9
10func _on_Button_pressed():
11 connectSource()
12
13func outputText(text):
14 output.text += text + '\n'
15
16func connectSource():
17 var url = urlInput.text
18 outputText('Connecting to: ' + url)
19 source.request(url)
20
21func _on_HTTPEventSource_event(data, event, id):
22 print(event, '('+ id + '): ', data)
23 outputText('id: ' + id)
24 outputText('event: ' + event)
25 outputText('data: ' + data)
26
27func _on_HTTPEventSource_response_started(status, _headers):
28 outputText('Response started (Status ' + str(status) + ')')
29
30func _on_HTTPEventSource_response_finished():
31 outputText('Response finished')
src/EventSourceListener/EventSourceListener.tscn +53 -0
……@@ -0,0 +1,53 @@
1[gd_scene load_steps=3 format=2]
2
3[ext_resource path="res://src/EventSourceListener/EventSourceListener.gd" type="Script" id=1]
4[ext_resource path="res://src/HTTPEventSource.gd" type="Script" id=2]
5
6[node name="Control" type="VBoxContainer"]
7anchor_right = 1.0
8anchor_bottom = 1.0
9size_flags_horizontal = 3
10size_flags_vertical = 3
11script = ExtResource( 1 )
12__meta__ = {
13"_edit_use_anchors_": false
14}
15
16[node name="HBoxContainer" type="HBoxContainer" parent="."]
17margin_right = 666.0
18margin_bottom = 24.0
19
20[node name="URLInput" type="LineEdit" parent="HBoxContainer"]
21margin_right = 598.0
22margin_bottom = 24.0
23size_flags_horizontal = 3
24size_flags_vertical = 3
25text = "http://127.0.0.1:42069/example/"
26
27[node name="SubmitButton" type="Button" parent="HBoxContainer"]
28margin_left = 602.0
29margin_right = 666.0
30margin_bottom = 24.0
31text = "Connect"
32
33[node name="ScrollContainer" type="ScrollContainer" parent="."]
34margin_top = 28.0
35margin_right = 666.0
36margin_bottom = 666.0
37size_flags_horizontal = 3
38size_flags_vertical = 3
39
40[node name="Output" type="RichTextLabel" parent="ScrollContainer"]
41margin_right = 666.0
42margin_bottom = 638.0
43size_flags_horizontal = 3
44size_flags_vertical = 3
45
46[node name="HTTPEventSource" type="Node" parent="."]
47script = ExtResource( 2 )
48
49[connection signal="text_entered" from="HBoxContainer/URLInput" to="." method="_on_URLInput_text_entered"]
50[connection signal="pressed" from="HBoxContainer/SubmitButton" to="." method="_on_Button_pressed"]
51[connection signal="event" from="HTTPEventSource" to="." method="_on_HTTPEventSource_event"]
52[connection signal="response_finished" from="HTTPEventSource" to="." method="_on_HTTPEventSource_response_finished"]
53[connection signal="response_started" from="HTTPEventSource" to="." method="_on_HTTPEventSource_response_started"]
src/HTTPEventSource.gd +126 -0
……@@ -0,0 +1,126 @@
1extends Node
2
3class_name HTTPEventSource
4
5const URLParser = preload('./utils/URLParser.gd')
6
7signal event(data, event, id)
8signal response_started(status, headers)
9signal response_finished()
10
11var http = HTTPClient.new()
12var urlParser = URLParser.new()
13
14func cancel_request():
15 http.close()
16 pass
17
18func request(
19 url,
20 custom_headers = [],
21 ssl_validate_domain=true,
22 method =0,
23 request_data=""
24):
25 var headers = ["Accept: text/event-stream"]
26 headers.append_array(custom_headers)
27 var parsedURL = urlParser.parse(url)
28 var use_ssl = parsedURL.protocol == 'https'
29
30 var params = {
31 "headers": headers,
32 "host": parsedURL.host,
33 "port": parsedURL.port,
34 "path": parsedURL.path,
35 "use_ssl": use_ssl,
36 "verify_host": use_ssl && ssl_validate_domain,
37 "method": method,
38 "request_data": request_data
39 }
40
41 print('About to request', parsedURL, params)
42
43 var thread = Thread.new()
44
45 thread.start(self,"_runRequest", params)
46
47 pass
48
49func _runRequest(params):
50 var err = 0
51 http.connect_to_host(params.host, params.port, params.use_ssl, params.verify_host)
52
53 print('Connected to host')
54
55 # Wait to establish a connection to the host
56 while http.get_status() == HTTPClient.STATUS_CONNECTING or http.get_status() == HTTPClient.STATUS_RESOLVING:
57 http.poll()
58 OS.delay_msec(100)
59
60 print('Able to connect, requesting')
61
62 # Start the request
63 err = http.request(params.method, params.path, params.headers, params.request_data)
64
65 # Wait for request to get processed and to get the body
66 while (http.get_status() == HTTPClient.STATUS_REQUESTING):
67 http.poll()
68 OS.delay_msec(100)
69
70 if !http.has_response():
71 print('No Response')
72 http.close()
73 call_deferred("emit_signal", "response_finished")
74 return
75
76 var statusCode = http.get_response_code()
77 var responseHeaders = http.get_response_headers()
78
79 print('Got response ', statusCode)
80
81 call_deferred("emit_signal", "response_started", statusCode, responseHeaders)
82
83 var buffer = ""
84 var lastChunkEmpty = false
85 var currentEvent = {
86 "event": "message",
87 "data": "",
88 "id": ""
89 }
90
91 while http.get_status() == HTTPClient.STATUS_BODY:
92 http.poll()
93 var chunk = http.read_response_body_chunk().get_string_from_utf8()
94 if(chunk.length() == 0):
95 var delay = 800 if lastChunkEmpty else 200
96 lastChunkEmpty = true
97 OS.delay_usec(delay)
98 continue
99 lastChunkEmpty = false
100 buffer = buffer + chunk
101
102 while buffer.find("\n") != -1:
103 var line = buffer.substr(0, buffer.find("\n"))
104 buffer = buffer.substr(buffer.find("\n") + 1)
105
106 if line.find("data:") == 0: currentEvent["data"] += line.trim_prefix("data:")
107 if line.find("id:") == 0: currentEvent["id"] = line.trim_prefix("id:")
108 if line.find("event:") == 0: currentEvent["event"] = line.trim_prefix("event:")
109
110 var isEmpty = line.length() == 0
111 if isEmpty:
112 call_deferred("emit_signal", "event", currentEvent.data, currentEvent.event, currentEvent.id)
113 currentEvent = {
114 "event": "message",
115 "data": "",
116 "id": ""
117 }
118 http.close()
119 print('Done!')
120 call_deferred("emit_signal", "response_finished")
121pass
122
123
124func _emitEvent(params):
125 emit_signal("event", params.data, params.name, params.id)
126 pass
src/HyperGateway/HyperGateway.gd +17 -10
……@@ -1,9 +1,6 @@
11extends Node
22
3
4# Declare member variables here. Examples:
5# var a = 2
6# var b = "text"
3class_name HyperGateway
74
85signal starting_gateway()
96signal started_gateway(pid)
……@@ -12,6 +9,8 @@ export var processPID = 0
129export var serverPrefix = "http://127.0.0.1:4973/hyper/"
1310export var storageDirectory = 'user://gateway-data/'
1411export var autoStart = false
12export var writable = true
13export var persist = true
1514
1615func _notification(what):
1716 if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
……@@ -30,18 +29,26 @@ func cleanupGateway():
3029 print('Cleaning up gateway ' + str(processPID))
3130 OS.kill(processPID)
3231 pass
32
33func _resolvePath(path):
34 var file = File.new()
35 file.open(path, File.READ)
36 var finalPath = file.get_path_absolute()
37 file.close()
38 return finalPath
3339
3440func setupGateway():
3541 emit_signal("starting_gateway")
3642 var executiblePath = getExecutiblePath()
37 var executibleFile = File.new()
43 var path = _resolvePath(executiblePath)
3844
39 executibleFile.open(executiblePath, File.READ)
45 var args = ["run"]
46 if !persist: args.append('--no-persist')
47 if writable: args.append('--writable')
4048
41 var path = executibleFile.get_path_absolute()
42 executibleFile.close()
43
44 var args = ["run", "--no-persist"]
49 var resolvedStorageDirectory = _resolvePath(storageDirectory)
50 args.append('--storage-location')
51 args.append(resolvedStorageDirectory)
4552
4653 print("Starting gateway from " + path)
4754
src/HyperLoad/HyperLoad.tscn +1 -1
……@@ -88,5 +88,5 @@ autoStart = true
8888[connection signal="started_gateway" from="HyperGateway" to="StatusLabel" method="setGatewayLoaded"]
8989[connection signal="starting_gateway" from="HyperGateway" to="StatusLabel" method="setGatewayLoading"]
9090[connection signal="loading_data" from="HyperGateway/HyperRequest" to="StatusLabel" method="setLoading"]
91[connection signal="request_completed" from="HyperGateway/HyperRequest" to="ScrollContainer/Output" method="_on_HyperLoad_request_completed"]
9291[connection signal="request_completed" from="HyperGateway/HyperRequest" to="StatusLabel" method="_on_HyperLoad_request_completed"]
92[connection signal="request_completed" from="HyperGateway/HyperRequest" to="ScrollContainer/Output" method="_on_HyperLoad_request_completed"]
src/HyperNotes/FileChanges.gd +11 -0
……@@ -0,0 +1,11 @@
1extends HyperEventSource
2
3signal change
4
5func listen(path):
6 request(path)
7
8func _on_FileChanges_event(data, event, id):
9 print('Event ', event, data)
10 if event == "change":
11 emit_signal("change")
src/HyperNotes/HyperNotes.gd +14 -6
……@@ -6,6 +6,14 @@ onready var loader = $HyperGateway/GetContent
66onready var filePathInput = $HBoxContainer/VBoxContainer/HBoxContainer/FilePathInput
77onready var fileLister = $HyperGateway/ListFiles
88onready var fileTree = $HBoxContainer/Files
9onready var fileChanges = $HyperGateway/FileChanges
10
11export var source = "hyper://notes/"
12
13func _ready():
14 fileChanges.request(source)
15 fileLister.list(source)
16 loader.getContent(filePathInput.text)
917
1018func _on_SaveButton_pressed():
1119 saver.save(filePathInput.text, fileContent.text)
……@@ -19,10 +27,6 @@ func _on_GetContent_content(content):
1927 fileContent.text = content
2028 pass # Replace with function body.
2129
22func _on_SaveContent_saved():
23 fileLister.list()
24 pass # Replace with function body.
25
2630func _on_ListFiles_files(files):
2731 fileTree.clear()
2832 if files.size() == 0:
……@@ -31,7 +35,7 @@ func _on_ListFiles_files(files):
3135 return
3236
3337 var root = fileTree.create_item()
34 root.set_text(0, "hyper://notes/")
38 root.set_text(0, source)
3539 for file in files:
3640 var child = fileTree.create_item(root)
3741 child.set_text(0, file)
……@@ -40,10 +44,14 @@ func _on_ListFiles_files(files):
4044func _on_Files_item_selected():
4145 var item = fileTree.get_selected()
4246 var text = item.get_text(0)
43 var path = 'hyper://notes/' + text
47 var path = source + text
4448
4549 print('Loading', path)
4650
4751 filePathInput.text = path
4852 loader.getContent(path)
4953 pass # Replace with function body.
54
55func _on_FileChanges_change():
56 fileLister.list(source)
57 pass # Replace with function body.
src/HyperNotes/HyperNotes.tscn +7 -2
……@@ -1,6 +1,7 @@
1[gd_scene load_steps=7 format=2]
1[gd_scene load_steps=8 format=2]
22
33[ext_resource path="res://src/HyperNotes/HyperNotes.gd" type="Script" id=1]
4[ext_resource path="res://src/HyperNotes/FileChanges.gd" type="Script" id=2]
45[ext_resource path="res://src/HyperRequest/HyperRequest.tscn" type="PackedScene" id=3]
56[ext_resource path="res://src/HyperNotes/ListFiles.gd" type="Script" id=4]
67[ext_resource path="res://src/HyperGateway/HyperGateway.tscn" type="PackedScene" id=5]
……@@ -77,6 +78,9 @@ script = ExtResource( 6 )
7778[node name="SaveContent" parent="HyperGateway" instance=ExtResource( 3 )]
7879script = ExtResource( 8 )
7980
81[node name="FileChanges" type="Node" parent="HyperGateway"]
82script = ExtResource( 2 )
83
8084[connection signal="item_selected" from="HBoxContainer/Files" to="." method="_on_Files_item_selected"]
8185[connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/SaveButton" to="." method="_on_SaveButton_pressed"]
8286[connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/LoadButton" to="." method="_on_LoadButton_pressed"]
……@@ -85,4 +89,5 @@ script = ExtResource( 8 )
8589[connection signal="content" from="HyperGateway/GetContent" to="." method="_on_GetContent_content"]
8690[connection signal="request_completed" from="HyperGateway/GetContent" to="HyperGateway/GetContent" method="_on_GetContent_request_completed"]
8791[connection signal="request_completed" from="HyperGateway/SaveContent" to="HyperGateway/SaveContent" method="_on_SaveContent_request_completed"]
88[connection signal="saved" from="HyperGateway/SaveContent" to="." method="_on_SaveContent_saved"]
92[connection signal="change" from="HyperGateway/FileChanges" to="." method="_on_FileChanges_change"]
93[connection signal="event" from="HyperGateway/FileChanges" to="HyperGateway/FileChanges" method="_on_FileChanges_event"]
src/HyperNotes/ListFiles.gd +2 -14
……@@ -2,29 +2,17 @@ extends "res://src/HyperRequest/HyperRequest.gd"
22
33signal files(files)
44
5export var folder = 'hyper://notes/'
6
7func _ready():
8 list()
9 pass # Replace with function body.
10
11func list(path=folder):
5func list(path):
126 request(path + "?noResolve")
137 pass
148
159func _on_ListFiles_request_completed(result, response_code, headers, body):
16 print('Loaded', response_code)
17
1810 if response_code != 200: return
1911
2012 var content = body.get_string_from_utf8()
21
22 print("Loaded directory listing", content)
23
13
2414 var json = JSON.parse(content)
2515
26 print("Loaded JSON", json)
27
2816 if json.error != OK: return printerr(json.error_string)
2917
3018 emit_signal("files", json.result)
src/HyperNotes/SaveContent.gd +1 -2
……@@ -3,7 +3,7 @@ extends "res://src/HyperRequest/HyperRequest.gd"
33signal saved
44
55func save(path, content):
6 print("Saving", path, content)
6 print("Saving ", path, " ", content)
77 self.request(
88 path,
99 PoolStringArray(["Content-Type: text/plain"]),
……@@ -13,7 +13,6 @@ func save(path, content):
1313 )
1414 pass
1515
16
1716func _on_SaveContent_request_completed(result, response_code, headers, body):
1817 if response_code == 200: emit_signal("saved")
1918 else: printerr(body.get_string_from_utf8())
src/HyperRequest/HyperEventSource.gd +21 -0
……@@ -0,0 +1,21 @@
1extends HTTPEventSource
2
3class_name HyperEventSource
4
5signal loading_data(url)
6
7export var serverPrefix = "http://127.0.0.1:4973/hyper/"
8
9var watching = false
10
11func request(
12 url,
13 custom_headers=PoolStringArray( ),
14 ssl_validate_domain=false,
15 method=HTTPClient.METHOD_GET, request_data=""
16):
17 assert(url.begins_with("hyper://"))
18 var toLoad = url.replace("hyper://", serverPrefix)
19 emit_signal('loading_data', url)
20 .request(toLoad, custom_headers, ssl_validate_domain, method, request_data)
21pass
src/HyperRequest/HyperRequest.gd +4 -0
……@@ -1,9 +1,13 @@
11extends HTTPRequest
22
3class_name HyperRequest
4
35signal loading_data(url)
46
57export var serverPrefix = "http://127.0.0.1:4973/hyper/"
68
9var watching = false
10
711func request(
812 url,
913 custom_headers=PoolStringArray( ),
src/utils/URLParser.gd +32 -0
……@@ -0,0 +1,32 @@
1var urlParseRegex = RegEx.new()
2
3const DEFAULT_PORTS = {
4 "http": 80,
5 "https": 443
6}
7
8func _init():
9 urlParseRegex.compile("([^:]+)://([^/]+)(/?.*)")
10
11func parse(url):
12 var parsed = urlParseRegex.search(url)
13
14 if !parsed: return null
15
16 var protocol = parsed.get_string(1).to_lower()
17 var raw_host = parsed.get_string(2)
18 var path = parsed.get_string(3)
19 var host = raw_host
20 var port = DEFAULT_PORTS[protocol]
21
22 if ":" in raw_host:
23 var split = raw_host.split(':')
24 host = split[0]
25 port = split[1].to_int()
26
27 return {
28 "protocol": protocol,
29 "host": host,
30 "port": port,
31 "path": path
32 }