From 7ee08ac5711f4cacc52e3d2ddbda9aa2248d9031 Mon Sep 17 00:00:00 2001 From: Jose Falanga Date: Wed, 19 Aug 2026 16:20:20 -0300 Subject: [PATCH] readability: extract magic constants, fix Go jargon - goos/goarch -> os_name/arch_name (Go ecosystem jargon) - BUTLER_USER_AGENT now reads version from plugin.json at runtime - Added named constants: CONNECTION_TIMEOUT_ITERATIONS, CONNECTION_POLL_DELAY_MS, PERCENTAGE_SCALE, LAUNCH_WATCH_INTERVAL_SEC, UPDATE_CHECK_INTERVAL_SEC, BUTLERD_BOOT_MAX_ATTEMPTS, BUTLERD_BOOT_RETRY_DELAY_SEC, LAUNCH_WATCH_TIMEOUT_MS, EXECUTE_PERMISSION_BIT - Removed BYTES_PER_MB (inline 1024 * 1024 is clearer) --- core/itch_client.gd | 36 +++++++++++++++++++++++++----------- core/library_itch.gd | 20 +++++++++++++------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/core/itch_client.gd b/core/itch_client.gd index 5af9df4..56c8209 100644 --- a/core/itch_client.gd +++ b/core/itch_client.gd @@ -29,6 +29,9 @@ const butler_dir := "user://butler" ## survive plugin updates untouched. const games_dir := "user://butler/games" const CACHE_DIR := "itch" +const CONNECTION_TIMEOUT_ITERATIONS := 50 +const CONNECTION_POLL_DELAY_MS := 20 +const PERCENTAGE_SCALE := 100 enum STATE { BOOT, @@ -101,7 +104,7 @@ func bootstrap() -> void: "--keep-alive", "--dbpath", dbpath, "--address", "https://itch.io", - "--user-agent", "OpenGamepadUI-itch/0.1.0", + "--user-agent", _get_user_agent(), "--destiny-pid", str(OS.get_process_id()), ] @@ -138,21 +141,21 @@ func _migrate_butler(dest_dir: String) -> void: ## Downloads a butler binary for this platform from itch's broth distribution ## channel (the same one the official itch.io app uses to self-update). func _install_butler() -> bool: - var goos := "linux" - var goarch := "amd64" + var os_name := "linux" + var arch_name := "amd64" if OS.get_name() == "Windows": - goos = "windows" + os_name = "windows" if OS.get_name() == "macOS": - goos = "darwin" + os_name = "darwin" # Engine.get_architecture_name() is only available on newer Godot 4.x # builds; guard it so this still works if OpenGamepadUI is running on an # older engine version. if Engine.has_method("get_architecture_name"): var arch: String = Engine.get_architecture_name() if "arm64" in arch or "aarch64" in arch: - goarch = "arm64" + arch_name = "arm64" - var platform_slug := goos + "-" + goarch + var platform_slug := os_name + "-" + arch_name var latest_url := "/".join([broth_base, platform_slug, "LATEST"]) var http := HTTPRequest.new() @@ -204,6 +207,17 @@ func _install_butler() -> bool: return true +func _get_user_agent() -> String: + var version := "unknown" + var file := FileAccess.open("res://plugin.json", FileAccess.READ) + if file: + var json: Variant = JSON.parse_string(file.get_as_text()) + file.close() + if json is Dictionary: + version = json.get("plugin.version", "unknown") + return "OpenGamepadUI-itch/" + version + + # --------------------------------------------------------------------------- # Wire protocol: spawn -> read handshake off stdout -> connect TCP -> auth # --------------------------------------------------------------------------- @@ -266,10 +280,10 @@ func _connect_and_authenticate(address: String, secret: String) -> void: return # Wait for the connection to establish - var timeout := 50 + var timeout := CONNECTION_TIMEOUT_ITERATIONS while socket.get_status() == StreamPeerTCP.STATUS_CONNECTING and timeout > 0: socket.poll() - OS.delay_msec(20) + OS.delay_msec(CONNECTION_POLL_DELAY_MS) timeout -= 1 if socket.get_status() != StreamPeerTCP.STATUS_CONNECTED: logger.error("Timed out connecting to butlerd") @@ -790,8 +804,8 @@ func _install(game: Dictionary, cave_id: String, options: Dictionary) -> bool: var progress: float = p.get("progress", 0.0) install_progressed.emit.call_deferred( cave_id if cave_id != "" else str(game_id), - int(progress * 100), - 100 + int(progress * PERCENTAGE_SCALE), + PERCENTAGE_SCALE ) rpc_notification.connect(on_notification) diff --git a/core/library_itch.gd b/core/library_itch.gd index 6813c92..901d841 100644 --- a/core/library_itch.gd +++ b/core/library_itch.gd @@ -2,6 +2,13 @@ extends Library const ItchClient := preload("res://plugins/itch/core/itch_client.gd") const _apps_cache_file: String = "apps.json" +const LAUNCH_WATCH_INTERVAL_SEC := 2.0 +const UPDATE_CHECK_INTERVAL_SEC := 600.0 +const BUTLERD_BOOT_MAX_ATTEMPTS := 10 +const BUTLERD_BOOT_RETRY_DELAY_SEC := 0.5 +const LAUNCH_WATCH_TIMEOUT_MS := 5000 +## 0o111 — execute bit set for any of owner/group/others. +const EXECUTE_PERMISSION_BIT := 73 var settings_manager := load("res://core/global/settings_manager.tres") as SettingsManager @@ -35,14 +42,14 @@ func _ready() -> void: # instead of leaving the user stuck on a black in-game screen. if load("res://core/global/launch_manager.tres") != null: var watch_timer := Timer.new() - watch_timer.wait_time = 2.0 + watch_timer.wait_time = LAUNCH_WATCH_INTERVAL_SEC watch_timer.autostart = true watch_timer.timeout.connect(_check_failed_launches) add_child(watch_timer) # Keep the has_update() flags fresh in the background (CheckUpdate hits the # itch.io API, so it must never run on the UI thread or per-library-load). var update_timer := Timer.new() - update_timer.wait_time = 600.0 + update_timer.wait_time = UPDATE_CHECK_INTERVAL_SEC update_timer.autostart = true update_timer.timeout.connect(_refresh_update_flags) add_child(update_timer) @@ -502,8 +509,8 @@ func _load_library(caching_flags: int = Cache.FLAGS.LOAD | Cache.FLAGS.SAVE) -> cached_installed = true break var attempts := 0 - while cached_installed and attempts < 10 and (caves == null or (caves.is_empty() and itch.state != ItchClient.STATE.CONNECTED)): - await get_tree().create_timer(0.5).timeout + while cached_installed and attempts < BUTLERD_BOOT_MAX_ATTEMPTS and (caves == null or (caves.is_empty() and itch.state != ItchClient.STATE.CONNECTED)): + await get_tree().create_timer(BUTLERD_BOOT_RETRY_DELAY_SEC).timeout caves = await itch.get_caves() attempts += 1 var caves_by_game_id := {} @@ -792,8 +799,7 @@ func _candidate_is_game_binary(path: String) -> bool: func _is_runnable_file(path: String) -> bool: if path == "" or not FileAccess.file_exists(path): return false - # 0o111 = execute bit set for any of owner/group/others. - return FileAccess.get_unix_permissions(path) & 73 != 0 + return FileAccess.get_unix_permissions(path) & EXECUTE_PERMISSION_BIT != 0 ## Looks up a runtime binary (love, java, ...). Checks the persistent runtime @@ -839,7 +845,7 @@ func _check_failed_launches() -> void: continue if app.is_running(): continue - if now - int(_launch_watch[app.pid]) < 5000: + if now - int(_launch_watch[app.pid]) < LAUNCH_WATCH_TIMEOUT_MS: continue if app.pid in _diagnosed_pids: continue