279 lines
No EOL
8.9 KiB
GDScript
279 lines
No EOL
8.9 KiB
GDScript
# ServerManager.gd
|
|
extends Node
|
|
|
|
var server_path: String = ""
|
|
var log_dir: String = ""
|
|
var variant_dir : String = ""
|
|
var log_string: String = ""
|
|
var running := false
|
|
var server_process_id: int = -50
|
|
var request_timer: Timer
|
|
var server_pinger: Timer
|
|
var ping_http: HTTPRequest
|
|
|
|
var server_url = "http://localhost:27531"
|
|
|
|
|
|
func write_variant(variant_string: String):
|
|
|
|
var file = FileAccess.open(variant_dir, FileAccess.WRITE_READ)
|
|
var error = FileAccess.get_open_error()
|
|
|
|
if error != OK:
|
|
# print("Failed to open log file. Error code: ", error)
|
|
return
|
|
|
|
if file == null:
|
|
# print("File handle is null")
|
|
return
|
|
|
|
file.store_string(variant_string)
|
|
|
|
var write_error = FileAccess.get_open_error()
|
|
if write_error != OK:
|
|
print("Failed to write to log file. Error code: ", write_error)
|
|
|
|
file.close()
|
|
|
|
|
|
func write_log(message: String):
|
|
# First check if path is valid
|
|
# print("Attempting to write to: ", log_dir)
|
|
|
|
var file = FileAccess.open(log_dir, FileAccess.WRITE_READ)
|
|
var error = FileAccess.get_open_error()
|
|
|
|
if error != OK:
|
|
# print("Failed to open log file. Error code: ", error)
|
|
return
|
|
|
|
if file == null:
|
|
# print("File handle is null")
|
|
return
|
|
|
|
var timestamp = Time.get_datetime_string_from_system()
|
|
var log_message = "[" + timestamp + "] " + message + "\n"
|
|
log_string += log_message
|
|
print("Writing message: ", log_message)
|
|
file.store_string(log_string)
|
|
|
|
var write_error = FileAccess.get_open_error()
|
|
if write_error != OK:
|
|
print("Failed to write to log file. Error code: ", write_error)
|
|
|
|
file.close()
|
|
func _ready():
|
|
server_path = extract_server_files() + "/ChessEngines/fairy-chess-server"
|
|
setup_logging()
|
|
setup_variant()
|
|
check_server_files(server_path)
|
|
start_server()
|
|
get_tree().set_auto_accept_quit(false)
|
|
setup_server_pinger()
|
|
|
|
func setup_server_pinger():
|
|
server_pinger = Timer.new()
|
|
add_child(server_pinger)
|
|
server_pinger.wait_time = 60.0
|
|
server_pinger.one_shot = false
|
|
server_pinger.timeout.connect(self._on_ping_timer_timeout)
|
|
ping_http = HTTPRequest.new()
|
|
add_child(ping_http)
|
|
ping_http.request_completed.connect(self._on_ping_completed)
|
|
|
|
server_pinger.start()
|
|
|
|
|
|
func _on_ping_timer_timeout():
|
|
write_log("Pinging server health endpoint...")
|
|
var error = ping_http.request(server_url + "/health")
|
|
if error != OK:
|
|
write_log("Error sending ping request: " + str(error))
|
|
|
|
|
|
func _on_ping_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray):
|
|
if result == HTTPRequest.RESULT_SUCCESS:
|
|
write_log("Server ping successful")
|
|
else:
|
|
write_log("Server ping failed - may need to restart server")
|
|
|
|
|
|
func write_log_dir_contents(path: String):
|
|
var dir = DirAccess.open(path)
|
|
if dir:
|
|
write_log("Directory contents of: " + path)
|
|
dir.list_dir_begin()
|
|
var file_name = dir.get_next()
|
|
while file_name != "":
|
|
write_log(" - " + file_name)
|
|
file_name = dir.get_next()
|
|
else:
|
|
write_log("ERROR: Could not open directory: " + path)
|
|
func check_server_files(path: String):
|
|
write_log("Checking server files...")
|
|
write_log(path)
|
|
|
|
var index_path = path.path_join("index.js")
|
|
if FileAccess.file_exists(index_path):
|
|
write_log("index.js exists")
|
|
var file = FileAccess.open(index_path, FileAccess.READ)
|
|
if file:
|
|
write_log("index.js contents:")
|
|
# write_log(file.get_as_text())
|
|
else:
|
|
write_log("ERROR: Could not read index.js")
|
|
else:
|
|
write_log("ERROR: index.js does not exist at path: " + index_path)
|
|
|
|
func get_globalDir() -> String:
|
|
|
|
if OS.get_name() == "Linux":
|
|
return OS.get_environment("HOME").path_join(".local/share/ChessBuilder")
|
|
elif OS.get_name() == "Windows":
|
|
return OS.get_environment("APPDATA").path_join("Roaming/ChessBuilder")
|
|
else: # macOS
|
|
return OS.get_environment("HOME").path_join("Library/ChessBuilder")
|
|
|
|
func setup_logging():
|
|
var l_dir = get_globalDir() + "/logs"
|
|
|
|
# Create directory if it doesn't exist
|
|
DirAccess.make_dir_recursive_absolute(l_dir)
|
|
|
|
log_dir = l_dir.path_join("godot-chess.log")
|
|
write_log("ServerManager initialized")
|
|
func setup_variant():
|
|
var l_dir = get_globalDir() + "/variant"
|
|
|
|
# Create directory if it doesn't exist
|
|
DirAccess.make_dir_recursive_absolute(l_dir)
|
|
|
|
variant_dir = l_dir.path_join("custom_variant.ini")
|
|
write_log("ServerManager Variants initialized")
|
|
|
|
func _exit_tree():
|
|
stop_server()
|
|
get_tree().quit()
|
|
|
|
func _notification(what):
|
|
if what == NOTIFICATION_WM_CLOSE_REQUEST:
|
|
stop_server()
|
|
get_tree().quit()
|
|
|
|
|
|
func start_server() -> bool:
|
|
if running:
|
|
return true
|
|
|
|
write_log("Starting chess server... " + server_path)
|
|
var http_request = HTTPRequest.new()
|
|
add_child(http_request)
|
|
http_request.request_completed.connect(self._on_init_request_completed)
|
|
|
|
request_timer = Timer.new()
|
|
add_child(request_timer)
|
|
request_timer.wait_time = 2.0 # 2 seconds
|
|
request_timer.one_shot = true
|
|
request_timer.timeout.connect(self._on_request_timeout)
|
|
request_timer.start()
|
|
http_request.request(server_url + "/health")
|
|
|
|
|
|
return true
|
|
|
|
|
|
func _on_request_timeout():
|
|
write_log("Request timed out, starting server manually")
|
|
# Clean up timer
|
|
request_timer.queue_free()
|
|
request_timer = null
|
|
write_log("HTTP Request failed, starting server process")
|
|
write_log(server_path + "/index.js")
|
|
server_process_id = OS.create_process("node", [server_path + "/index.js"])
|
|
write_log("SERVER PATH " + server_path)
|
|
if server_process_id <= 0:
|
|
printerr("Failed to start server")
|
|
write_log("ERROR: Failed to start server, process ID: " + str(server_process_id))
|
|
|
|
return false
|
|
|
|
running = true
|
|
write_log("Chess server started with PID: " + str(server_process_id))
|
|
return
|
|
|
|
func _on_init_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray):
|
|
write_log("*****************_on_init_request_completed************")
|
|
if request_timer:
|
|
request_timer.stop()
|
|
request_timer.queue_free()
|
|
request_timer = null
|
|
var json = JSON.new()
|
|
json.parse(body.get_string_from_utf8())
|
|
var response = json.get_data()
|
|
write_log("Init request completed")
|
|
write_log("Result: " + str(response))
|
|
if response == null:
|
|
write_log("HTTP Request failed, starting server process")
|
|
write_log(server_path + "/index.js")
|
|
server_process_id = OS.create_process("node", [server_path + "/index.js"])
|
|
write_log("SERVER PATH " + server_path)
|
|
if server_process_id <= 0:
|
|
printerr("Failed to start server")
|
|
write_log("ERROR: Failed to start server, process ID: " + str(server_process_id))
|
|
|
|
return false
|
|
|
|
running = true
|
|
write_log("Chess server started with PID: " + str(server_process_id))
|
|
return
|
|
running = true
|
|
if response and response.status != "ok":
|
|
print("Server error : ", response_code, json.parse(body.get_string_from_utf8()),)
|
|
return
|
|
|
|
static func copy_directory_recursively(p_from: String, p_to: String) -> void:
|
|
# Create target directory if it doesn't exist
|
|
if not DirAccess.dir_exists_absolute(p_to):
|
|
DirAccess.make_dir_recursive_absolute(p_to)
|
|
|
|
# Open source directory
|
|
var dir = DirAccess.open(p_from)
|
|
if dir:
|
|
# Begin listing directory contents
|
|
dir.list_dir_begin()
|
|
var file_name = dir.get_next()
|
|
|
|
# Iterate through directory contents
|
|
while file_name != "":
|
|
# write_log(file_name + " isDIr? " + str(dir.current_is_dir()))
|
|
if dir.current_is_dir():
|
|
# Recursively copy subdirectories
|
|
copy_directory_recursively(p_from.path_join(file_name), p_to.path_join(file_name))
|
|
else:
|
|
# Copy files
|
|
dir.copy(p_from.path_join(file_name), p_to.path_join(file_name))
|
|
file_name = dir.get_next()
|
|
|
|
func extract_server_files() -> String:
|
|
write_log("Extracting server files from PCK...")
|
|
var dir = get_globalDir() + "/Assets";
|
|
copy_directory_recursively("res://Assets/", dir)
|
|
return dir
|
|
|
|
|
|
func stop_server():
|
|
if not running:
|
|
return
|
|
|
|
write_log("Stopping chess server...")
|
|
# Send a stop request to the server
|
|
var headers = ["Content-Type: application/json"]
|
|
var http = HTTPClient.new()
|
|
var data = JSON.stringify({"command": "shutdown"})
|
|
http.request(HTTPClient.METHOD_POST, "/shutdown", headers, data)
|
|
|
|
running = false
|
|
write_log("Chess server stopped")
|
|
|
|
func is_server_running() -> bool:
|
|
return running |