| … | … | @@ -8,6 +8,34 @@ |
| 8 | 8 | |
| 9 | 9 | config_version=4 |
| 10 | 10 | |
| 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 | ||
| 11 | 39 | [application] |
| 12 | 40 | |
| 13 | 41 | config/name="HyperGodot" |
| … | … | @@ -0,0 +1,31 @@ |
| 1 | extends "res://src/ResizeRoot.gd" | |
| 2 | ||
| 3 | onready var output = $ScrollContainer/Output | |
| 4 | onready var urlInput = $HBoxContainer/URLInput | |
| 5 | onready var source = $HTTPEventSource | |
| 6 | ||
| 7 | func _on_URLInput_text_entered(_new_text): | |
| 8 | connectSource() | |
| 9 | ||
| 10 | func _on_Button_pressed(): | |
| 11 | connectSource() | |
| 12 | ||
| 13 | func outputText(text): | |
| 14 | output.text += text + '\n' | |
| 15 | ||
| 16 | func connectSource(): | |
| 17 | var url = urlInput.text | |
| 18 | outputText('Connecting to: ' + url) | |
| 19 | source.request(url) | |
| 20 | ||
| 21 | func _on_HTTPEventSource_event(data, event, id): | |
| 22 | print(event, '('+ id + '): ', data) | |
| 23 | outputText('id: ' + id) | |
| 24 | outputText('event: ' + event) | |
| 25 | outputText('data: ' + data) | |
| 26 | ||
| 27 | func _on_HTTPEventSource_response_started(status, _headers): | |
| 28 | outputText('Response started (Status ' + str(status) + ')') | |
| 29 | ||
| 30 | func _on_HTTPEventSource_response_finished(): | |
| 31 | outputText('Response finished') |
| … | … | @@ -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"] | |
| 7 | anchor_right = 1.0 | |
| 8 | anchor_bottom = 1.0 | |
| 9 | size_flags_horizontal = 3 | |
| 10 | size_flags_vertical = 3 | |
| 11 | script = ExtResource( 1 ) | |
| 12 | __meta__ = { | |
| 13 | "_edit_use_anchors_": false | |
| 14 | } | |
| 15 | ||
| 16 | [node name="HBoxContainer" type="HBoxContainer" parent="."] | |
| 17 | margin_right = 666.0 | |
| 18 | margin_bottom = 24.0 | |
| 19 | ||
| 20 | [node name="URLInput" type="LineEdit" parent="HBoxContainer"] | |
| 21 | margin_right = 598.0 | |
| 22 | margin_bottom = 24.0 | |
| 23 | size_flags_horizontal = 3 | |
| 24 | size_flags_vertical = 3 | |
| 25 | text = "http://127.0.0.1:42069/example/" | |
| 26 | ||
| 27 | [node name="SubmitButton" type="Button" parent="HBoxContainer"] | |
| 28 | margin_left = 602.0 | |
| 29 | margin_right = 666.0 | |
| 30 | margin_bottom = 24.0 | |
| 31 | text = "Connect" | |
| 32 | ||
| 33 | [node name="ScrollContainer" type="ScrollContainer" parent="."] | |
| 34 | margin_top = 28.0 | |
| 35 | margin_right = 666.0 | |
| 36 | margin_bottom = 666.0 | |
| 37 | size_flags_horizontal = 3 | |
| 38 | size_flags_vertical = 3 | |
| 39 | ||
| 40 | [node name="Output" type="RichTextLabel" parent="ScrollContainer"] | |
| 41 | margin_right = 666.0 | |
| 42 | margin_bottom = 638.0 | |
| 43 | size_flags_horizontal = 3 | |
| 44 | size_flags_vertical = 3 | |
| 45 | ||
| 46 | [node name="HTTPEventSource" type="Node" parent="."] | |
| 47 | script = 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"] |
| … | … | @@ -0,0 +1,126 @@ |
| 1 | extends Node | |
| 2 | ||
| 3 | class_name HTTPEventSource | |
| 4 | ||
| 5 | const URLParser = preload('./utils/URLParser.gd') | |
| 6 | ||
| 7 | signal event(data, event, id) | |
| 8 | signal response_started(status, headers) | |
| 9 | signal response_finished() | |
| 10 | ||
| 11 | var http = HTTPClient.new() | |
| 12 | var urlParser = URLParser.new() | |
| 13 | ||
| 14 | func cancel_request(): | |
| 15 | http.close() | |
| 16 | pass | |
| 17 | ||
| 18 | func 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 | ||
| 49 | func _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") | |
| 121 | pass | |
| 122 | ||
| 123 | ||
| 124 | func _emitEvent(params): | |
| 125 | emit_signal("event", params.data, params.name, params.id) | |
| 126 | pass |
| … | … | @@ -1,9 +1,6 @@ |
| 1 | 1 | extends Node |
| 2 | 2 | |
| 3 | ||
| 4 | # Declare member variables here. Examples: | |
| 5 | # var a = 2 | |
| 6 | # var b = "text" | |
| 3 | class_name HyperGateway | |
| 7 | 4 | |
| 8 | 5 | signal starting_gateway() |
| 9 | 6 | signal started_gateway(pid) |
| … | … | @@ -12,6 +9,8 @@ export var processPID = 0 |
| 12 | 9 | export var serverPrefix = "http://127.0.0.1:4973/hyper/" |
| 13 | 10 | export var storageDirectory = 'user://gateway-data/' |
| 14 | 11 | export var autoStart = false |
| 12 | export var writable = true | |
| 13 | export var persist = true | |
| 15 | 14 | |
| 16 | 15 | func _notification(what): |
| 17 | 16 | if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST: |
| … | … | @@ -30,18 +29,26 @@ func cleanupGateway(): |
| 30 | 29 | print('Cleaning up gateway ' + str(processPID)) |
| 31 | 30 | OS.kill(processPID) |
| 32 | 31 | pass |
| 32 | ||
| 33 | func _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 | |
| 33 | 39 | |
| 34 | 40 | func setupGateway(): |
| 35 | 41 | emit_signal("starting_gateway") |
| 36 | 42 | var executiblePath = getExecutiblePath() |
| 37 | var executibleFile = File.new() | |
| 43 | var path = _resolvePath(executiblePath) | |
| 38 | 44 | |
| 39 | executibleFile.open(executiblePath, File.READ) | |
| 45 | var args = ["run"] | |
| 46 | if !persist: args.append('--no-persist') | |
| 47 | if writable: args.append('--writable') | |
| 40 | 48 | |
| 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) | |
| 45 | 52 | |
| 46 | 53 | print("Starting gateway from " + path) |
| 47 | 54 |
| … | … | @@ -88,5 +88,5 @@ autoStart = true |
| 88 | 88 | [connection signal="started_gateway" from="HyperGateway" to="StatusLabel" method="setGatewayLoaded"] |
| 89 | 89 | [connection signal="starting_gateway" from="HyperGateway" to="StatusLabel" method="setGatewayLoading"] |
| 90 | 90 | [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"] | |
| 92 | 91 | [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"] |
| … | … | @@ -0,0 +1,11 @@ |
| 1 | extends HyperEventSource | |
| 2 | ||
| 3 | signal change | |
| 4 | ||
| 5 | func listen(path): | |
| 6 | request(path) | |
| 7 | ||
| 8 | func _on_FileChanges_event(data, event, id): | |
| 9 | print('Event ', event, data) | |
| 10 | if event == "change": | |
| 11 | emit_signal("change") |
| … | … | @@ -6,6 +6,14 @@ onready var loader = $HyperGateway/GetContent |
| 6 | 6 | onready var filePathInput = $HBoxContainer/VBoxContainer/HBoxContainer/FilePathInput |
| 7 | 7 | onready var fileLister = $HyperGateway/ListFiles |
| 8 | 8 | onready var fileTree = $HBoxContainer/Files |
| 9 | onready var fileChanges = $HyperGateway/FileChanges | |
| 10 | ||
| 11 | export var source = "hyper://notes/" | |
| 12 | ||
| 13 | func _ready(): | |
| 14 | fileChanges.request(source) | |
| 15 | fileLister.list(source) | |
| 16 | loader.getContent(filePathInput.text) | |
| 9 | 17 | |
| 10 | 18 | func _on_SaveButton_pressed(): |
| 11 | 19 | saver.save(filePathInput.text, fileContent.text) |
| … | … | @@ -19,10 +27,6 @@ func _on_GetContent_content(content): |
| 19 | 27 | fileContent.text = content |
| 20 | 28 | pass # Replace with function body. |
| 21 | 29 | |
| 22 | func _on_SaveContent_saved(): | |
| 23 | fileLister.list() | |
| 24 | pass # Replace with function body. | |
| 25 | ||
| 26 | 30 | func _on_ListFiles_files(files): |
| 27 | 31 | fileTree.clear() |
| 28 | 32 | if files.size() == 0: |
| … | … | @@ -31,7 +35,7 @@ func _on_ListFiles_files(files): |
| 31 | 35 | return |
| 32 | 36 | |
| 33 | 37 | var root = fileTree.create_item() |
| 34 | root.set_text(0, "hyper://notes/") | |
| 38 | root.set_text(0, source) | |
| 35 | 39 | for file in files: |
| 36 | 40 | var child = fileTree.create_item(root) |
| 37 | 41 | child.set_text(0, file) |
| … | … | @@ -40,10 +44,14 @@ func _on_ListFiles_files(files): |
| 40 | 44 | func _on_Files_item_selected(): |
| 41 | 45 | var item = fileTree.get_selected() |
| 42 | 46 | var text = item.get_text(0) |
| 43 | var path = 'hyper://notes/' + text | |
| 47 | var path = source + text | |
| 44 | 48 | |
| 45 | 49 | print('Loading', path) |
| 46 | 50 | |
| 47 | 51 | filePathInput.text = path |
| 48 | 52 | loader.getContent(path) |
| 49 | 53 | pass # Replace with function body. |
| 54 | ||
| 55 | func _on_FileChanges_change(): | |
| 56 | fileLister.list(source) | |
| 57 | pass # Replace with function body. |
| … | … | @@ -1,6 +1,7 @@ |
| 1 | [gd_scene load_steps=7 format=2] | |
| 1 | [gd_scene load_steps=8 format=2] | |
| 2 | 2 | |
| 3 | 3 | [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] | |
| 4 | 5 | [ext_resource path="res://src/HyperRequest/HyperRequest.tscn" type="PackedScene" id=3] |
| 5 | 6 | [ext_resource path="res://src/HyperNotes/ListFiles.gd" type="Script" id=4] |
| 6 | 7 | [ext_resource path="res://src/HyperGateway/HyperGateway.tscn" type="PackedScene" id=5] |
| … | … | @@ -77,6 +78,9 @@ script = ExtResource( 6 ) |
| 77 | 78 | [node name="SaveContent" parent="HyperGateway" instance=ExtResource( 3 )] |
| 78 | 79 | script = ExtResource( 8 ) |
| 79 | 80 | |
| 81 | [node name="FileChanges" type="Node" parent="HyperGateway"] | |
| 82 | script = ExtResource( 2 ) | |
| 83 | ||
| 80 | 84 | [connection signal="item_selected" from="HBoxContainer/Files" to="." method="_on_Files_item_selected"] |
| 81 | 85 | [connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/SaveButton" to="." method="_on_SaveButton_pressed"] |
| 82 | 86 | [connection signal="pressed" from="HBoxContainer/VBoxContainer/HBoxContainer/LoadButton" to="." method="_on_LoadButton_pressed"] |
| … | … | @@ -85,4 +89,5 @@ script = ExtResource( 8 ) |
| 85 | 89 | [connection signal="content" from="HyperGateway/GetContent" to="." method="_on_GetContent_content"] |
| 86 | 90 | [connection signal="request_completed" from="HyperGateway/GetContent" to="HyperGateway/GetContent" method="_on_GetContent_request_completed"] |
| 87 | 91 | [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"] |
| … | … | @@ -2,29 +2,17 @@ extends "res://src/HyperRequest/HyperRequest.gd" |
| 2 | 2 | |
| 3 | 3 | signal files(files) |
| 4 | 4 | |
| 5 | export var folder = 'hyper://notes/' | |
| 6 | ||
| 7 | func _ready(): | |
| 8 | list() | |
| 9 | pass # Replace with function body. | |
| 10 | ||
| 11 | func list(path=folder): | |
| 5 | func list(path): | |
| 12 | 6 | request(path + "?noResolve") |
| 13 | 7 | pass |
| 14 | 8 | |
| 15 | 9 | func _on_ListFiles_request_completed(result, response_code, headers, body): |
| 16 | print('Loaded', response_code) | |
| 17 | ||
| 18 | 10 | if response_code != 200: return |
| 19 | 11 | |
| 20 | 12 | var content = body.get_string_from_utf8() |
| 21 | ||
| 22 | print("Loaded directory listing", content) | |
| 23 | ||
| 13 | ||
| 24 | 14 | var json = JSON.parse(content) |
| 25 | 15 | |
| 26 | print("Loaded JSON", json) | |
| 27 | ||
| 28 | 16 | if json.error != OK: return printerr(json.error_string) |
| 29 | 17 | |
| 30 | 18 | emit_signal("files", json.result) |
| … | … | @@ -3,7 +3,7 @@ extends "res://src/HyperRequest/HyperRequest.gd" |
| 3 | 3 | signal saved |
| 4 | 4 | |
| 5 | 5 | func save(path, content): |
| 6 | print("Saving", path, content) | |
| 6 | print("Saving ", path, " ", content) | |
| 7 | 7 | self.request( |
| 8 | 8 | path, |
| 9 | 9 | PoolStringArray(["Content-Type: text/plain"]), |
| … | … | @@ -13,7 +13,6 @@ func save(path, content): |
| 13 | 13 | ) |
| 14 | 14 | pass |
| 15 | 15 | |
| 16 | ||
| 17 | 16 | func _on_SaveContent_request_completed(result, response_code, headers, body): |
| 18 | 17 | if response_code == 200: emit_signal("saved") |
| 19 | 18 | else: printerr(body.get_string_from_utf8()) |
| … | … | @@ -0,0 +1,21 @@ |
| 1 | extends HTTPEventSource | |
| 2 | ||
| 3 | class_name HyperEventSource | |
| 4 | ||
| 5 | signal loading_data(url) | |
| 6 | ||
| 7 | export var serverPrefix = "http://127.0.0.1:4973/hyper/" | |
| 8 | ||
| 9 | var watching = false | |
| 10 | ||
| 11 | func 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) | |
| 21 | pass |
| … | … | @@ -1,9 +1,13 @@ |
| 1 | 1 | extends HTTPRequest |
| 2 | 2 | |
| 3 | class_name HyperRequest | |
| 4 | ||
| 3 | 5 | signal loading_data(url) |
| 4 | 6 | |
| 5 | 7 | export var serverPrefix = "http://127.0.0.1:4973/hyper/" |
| 6 | 8 | |
| 9 | var watching = false | |
| 10 | ||
| 7 | 11 | func request( |
| 8 | 12 | url, |
| 9 | 13 | custom_headers=PoolStringArray( ), |
| … | … | @@ -0,0 +1,32 @@ |
| 1 | var urlParseRegex = RegEx.new() | |
| 2 | ||
| 3 | const DEFAULT_PORTS = { | |
| 4 | "http": 80, | |
| 5 | "https": 443 | |
| 6 | } | |
| 7 | ||
| 8 | func _init(): | |
| 9 | urlParseRegex.compile("([^:]+)://([^/]+)(/?.*)") | |
| 10 | ||
| 11 | func 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 | } |