Compare commits
No commits in common. "main" and "003eb04013244ba56cdfd128821878d8c0824ff7" have entirely different histories.
main
...
003eb04013
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,6 +9,3 @@ export_presets.cfg
|
|||||||
# Mono-specific ignores
|
# Mono-specific ignores
|
||||||
.mono/
|
.mono/
|
||||||
data_*/
|
data_*/
|
||||||
|
|
||||||
# VSCode config folder
|
|
||||||
.vscode/
|
|
||||||
|
69
Main.gd
69
Main.gd
@ -4,12 +4,11 @@ var mime_types := MimeTypeHelper.generate_db()
|
|||||||
|
|
||||||
var _server: HTTPServer = null
|
var _server: HTTPServer = null
|
||||||
|
|
||||||
onready var server_ui := $ServerUI
|
var files: Array = []
|
||||||
onready var server_dir = server_ui.server_dir
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
pass
|
_start_server()
|
||||||
|
|
||||||
|
|
||||||
func _start_server(port: int = 3001) -> void:
|
func _start_server(port: int = 3001) -> void:
|
||||||
@ -17,22 +16,36 @@ func _start_server(port: int = 3001) -> void:
|
|||||||
return
|
return
|
||||||
|
|
||||||
_server = HTTPServer.new()
|
_server = HTTPServer.new()
|
||||||
_server.endpoint(HTTPServer.Method.GET, "/", funcref(self, "_serve_file"))
|
var dir := Directory.new()
|
||||||
|
if dir.open("res://server_files") == OK:
|
||||||
|
if dir.list_dir_begin() != OK:
|
||||||
|
# TODO: show error to user here
|
||||||
|
return
|
||||||
|
var file_name := dir.get_next()
|
||||||
|
while file_name != "":
|
||||||
|
if !dir.current_is_dir():
|
||||||
|
if file_name.get_extension() == "import":
|
||||||
|
file_name = dir.get_next()
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(file_name)
|
||||||
|
|
||||||
|
_server.endpoint(HTTPServer.Method.GET, "/%s" % file_name, funcref(self, "_serve_file"), [file_name])
|
||||||
|
|
||||||
|
file_name = dir.get_next()
|
||||||
|
|
||||||
|
_server.endpoint(HTTPServer.Method.GET, "/", funcref(self, "_serve_file"), ["index.html"])
|
||||||
|
|
||||||
|
|
||||||
if _server.listen(port) != OK:
|
if _server.listen(port) != OK:
|
||||||
# TODO: show error to user here
|
# TODO: show error to user here
|
||||||
return
|
return
|
||||||
|
|
||||||
server_ui.is_server_running = true
|
|
||||||
|
|
||||||
|
|
||||||
func _stop_server() -> void:
|
func _stop_server() -> void:
|
||||||
if _server:
|
if _server:
|
||||||
_server.stop()
|
|
||||||
_server = null
|
_server = null
|
||||||
|
|
||||||
server_ui.is_server_running = false
|
|
||||||
|
|
||||||
|
|
||||||
func _process(_delta: float) -> void:
|
func _process(_delta: float) -> void:
|
||||||
if _server == null:
|
if _server == null:
|
||||||
@ -43,35 +56,29 @@ func _process(_delta: float) -> void:
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
func _serve_file(request: HTTPServer.Request, response: HTTPServer.Response) -> void:
|
func _serve_file(_request: HTTPServer.Request, response: HTTPServer.Response, binds: Array) -> void:
|
||||||
var file_name: String = request.endpoint()
|
var file_name: String = binds[0] as String
|
||||||
if file_name == "/": # if the request is for root, serve index
|
print(file_name)
|
||||||
file_name = "index.html"
|
|
||||||
var f := File.new()
|
var f := File.new()
|
||||||
var success = f.open(server_dir.plus_file(file_name), File.READ)
|
var success = f.open("res://server_files/%s" % file_name, File.READ)
|
||||||
|
|
||||||
|
if success == OK:
|
||||||
|
|
||||||
if success == OK: # TODO: handle other errors like file not found
|
|
||||||
var mime := mime_types.get(file_name)
|
var mime := mime_types.get(file_name)
|
||||||
response.type(mime)
|
response.header("content-type", mime.full_type)
|
||||||
|
|
||||||
var data = f.get_buffer(f.get_len())
|
# variant
|
||||||
|
# warning-ignore:incompatible_ternary
|
||||||
|
var data = f.get_as_text() if mime.type == 'text' else f.get_buffer(f.get_len())
|
||||||
|
|
||||||
response.data(data)
|
response.data(data)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
response.type(mime_types.get("txt"))
|
response.header("content-type", "text/plain")
|
||||||
response.status(500)
|
response.data("500 - Read Error")
|
||||||
response.data("Internal Server Error")
|
|
||||||
|
|
||||||
|
|
||||||
func _on_ServerUI_start_server_button_pressed(port: int, new_dir: String) -> void:
|
func get_mime_type(file_name: String) -> String:
|
||||||
server_dir = new_dir
|
var ext := file_name.get_extension().to_lower()
|
||||||
_start_server(port)
|
return mime_types[ext] if ext in mime_types else "application/octet-stream"
|
||||||
|
|
||||||
|
|
||||||
func _on_ServerUI_stop_server_button_pressed() -> void:
|
|
||||||
_stop_server()
|
|
||||||
|
|
||||||
|
|
||||||
func _on_ServerUI_server_folder_changed(new_path: String) -> void:
|
|
||||||
server_dir = new_path
|
|
||||||
|
192
Main.tscn
192
Main.tscn
@ -1,15 +1,195 @@
|
|||||||
[gd_scene load_steps=3 format=2]
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
[ext_resource path="res://Main.gd" type="Script" id=1]
|
[ext_resource path="res://Main.gd" type="Script" id=1]
|
||||||
[ext_resource path="res://ServerUI.tscn" type="PackedScene" id=2]
|
|
||||||
|
|
||||||
[node name="Main" type="Control"]
|
[node name="Main" type="Control"]
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
|
|
||||||
[node name="ServerUI" parent="." instance=ExtResource( 2 )]
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
anchor_left = 0.0380859
|
||||||
|
anchor_top = 0.087
|
||||||
|
anchor_right = 0.961914
|
||||||
|
anchor_bottom = 0.936667
|
||||||
|
margin_top = -0.200005
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": true
|
||||||
|
}
|
||||||
|
|
||||||
[connection signal="server_folder_changed" from="ServerUI" to="." method="_on_ServerUI_server_folder_changed"]
|
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
|
||||||
[connection signal="start_server_button_pressed" from="ServerUI" to="." method="_on_ServerUI_start_server_button_pressed"]
|
margin_right = 1182.0
|
||||||
[connection signal="stop_server_button_pressed" from="ServerUI" to="." method="_on_ServerUI_stop_server_button_pressed"]
|
margin_bottom = 32.0
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 146.0
|
||||||
|
margin_top = 9.0
|
||||||
|
margin_right = 231.0
|
||||||
|
margin_bottom = 23.0
|
||||||
|
text = "Server folder:"
|
||||||
|
|
||||||
|
[node name="ServerPathLabel" type="Label" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 235.0
|
||||||
|
margin_top = 9.0
|
||||||
|
margin_right = 491.0
|
||||||
|
margin_bottom = 23.0
|
||||||
|
rect_min_size = Vector2( 256, 0 )
|
||||||
|
text = "/home/username/long/path/to/server"
|
||||||
|
clip_text = true
|
||||||
|
|
||||||
|
[node name="OpenServerFolderButton" type="Button" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 495.0
|
||||||
|
margin_right = 554.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 0, 32 )
|
||||||
|
text = "Open..."
|
||||||
|
|
||||||
|
[node name="Label2" type="Label" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 558.0
|
||||||
|
margin_top = 9.0
|
||||||
|
margin_right = 632.0
|
||||||
|
margin_bottom = 23.0
|
||||||
|
text = "Server port:"
|
||||||
|
|
||||||
|
[node name="SpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 636.0
|
||||||
|
margin_right = 710.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
min_value = 81.0
|
||||||
|
max_value = 8000.0
|
||||||
|
value = 3001.0
|
||||||
|
|
||||||
|
[node name="StartServerButton" type="Button" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 714.0
|
||||||
|
margin_right = 799.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 0, 32 )
|
||||||
|
text = "Start server"
|
||||||
|
|
||||||
|
[node name="ServerStatusLabel" type="Label" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 803.0
|
||||||
|
margin_top = 9.0
|
||||||
|
margin_right = 914.0
|
||||||
|
margin_bottom = 23.0
|
||||||
|
text = "Server is running!"
|
||||||
|
|
||||||
|
[node name="Button" type="Button" parent="VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 918.0
|
||||||
|
margin_right = 1036.0
|
||||||
|
margin_bottom = 32.0
|
||||||
|
rect_min_size = Vector2( 0, 32 )
|
||||||
|
size_flags_horizontal = 12
|
||||||
|
text = "Open in browser"
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer"]
|
||||||
|
margin_top = 36.0
|
||||||
|
margin_right = 34.0
|
||||||
|
margin_bottom = 50.0
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
text = "Files:"
|
||||||
|
|
||||||
|
[node name="HSplitContainer" type="HSplitContainer" parent="VBoxContainer"]
|
||||||
|
margin_top = 54.0
|
||||||
|
margin_right = 1182.0
|
||||||
|
margin_bottom = 611.0
|
||||||
|
size_flags_vertical = 3
|
||||||
|
split_offset = -263
|
||||||
|
|
||||||
|
[node name="Tree" type="Tree" parent="VBoxContainer/HSplitContainer"]
|
||||||
|
margin_right = 322.0
|
||||||
|
margin_bottom = 557.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/HSplitContainer"]
|
||||||
|
margin_left = 334.0
|
||||||
|
margin_right = 1182.0
|
||||||
|
margin_bottom = 557.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
|
||||||
|
[node name="HSplitContainer" type="HSplitContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer"]
|
||||||
|
margin_right = 848.0
|
||||||
|
margin_bottom = 557.0
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer"]
|
||||||
|
margin_right = 848.0
|
||||||
|
margin_bottom = 557.0
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer"]
|
||||||
|
margin_right = 848.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer"]
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 32.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
text = "Title:"
|
||||||
|
|
||||||
|
[node name="DocTitleLineEdit" type="LineEdit" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer"]
|
||||||
|
margin_left = 36.0
|
||||||
|
margin_right = 848.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
placeholder_text = "(Optional)"
|
||||||
|
|
||||||
|
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer"]
|
||||||
|
margin_top = 28.0
|
||||||
|
margin_right = 848.0
|
||||||
|
margin_bottom = 52.0
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer2"]
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 34.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
text = "Date:"
|
||||||
|
|
||||||
|
[node name="DocDateLineEdit" type="LineEdit" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer2"]
|
||||||
|
margin_left = 38.0
|
||||||
|
margin_right = 848.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
placeholder_text = "(Optional)"
|
||||||
|
|
||||||
|
[node name="HSplitContainer" type="HSplitContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer"]
|
||||||
|
margin_top = 56.0
|
||||||
|
margin_right = 848.0
|
||||||
|
margin_bottom = 557.0
|
||||||
|
size_flags_vertical = 3
|
||||||
|
split_offset = 328
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer"]
|
||||||
|
margin_right = 378.0
|
||||||
|
margin_bottom = 501.0
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer"]
|
||||||
|
margin_right = 378.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
text = "Content"
|
||||||
|
|
||||||
|
[node name="DocumentInputTextEdit" type="TextEdit" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer"]
|
||||||
|
margin_top = 18.0
|
||||||
|
margin_right = 378.0
|
||||||
|
margin_bottom = 501.0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
show_line_numbers = true
|
||||||
|
wrap_enabled = true
|
||||||
|
|
||||||
|
[node name="VBoxContainer2" type="VBoxContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer"]
|
||||||
|
margin_left = 390.0
|
||||||
|
margin_right = 848.0
|
||||||
|
margin_bottom = 501.0
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer2"]
|
||||||
|
margin_right = 458.0
|
||||||
|
margin_bottom = 14.0
|
||||||
|
text = "Content Preview (Not accurate!)"
|
||||||
|
|
||||||
|
[node name="ContentPreviewRichTextLabel" type="RichTextLabel" parent="VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer/HSplitContainer/VBoxContainer2"]
|
||||||
|
margin_top = 18.0
|
||||||
|
margin_right = 458.0
|
||||||
|
margin_bottom = 501.0
|
||||||
|
size_flags_vertical = 3
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# Godot frontend for Tickle
|
# Godot frontend for Ticle
|
||||||
|
|
||||||
Tickle is a WIP tiny static site "generator" that parses Markdown files right in the browser, with no compilation to HTML necessary, intended for equally tiny blogs.
|
Ticle is a WIP tiny static site "generator" that parses Markdown files right in the browser, with no compilation to HTML necessary, intended for equally tiny blogs.
|
||||||
|
|
||||||
This project aims to provide a nice frontend/UI to manage Tickle files and an easy way to run your site locally.
|
This project aims to provide a nice frontend/UI to manage Ticle files and an easy way to run your site locally.
|
||||||
|
|
||||||
It uses a slightly modified version of [godot-http-server](https://github.com/velopman/godot-http-server) for the server side.
|
It uses a slightly modified version of [godot-http-server](https://github.com/velopman/godot-http-server) for the server side.
|
||||||
|
|
||||||
The version of Godot used for this project is 3.5rc5.
|
The version of Godot used for this project is 3.5rc4.
|
||||||
|
141
ServerUI.gd
141
ServerUI.gd
@ -1,16 +1,11 @@
|
|||||||
extends Control
|
extends Control
|
||||||
|
|
||||||
const SERVER_STATUS_TEXT: Dictionary = {
|
const SERVER_STATUS_TEXT: Dictionary = {
|
||||||
true: "Server is running!",
|
"RUNNING": "Server is running!",
|
||||||
false: "Server is not running.",
|
"NOT_RUNNING": "Server is not running."
|
||||||
}
|
}
|
||||||
|
|
||||||
const START_BUTTON_SERVER_TEXT: Dictionary = {
|
const ACCEPTED_FILE_FORMATS := ["md"] # server should ignore these file types when adding endpoints
|
||||||
true: "Stop server",
|
|
||||||
false: "Start server",
|
|
||||||
}
|
|
||||||
|
|
||||||
const ACCEPTED_FILE_FORMATS := ["md"]
|
|
||||||
|
|
||||||
export(bool) var enable_file_autosave := true # if true, will save the active file's contents every save_file_timeout seconds.
|
export(bool) var enable_file_autosave := true # if true, will save the active file's contents every save_file_timeout seconds.
|
||||||
export(float) var save_file_timeout := 4.0 # the time to save document content after the edited signal of TextEdit
|
export(float) var save_file_timeout := 4.0 # the time to save document content after the edited signal of TextEdit
|
||||||
@ -22,9 +17,7 @@ enum ContextMenuOptions {
|
|||||||
|
|
||||||
onready var server_path_label := $"%ServerPathLabel"
|
onready var server_path_label := $"%ServerPathLabel"
|
||||||
onready var port_spin_box := $"%PortSpinBox"
|
onready var port_spin_box := $"%PortSpinBox"
|
||||||
onready var start_server_button := $"%StartServerButton"
|
|
||||||
onready var server_status_label := $"%ServerStatusLabel"
|
onready var server_status_label := $"%ServerStatusLabel"
|
||||||
onready var open_browser_button := $"%OpenBrowserButton"
|
|
||||||
|
|
||||||
onready var document_title_lineedit := $"%DocTitleLineEdit"
|
onready var document_title_lineedit := $"%DocTitleLineEdit"
|
||||||
onready var document_date_lineedit := $"%DocDateLineEdit"
|
onready var document_date_lineedit := $"%DocDateLineEdit"
|
||||||
@ -38,12 +31,11 @@ onready var content_preview_richtextlabel := $"%ContentPreviewRichTextLabel"
|
|||||||
onready var server_folder_dialog := $"%ServerFolderDialog"
|
onready var server_folder_dialog := $"%ServerFolderDialog"
|
||||||
|
|
||||||
signal server_folder_changed(new_path) # new_path: String
|
signal server_folder_changed(new_path) # new_path: String
|
||||||
signal start_server_button_pressed(port, path) # port: int, path: String
|
signal server_port_changed(new_port) # new_port: int
|
||||||
signal stop_server_button_pressed() # emit from %StartServerButton, when the server is not running.
|
signal start_server_button_pressed(port) # port: int
|
||||||
|
signal open_browser_button_pressed(port) # port: int
|
||||||
|
|
||||||
#signal server_port_changed(new_port) # new_port: int
|
signal files_selection_changed(new_files) # new_files: Array<String>
|
||||||
#signal open_browser_button_pressed(port) # port: int
|
|
||||||
#signal files_selection_changed(new_files) # new_files: Array<String>
|
|
||||||
|
|
||||||
var server_dir: String setget set_server_dir
|
var server_dir: String setget set_server_dir
|
||||||
var is_server_running: bool = false setget set_server_running
|
var is_server_running: bool = false setget set_server_running
|
||||||
@ -74,35 +66,28 @@ func set_server_dir(dir: String) -> void:
|
|||||||
|
|
||||||
var directory := Directory.new()
|
var directory := Directory.new()
|
||||||
if directory.open(dir) == OK:
|
if directory.open(dir) == OK:
|
||||||
if directory.list_dir_begin() != OK:
|
directory.list_dir_begin()
|
||||||
push_error("Directory error") # TODO: show a user-facing error
|
|
||||||
|
|
||||||
var file_name: String = directory.get_next()
|
var file_name: String = directory.get_next()
|
||||||
|
var idx: int = 0
|
||||||
while file_name != "":
|
while file_name != "":
|
||||||
if !directory.current_is_dir() && (file_name.get_extension() in ACCEPTED_FILE_FORMATS):
|
if !directory.current_is_dir() && (file_name.get_extension() in ACCEPTED_FILE_FORMATS):
|
||||||
var fd = FileDef(file_name, false)
|
var fd = FileDef(file_name, false)
|
||||||
working_files.append(fd)
|
working_files.append(fd)
|
||||||
fd.content = _get_file_content(file_name)
|
|
||||||
|
|
||||||
var in_filestxt := _is_file_in_filestxt(file_name)
|
var in_filestxt := _is_file_in_filestxt(file_name)
|
||||||
|
|
||||||
fd.include_in_filestxt = in_filestxt
|
fd.include_in_filestxt = in_filestxt
|
||||||
if in_filestxt:
|
|
||||||
var file_metadata := _get_file_metadata(file_name)
|
idx += 1
|
||||||
fd.title = file_metadata["title"]
|
|
||||||
fd.date = file_metadata["date"]
|
|
||||||
|
|
||||||
file_name = directory.get_next()
|
file_name = directory.get_next()
|
||||||
|
|
||||||
directory.list_dir_end()
|
directory.list_dir_end()
|
||||||
|
|
||||||
_reconstruct_tree_from_working_files()
|
_reconstruct_tree_from_working_files()
|
||||||
emit_signal("server_folder_changed", server_dir)
|
|
||||||
|
|
||||||
|
|
||||||
func _reconstruct_tree_from_working_files() -> void:
|
func _reconstruct_tree_from_working_files() -> void:
|
||||||
current_file = null
|
|
||||||
current_tree_selection = null
|
|
||||||
|
|
||||||
file_tree.clear()
|
file_tree.clear()
|
||||||
var root: TreeItem = file_tree.create_item()
|
var root: TreeItem = file_tree.create_item()
|
||||||
root.set_text(0, "Server files")
|
root.set_text(0, "Server files")
|
||||||
@ -129,6 +114,12 @@ func _on_FileTree_item_selected() -> void:
|
|||||||
current_tree_selection = item
|
current_tree_selection = item
|
||||||
current_file = item.get_metadata(0)["file_def"] as FileDef
|
current_file = item.get_metadata(0)["file_def"] as FileDef
|
||||||
|
|
||||||
|
if !current_file.dirty:
|
||||||
|
var file_metadata := _get_file_metadata(current_file.file_path)
|
||||||
|
current_file.title = file_metadata["title"]
|
||||||
|
current_file.date = file_metadata["date"]
|
||||||
|
current_file.content = file_metadata["content"]
|
||||||
|
|
||||||
document_input_textedit.text = current_file.content
|
document_input_textedit.text = current_file.content
|
||||||
document_date_lineedit.text = current_file.date
|
document_date_lineedit.text = current_file.date
|
||||||
document_title_lineedit.text = current_file.title
|
document_title_lineedit.text = current_file.title
|
||||||
@ -137,11 +128,6 @@ func _on_FileTree_item_selected() -> void:
|
|||||||
func _on_FileTree_item_rmb_selected(position: Vector2) -> void:
|
func _on_FileTree_item_rmb_selected(position: Vector2) -> void:
|
||||||
current_tree_selection = file_tree.get_selected()
|
current_tree_selection = file_tree.get_selected()
|
||||||
file_tree_context_menu.rect_position = position + file_tree.rect_global_position
|
file_tree_context_menu.rect_position = position + file_tree.rect_global_position
|
||||||
file_tree_context_menu.popup()
|
|
||||||
|
|
||||||
if is_server_running:
|
|
||||||
return # the file tree can't be edited while the server is running, so disable moving items as well
|
|
||||||
|
|
||||||
if (current_tree_selection.get_metadata(0)["id"] as int) == 0:
|
if (current_tree_selection.get_metadata(0)["id"] as int) == 0:
|
||||||
file_tree_context_menu.set_item_disabled(ContextMenuOptions.MOVE_UP, true)
|
file_tree_context_menu.set_item_disabled(ContextMenuOptions.MOVE_UP, true)
|
||||||
else:
|
else:
|
||||||
@ -153,23 +139,15 @@ func _on_FileTree_item_rmb_selected(position: Vector2) -> void:
|
|||||||
file_tree_context_menu.set_item_disabled(ContextMenuOptions.MOVE_DOWN, false)
|
file_tree_context_menu.set_item_disabled(ContextMenuOptions.MOVE_DOWN, false)
|
||||||
|
|
||||||
|
|
||||||
|
file_tree_context_menu.popup()
|
||||||
|
|
||||||
|
|
||||||
func _on_OpenServerFolderButton_pressed() -> void:
|
func _on_OpenServerFolderButton_pressed() -> void:
|
||||||
server_folder_dialog.popup()
|
server_folder_dialog.popup()
|
||||||
|
|
||||||
|
|
||||||
func set_server_running(running: bool) -> void:
|
func set_server_running(running: bool) -> void:
|
||||||
is_server_running = running
|
is_server_running = running # TODO: logic for disabling and enabling certain nodes
|
||||||
|
|
||||||
port_spin_box.editable = !running
|
|
||||||
document_date_lineedit.editable = !running
|
|
||||||
document_title_lineedit.editable = !running
|
|
||||||
document_input_textedit.readonly = running
|
|
||||||
open_browser_button.disabled = !running
|
|
||||||
_set_file_tree_disabled(running)
|
|
||||||
_set_context_menu_disabled(running)
|
|
||||||
|
|
||||||
server_status_label.text = SERVER_STATUS_TEXT[running]
|
|
||||||
start_server_button.text = START_BUTTON_SERVER_TEXT[running]
|
|
||||||
|
|
||||||
|
|
||||||
func _generate_filestxt():
|
func _generate_filestxt():
|
||||||
@ -178,22 +156,14 @@ func _generate_filestxt():
|
|||||||
for file in working_files:
|
for file in working_files:
|
||||||
file = file as FileDef
|
file = file as FileDef
|
||||||
if file.include_in_filestxt:
|
if file.include_in_filestxt:
|
||||||
files += ("%s %s %s" % [file.file_path, file.date, file.title]).strip_edges(false, true) + "\n"
|
files += "%s %s %s\n" % [file.file_path, file.date, file.title]
|
||||||
|
|
||||||
var f := File.new()
|
var f := File.new()
|
||||||
if f.open(server_dir.plus_file("files.txt"), File.WRITE) == OK:
|
if f.open(server_dir.plus_file("files.txt"), File.WRITE) == OK:
|
||||||
f.store_string(files)
|
f.store_string(files)
|
||||||
f.close()
|
f.close()
|
||||||
else:
|
else:
|
||||||
push_error("File.txt open for save error!") # TODO: show a user-facing error
|
push_error("File.txt open for save error!")
|
||||||
|
|
||||||
|
|
||||||
func _on_StartServerButton_pressed() -> void:
|
|
||||||
if is_server_running:
|
|
||||||
emit_signal("stop_server_button_pressed")
|
|
||||||
else:
|
|
||||||
_generate_filestxt()
|
|
||||||
emit_signal("start_server_button_pressed", port_spin_box.value, server_dir)
|
|
||||||
|
|
||||||
|
|
||||||
func _is_file_in_filestxt(path: String) -> bool:
|
func _is_file_in_filestxt(path: String) -> bool:
|
||||||
@ -229,39 +199,12 @@ func _get_file_metadata(path: String) -> Dictionary:
|
|||||||
res["title"] = def[2] if def.size() > 2 else ""
|
res["title"] = def[2] if def.size() > 2 else ""
|
||||||
break
|
break
|
||||||
|
|
||||||
res["content"] = _get_file_content(path)
|
if f.open(server_dir.plus_file(path), File.READ) == OK:
|
||||||
|
res["content"] = f.get_as_text()
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
func _get_file_content(path: String) -> String:
|
|
||||||
var content: String = ""
|
|
||||||
var f := File.new()
|
|
||||||
if f.open(server_dir.plus_file(path), File.READ) == OK:
|
|
||||||
content = f.get_as_text()
|
|
||||||
|
|
||||||
return content
|
|
||||||
|
|
||||||
|
|
||||||
func _set_file_tree_disabled(disabled: bool) -> void:
|
|
||||||
var root = file_tree.get_root()
|
|
||||||
var tree_item = root.get_children() as TreeItem
|
|
||||||
while tree_item != null:
|
|
||||||
tree_item.set_editable(0, !disabled)
|
|
||||||
tree_item = tree_item.get_next()
|
|
||||||
|
|
||||||
|
|
||||||
func _set_context_menu_disabled(disabled: bool) -> void:
|
|
||||||
for i in file_tree_context_menu.get_item_count():
|
|
||||||
file_tree_context_menu.set_item_disabled(i, disabled)
|
|
||||||
|
|
||||||
|
|
||||||
func _commit_all_files() -> void:
|
|
||||||
for file in working_files:
|
|
||||||
file = file as FileDef
|
|
||||||
file.commit(server_dir)
|
|
||||||
|
|
||||||
|
|
||||||
func _on_FileTreeContextMenu_id_pressed(id: int) -> void:
|
func _on_FileTreeContextMenu_id_pressed(id: int) -> void:
|
||||||
var idx = current_tree_selection.get_metadata(0)["id"] as int
|
var idx = current_tree_selection.get_metadata(0)["id"] as int
|
||||||
var fd = working_files[idx] as FileDef
|
var fd = working_files[idx] as FileDef
|
||||||
@ -279,28 +222,20 @@ func _on_FileTreeContextMenu_id_pressed(id: int) -> void:
|
|||||||
func _on_DocTitleLineEdit_text_changed(new_text: String) -> void:
|
func _on_DocTitleLineEdit_text_changed(new_text: String) -> void:
|
||||||
if current_file:
|
if current_file:
|
||||||
current_file.title = new_text
|
current_file.title = new_text
|
||||||
|
current_file.dirty = true
|
||||||
|
|
||||||
|
|
||||||
func _on_DocDateLineEdit_text_changed(new_text: String) -> void:
|
func _on_DocDateLineEdit_text_changed(new_text: String) -> void:
|
||||||
if current_file:
|
if current_file:
|
||||||
current_file.date = new_text
|
current_file.date = new_text
|
||||||
|
current_file.dirty = true
|
||||||
|
|
||||||
func _on_OpenBrowserButton_pressed() -> void:
|
|
||||||
if OS.shell_open("http://localhost:%s" % port_spin_box.value) != OK:
|
|
||||||
push_error("Error opening browser!") # TODO: show a user-facing error
|
|
||||||
|
|
||||||
|
|
||||||
func _on_RefreshFilesButton_pressed() -> void:
|
|
||||||
_commit_all_files()
|
|
||||||
_generate_filestxt()
|
|
||||||
self.server_dir = server_dir
|
|
||||||
|
|
||||||
|
|
||||||
func _on_DocInputTextEdit_text_changed() -> void:
|
func _on_DocInputTextEdit_text_changed() -> void:
|
||||||
if current_file:
|
if current_file:
|
||||||
var new_text: String = document_input_textedit.text
|
var new_text: String = document_input_textedit.text
|
||||||
current_file.content = new_text
|
current_file.content = new_text
|
||||||
|
current_file.dirty = true
|
||||||
|
|
||||||
if !current_file.timer:
|
if !current_file.timer:
|
||||||
var t := Timer.new()
|
var t := Timer.new()
|
||||||
@ -308,7 +243,6 @@ func _on_DocInputTextEdit_text_changed() -> void:
|
|||||||
t.one_shot = true
|
t.one_shot = true
|
||||||
current_file.timer = t
|
current_file.timer = t
|
||||||
add_child(t)
|
add_child(t)
|
||||||
# warning-ignore:return_value_discarded
|
|
||||||
t.connect("timeout", self, "_on_EditedTimeout_timeout", [t, current_file])
|
t.connect("timeout", self, "_on_EditedTimeout_timeout", [t, current_file])
|
||||||
else:
|
else:
|
||||||
current_file.timer.stop()
|
current_file.timer.stop()
|
||||||
@ -319,7 +253,9 @@ func _on_EditedTimeout_timeout(timer: Timer, file: FileDef) -> void:
|
|||||||
file.timer = null
|
file.timer = null
|
||||||
timer.queue_free()
|
timer.queue_free()
|
||||||
|
|
||||||
file.commit(server_dir)
|
var f := File.new()
|
||||||
|
if f.open(server_dir.plus_file(file.file_path), File.WRITE) == OK:
|
||||||
|
f.store_string(file.content)
|
||||||
|
|
||||||
|
|
||||||
func FileDef(
|
func FileDef(
|
||||||
@ -341,19 +277,8 @@ class FileDef:
|
|||||||
var include_in_filestxt: bool = true
|
var include_in_filestxt: bool = true
|
||||||
var title: String # optional
|
var title: String # optional
|
||||||
var date: String # optional, YYYY-MM-DD
|
var date: String # optional, YYYY-MM-DD
|
||||||
|
var dirty: bool = false
|
||||||
|
|
||||||
var content: String
|
var content: String
|
||||||
|
|
||||||
var timer: Timer
|
var timer: Timer
|
||||||
|
|
||||||
func commit(server_dir: String) -> void:
|
|
||||||
var f := File.new()
|
|
||||||
var open := f.open(server_dir.plus_file(file_path), File.WRITE)
|
|
||||||
if open == OK:
|
|
||||||
f.store_string(content)
|
|
||||||
|
|
||||||
if timer && !timer.is_stopped(): # if there's an autosave pending, stop it since we're setting it here.
|
|
||||||
timer.stop()
|
|
||||||
|
|
||||||
else:
|
|
||||||
push_error("Error committing file %s, code %s" % [file_path, open]) # TODO: show a user-facing error
|
|
||||||
|
@ -62,7 +62,6 @@ max_value = 8000.0
|
|||||||
value = 3001.0
|
value = 3001.0
|
||||||
|
|
||||||
[node name="StartServerButton" type="Button" parent="VBoxContainer/HBoxContainer"]
|
[node name="StartServerButton" type="Button" parent="VBoxContainer/HBoxContainer"]
|
||||||
unique_name_in_owner = true
|
|
||||||
margin_left = 693.0
|
margin_left = 693.0
|
||||||
margin_right = 778.0
|
margin_right = 778.0
|
||||||
margin_bottom = 32.0
|
margin_bottom = 32.0
|
||||||
@ -78,13 +77,11 @@ margin_bottom = 23.0
|
|||||||
text = "Server is not running."
|
text = "Server is not running."
|
||||||
|
|
||||||
[node name="OpenBrowserButton" type="Button" parent="VBoxContainer/HBoxContainer"]
|
[node name="OpenBrowserButton" type="Button" parent="VBoxContainer/HBoxContainer"]
|
||||||
unique_name_in_owner = true
|
|
||||||
margin_left = 922.0
|
margin_left = 922.0
|
||||||
margin_right = 1040.0
|
margin_right = 1040.0
|
||||||
margin_bottom = 32.0
|
margin_bottom = 32.0
|
||||||
rect_min_size = Vector2( 0, 32 )
|
rect_min_size = Vector2( 0, 32 )
|
||||||
size_flags_horizontal = 12
|
size_flags_horizontal = 12
|
||||||
disabled = true
|
|
||||||
text = "Open in browser"
|
text = "Open in browser"
|
||||||
|
|
||||||
[node name="HSplitContainer" type="HSplitContainer" parent="VBoxContainer"]
|
[node name="HSplitContainer" type="HSplitContainer" parent="VBoxContainer"]
|
||||||
@ -190,19 +187,19 @@ size_flags_vertical = 3
|
|||||||
split_offset = 328
|
split_offset = 328
|
||||||
|
|
||||||
[node name="ContentEditContainer" type="VBoxContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/HSplitContainer"]
|
[node name="ContentEditContainer" type="VBoxContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/HSplitContainer"]
|
||||||
margin_right = 848.0
|
margin_right = 378.0
|
||||||
margin_bottom = 514.0
|
margin_bottom = 514.0
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
|
|
||||||
[node name="Label" type="Label" parent="VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/HSplitContainer/ContentEditContainer"]
|
[node name="Label" type="Label" parent="VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/HSplitContainer/ContentEditContainer"]
|
||||||
margin_right = 848.0
|
margin_right = 378.0
|
||||||
margin_bottom = 14.0
|
margin_bottom = 14.0
|
||||||
text = "Content"
|
text = "Content"
|
||||||
|
|
||||||
[node name="DocInputTextEdit" type="TextEdit" parent="VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/HSplitContainer/ContentEditContainer"]
|
[node name="DocInputTextEdit" type="TextEdit" parent="VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/HSplitContainer/ContentEditContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
margin_top = 18.0
|
margin_top = 18.0
|
||||||
margin_right = 848.0
|
margin_right = 378.0
|
||||||
margin_bottom = 514.0
|
margin_bottom = 514.0
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
@ -210,7 +207,6 @@ show_line_numbers = true
|
|||||||
wrap_enabled = true
|
wrap_enabled = true
|
||||||
|
|
||||||
[node name="ContentPreviewContainer" type="VBoxContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/HSplitContainer"]
|
[node name="ContentPreviewContainer" type="VBoxContainer" parent="VBoxContainer/HSplitContainer/VBoxContainer/HBoxContainer/VBoxContainer/HSplitContainer"]
|
||||||
visible = false
|
|
||||||
margin_left = 390.0
|
margin_left = 390.0
|
||||||
margin_right = 848.0
|
margin_right = 848.0
|
||||||
margin_bottom = 514.0
|
margin_bottom = 514.0
|
||||||
@ -250,9 +246,6 @@ rect_min_size = Vector2( 95, 56 )
|
|||||||
items = [ "Move Up", null, 0, false, false, 0, 0, null, "", false, "Move Down", null, 0, false, false, 1, 0, null, "", false ]
|
items = [ "Move Up", null, 0, false, false, 0, 0, null, "", false, "Move Down", null, 0, false, false, 1, 0, null, "", false ]
|
||||||
|
|
||||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/OpenServerFolderButton" to="." method="_on_OpenServerFolderButton_pressed"]
|
[connection signal="pressed" from="VBoxContainer/HBoxContainer/OpenServerFolderButton" to="." method="_on_OpenServerFolderButton_pressed"]
|
||||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/StartServerButton" to="." method="_on_StartServerButton_pressed"]
|
|
||||||
[connection signal="pressed" from="VBoxContainer/HBoxContainer/OpenBrowserButton" to="." method="_on_OpenBrowserButton_pressed"]
|
|
||||||
[connection signal="pressed" from="VBoxContainer/HSplitContainer/VBoxContainer2/HBoxContainer2/RefreshFilesButton" to="." method="_on_RefreshFilesButton_pressed"]
|
|
||||||
[connection signal="item_edited" from="VBoxContainer/HSplitContainer/VBoxContainer2/FileTree" to="." method="_on_FileTree_item_edited"]
|
[connection signal="item_edited" from="VBoxContainer/HSplitContainer/VBoxContainer2/FileTree" to="." method="_on_FileTree_item_edited"]
|
||||||
[connection signal="item_rmb_selected" from="VBoxContainer/HSplitContainer/VBoxContainer2/FileTree" to="." method="_on_FileTree_item_rmb_selected"]
|
[connection signal="item_rmb_selected" from="VBoxContainer/HSplitContainer/VBoxContainer2/FileTree" to="." method="_on_FileTree_item_rmb_selected"]
|
||||||
[connection signal="item_selected" from="VBoxContainer/HSplitContainer/VBoxContainer2/FileTree" to="." method="_on_FileTree_item_selected"]
|
[connection signal="item_selected" from="VBoxContainer/HSplitContainer/VBoxContainer2/FileTree" to="." method="_on_FileTree_item_selected"]
|
||||||
|
@ -13,7 +13,7 @@ const Status = preload("res://addons/http_server/status.gd")
|
|||||||
|
|
||||||
var __endpoints: Dictionary = {
|
var __endpoints: Dictionary = {
|
||||||
# key: [Int, String], array with 0 index representing method, 1 index representing endpoint
|
# key: [Int, String], array with 0 index representing method, 1 index representing endpoint
|
||||||
# value: FuncRef, reference to function to call
|
# value: [FuncRef, Array], index 0 = reference to function to call, index 1 = binds to pass to func
|
||||||
}
|
}
|
||||||
var __fallback: FuncRef = null
|
var __fallback: FuncRef = null
|
||||||
var __server: TCP_Server = null
|
var __server: TCP_Server = null
|
||||||
@ -32,7 +32,7 @@ func endpoint(type: int, endpoint: String, function: FuncRef, binds: Array = [])
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
__endpoints[endpoint_hash] = function
|
__endpoints[endpoint_hash] = [function, binds]
|
||||||
|
|
||||||
|
|
||||||
func fallback(function: FuncRef) -> void:
|
func fallback(function: FuncRef) -> void:
|
||||||
@ -106,7 +106,7 @@ func __process_connection(connection: StreamPeerTCP) -> void:
|
|||||||
body = PoolStringArray(body_parts).join("\r\n")
|
body = PoolStringArray(body_parts).join("\r\n")
|
||||||
|
|
||||||
var response: Response = __process_request(method, endpoint, headers, body)
|
var response: Response = __process_request(method, endpoint, headers, body)
|
||||||
connection.put_data(response.get_data())
|
connection.put_data(response.to_utf8())
|
||||||
|
|
||||||
|
|
||||||
func __process_request(method: String, endpoint: String, headers: Dictionary, body: String) -> Response:
|
func __process_request(method: String, endpoint: String, headers: Dictionary, body: String) -> Response:
|
||||||
@ -121,13 +121,20 @@ func __process_request(method: String, endpoint: String, headers: Dictionary, bo
|
|||||||
|
|
||||||
var endpoint_func: FuncRef = null
|
var endpoint_func: FuncRef = null
|
||||||
var endpoint_parts: PoolStringArray = endpoint.split("/", false)
|
var endpoint_parts: PoolStringArray = endpoint.split("/", false)
|
||||||
|
var binds
|
||||||
|
|
||||||
while !endpoint_func:
|
# special case for if endpoint is just root
|
||||||
|
if endpoint == "/":
|
||||||
|
var endpoint_hash: Array = [type, "/"]
|
||||||
|
if __endpoints.has(endpoint_hash):
|
||||||
|
endpoint_func = __endpoints[endpoint_hash][0]
|
||||||
|
binds = __endpoints[endpoint_hash][1]
|
||||||
|
else:
|
||||||
|
while (!endpoint_func && !endpoint_parts.empty()):
|
||||||
var endpoint_hash: Array = [type, "/" + endpoint_parts.join("/")]
|
var endpoint_hash: Array = [type, "/" + endpoint_parts.join("/")]
|
||||||
if __endpoints.has(endpoint_hash):
|
if __endpoints.has(endpoint_hash):
|
||||||
endpoint_func = __endpoints[endpoint_hash]
|
endpoint_func = __endpoints[endpoint_hash][0]
|
||||||
elif endpoint_parts.empty():
|
binds = __endpoints[endpoint_hash][1]
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
endpoint_parts.remove(endpoint_parts.size() - 1)
|
endpoint_parts.remove(endpoint_parts.size() - 1)
|
||||||
|
|
||||||
@ -153,7 +160,10 @@ func __process_request(method: String, endpoint: String, headers: Dictionary, bo
|
|||||||
"[INF] Recieved request method: %s, endpoint: %s" % [method, endpoint]
|
"[INF] Recieved request method: %s, endpoint: %s" % [method, endpoint]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if !binds:
|
||||||
endpoint_func.call_func(request, response)
|
endpoint_func.call_func(request, response)
|
||||||
|
else:
|
||||||
|
endpoint_func.call_func(request, response, binds)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ var __headers: Dictionary = {
|
|||||||
# value: Variant, header value
|
# value: Variant, header value
|
||||||
}
|
}
|
||||||
var __status: int = 200
|
var __status: int = 200
|
||||||
var __type: MimeTypeHelper.MimeType
|
|
||||||
|
|
||||||
|
|
||||||
# Public methods
|
# Public methods
|
||||||
@ -33,10 +32,6 @@ func status(status: int) -> void:
|
|||||||
__status = status
|
__status = status
|
||||||
|
|
||||||
|
|
||||||
func type(type: MimeTypeHelper.MimeType) -> void:
|
|
||||||
__type = type
|
|
||||||
|
|
||||||
|
|
||||||
func to_utf8() -> PoolByteArray:
|
func to_utf8() -> PoolByteArray:
|
||||||
var content = PoolStringArray()
|
var content = PoolStringArray()
|
||||||
|
|
||||||
@ -50,7 +45,6 @@ func to_utf8() -> PoolByteArray:
|
|||||||
data = JSON.print(data)
|
data = JSON.print(data)
|
||||||
|
|
||||||
__headers['content-length'] = len(data)
|
__headers['content-length'] = len(data)
|
||||||
__headers["content-type"] = "application/octet-stream" if !__type else __type.full_type
|
|
||||||
|
|
||||||
for header in __headers:
|
for header in __headers:
|
||||||
content.append("%s: %s" % [header, String(__headers[header])])
|
content.append("%s: %s" % [header, String(__headers[header])])
|
||||||
@ -61,48 +55,3 @@ func to_utf8() -> PoolByteArray:
|
|||||||
content.append(data)
|
content.append(data)
|
||||||
|
|
||||||
return content.join("\r\n").to_utf8()
|
return content.join("\r\n").to_utf8()
|
||||||
|
|
||||||
|
|
||||||
func get_data() -> PoolByteArray:
|
|
||||||
var res = __response_headers()
|
|
||||||
|
|
||||||
var data = __data
|
|
||||||
if !data:
|
|
||||||
return res
|
|
||||||
|
|
||||||
var type: MimeTypeHelper.MimeType = __type
|
|
||||||
if !type:
|
|
||||||
type = MimeTypeHelper.MimeType.new()
|
|
||||||
|
|
||||||
if data is String: # else, assume data is PoolByteArray
|
|
||||||
data = data.to_utf8()
|
|
||||||
|
|
||||||
res.append_array(data)
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
# Private methods
|
|
||||||
|
|
||||||
func __response_headers() -> PoolByteArray:
|
|
||||||
var res = PoolStringArray()
|
|
||||||
|
|
||||||
res.append(Status.code_to_status_line(__status))
|
|
||||||
|
|
||||||
var data = __data
|
|
||||||
if !data:
|
|
||||||
data = Status.code_to_description(__status)
|
|
||||||
|
|
||||||
__headers["content-length"] = len(data)
|
|
||||||
|
|
||||||
__headers["content-type"] = "application/octet-stream" if !__type else __type.full_type
|
|
||||||
|
|
||||||
for header in __headers:
|
|
||||||
res.append("%s: %s" % [header, String(__headers[header])])
|
|
||||||
|
|
||||||
res.append("")
|
|
||||||
|
|
||||||
var s = res.join("\r\n")
|
|
||||||
s = s + "\r\n"
|
|
||||||
|
|
||||||
return s.to_utf8()
|
|
||||||
|
@ -26,7 +26,7 @@ _global_script_class_icons={
|
|||||||
|
|
||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="Tickle Frontend"
|
config/name="Ticle Frontend"
|
||||||
run/main_scene="res://Main.tscn"
|
run/main_scene="res://Main.tscn"
|
||||||
config/icon="res://icon.png"
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
first.md 2022-03-03 first title
|
first.md 2022-01-06 first article
|
||||||
second.md 2022-03-05 second title
|
second.md 2021-05-03 second article
|
||||||
|
second.md
|
||||||
|
Loading…
Reference in New Issue
Block a user