Emit install/update/uninstall completion and forward install progress to the base Library contract so OGPU's InstallManager and launch menu stop hanging at 0%
This commit is contained in:
parent
b19903e682
commit
e48a0b501d
3 changed files with 46 additions and 25 deletions
|
|
@ -495,11 +495,12 @@ func _ensure_install_location() -> String:
|
||||||
|
|
||||||
|
|
||||||
## Installs (or updates, if a caveId is given) the given game.
|
## Installs (or updates, if a caveId is given) the given game.
|
||||||
func install(game: Dictionary, cave_id: String = "") -> void:
|
## Returns true when the operation finished without errors.
|
||||||
await thread_group.exec(_install.bind(game, cave_id))
|
func install(game: Dictionary, cave_id: String = "") -> bool:
|
||||||
|
return await thread_group.exec(_install.bind(game, cave_id))
|
||||||
|
|
||||||
|
|
||||||
func _install(game: Dictionary, cave_id: String) -> void:
|
func _install(game: Dictionary, cave_id: String) -> bool:
|
||||||
var game_id: int = game.get("id", 0)
|
var game_id: int = game.get("id", 0)
|
||||||
var reason := "update" if cave_id != "" else "install"
|
var reason := "update" if cave_id != "" else "install"
|
||||||
|
|
||||||
|
|
@ -508,7 +509,7 @@ func _install(game: Dictionary, cave_id: String) -> void:
|
||||||
if "error" in uploads_res:
|
if "error" in uploads_res:
|
||||||
logger.warn("Fetch.GameUploads failed: " + str(uploads_res["error"]))
|
logger.warn("Fetch.GameUploads failed: " + str(uploads_res["error"]))
|
||||||
emit_signal.call_deferred("app_installed", cave_id, false)
|
emit_signal.call_deferred("app_installed", cave_id, false)
|
||||||
return
|
return false
|
||||||
# Uploads are cached by butlerd just like owned keys, so retry fresh when
|
# Uploads are cached by butlerd just like owned keys, so retry fresh when
|
||||||
# the cached result is stale, otherwise a cold database would report every
|
# the cached result is stale, otherwise a cold database would report every
|
||||||
# game as having no compatible upload.
|
# game as having no compatible upload.
|
||||||
|
|
@ -519,12 +520,12 @@ func _install(game: Dictionary, cave_id: String) -> void:
|
||||||
if "error" in uploads_res:
|
if "error" in uploads_res:
|
||||||
logger.warn("Fetch.GameUploads (fresh) failed: " + str(uploads_res["error"]))
|
logger.warn("Fetch.GameUploads (fresh) failed: " + str(uploads_res["error"]))
|
||||||
emit_signal.call_deferred("app_installed", cave_id, false)
|
emit_signal.call_deferred("app_installed", cave_id, false)
|
||||||
return
|
return false
|
||||||
var uploads: Array = uploads_res.get("uploads", [])
|
var uploads: Array = uploads_res.get("uploads", [])
|
||||||
if uploads.is_empty():
|
if uploads.is_empty():
|
||||||
logger.error("No compatible uploads found for game id " + str(game_id))
|
logger.error("No compatible uploads found for game id " + str(game_id))
|
||||||
emit_signal.call_deferred("app_installed", cave_id, false)
|
emit_signal.call_deferred("app_installed", cave_id, false)
|
||||||
return
|
return false
|
||||||
var upload: Dictionary = uploads[0]
|
var upload: Dictionary = uploads[0]
|
||||||
|
|
||||||
var location_id := await _ensure_install_location()
|
var location_id := await _ensure_install_location()
|
||||||
|
|
@ -543,7 +544,7 @@ func _install(game: Dictionary, cave_id: String) -> void:
|
||||||
if "error" in queue_res:
|
if "error" in queue_res:
|
||||||
logger.error("Install.Queue failed: " + str(queue_res["error"]))
|
logger.error("Install.Queue failed: " + str(queue_res["error"]))
|
||||||
emit_signal.call_deferred("app_installed", cave_id, false)
|
emit_signal.call_deferred("app_installed", cave_id, false)
|
||||||
return
|
return false
|
||||||
|
|
||||||
var task_id: String = queue_res.get("id", "")
|
var task_id: String = queue_res.get("id", "")
|
||||||
var staging_folder: String = queue_res.get("stagingFolder", "")
|
var staging_folder: String = queue_res.get("stagingFolder", "")
|
||||||
|
|
@ -572,19 +573,21 @@ func _install(game: Dictionary, cave_id: String) -> void:
|
||||||
emit_signal.call_deferred("app_updated", cave_id, success)
|
emit_signal.call_deferred("app_updated", cave_id, success)
|
||||||
else:
|
else:
|
||||||
emit_signal.call_deferred("app_installed", cave_id, success)
|
emit_signal.call_deferred("app_installed", cave_id, success)
|
||||||
|
return success
|
||||||
|
|
||||||
|
|
||||||
## Uninstalls the given cave.
|
## Uninstalls the given cave. Returns true on success.
|
||||||
func uninstall(cave_id: String) -> void:
|
func uninstall(cave_id: String) -> bool:
|
||||||
await thread_group.exec(_uninstall.bind(cave_id))
|
return await thread_group.exec(_uninstall.bind(cave_id))
|
||||||
|
|
||||||
|
|
||||||
func _uninstall(cave_id: String) -> void:
|
func _uninstall(cave_id: String) -> bool:
|
||||||
var res := await _rpc_call("Uninstall.Perform", {"caveId": cave_id})
|
var res := await _rpc_call("Uninstall.Perform", {"caveId": cave_id})
|
||||||
var success := not ("error" in res)
|
var success := not ("error" in res)
|
||||||
if not success:
|
if not success:
|
||||||
logger.error("Uninstall.Perform failed: " + str(res.get("error")))
|
logger.error("Uninstall.Perform failed: " + str(res.get("error")))
|
||||||
emit_signal.call_deferred("app_uninstalled", cave_id, success)
|
emit_signal.call_deferred("app_uninstalled", cave_id, success)
|
||||||
|
return success
|
||||||
|
|
||||||
|
|
||||||
## Launches the given cave. This call blocks (on the background thread) for
|
## Launches the given cave. This call blocks (on the background thread) for
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,11 @@ const _apps_cache_file: String = "apps.json"
|
||||||
|
|
||||||
@onready var itch: ItchClient = get_tree().get_first_node_in_group("itch_client")
|
@onready var itch: ItchClient = get_tree().get_first_node_in_group("itch_client")
|
||||||
|
|
||||||
|
## The item currently being installed/updated/uninstalled. OGPU's InstallManager
|
||||||
|
## only runs one install at a time, so a single slot is enough to map butlerd's
|
||||||
|
## install_progressed/app_* signals back to the LibraryLaunchItem.
|
||||||
|
var _active_item: LibraryLaunchItem
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
super()
|
super()
|
||||||
|
|
@ -22,16 +27,28 @@ func get_library_launch_items() -> Array[LibraryLaunchItem]:
|
||||||
|
|
||||||
func install_to(item: LibraryLaunchItem, _location: InstallLocation = null, _options: Dictionary = {}) -> void:
|
func install_to(item: LibraryLaunchItem, _location: InstallLocation = null, _options: Dictionary = {}) -> void:
|
||||||
var game := (item.metadata.get("game", {}) as Dictionary)
|
var game := (item.metadata.get("game", {}) as Dictionary)
|
||||||
itch.install(game)
|
_active_item = item
|
||||||
|
var success: bool = await itch.install(game)
|
||||||
|
_active_item = null
|
||||||
|
install_completed.emit(item, success)
|
||||||
|
logger.info("Install of '" + item.name + "' completed with status: " + str(success))
|
||||||
|
|
||||||
|
|
||||||
func update(item: LibraryLaunchItem) -> void:
|
func update(item: LibraryLaunchItem) -> void:
|
||||||
var game := (item.metadata.get("game", {}) as Dictionary)
|
var game := (item.metadata.get("game", {}) as Dictionary)
|
||||||
itch.install(game, item.provider_app_id)
|
_active_item = item
|
||||||
|
var success: bool = await itch.install(game, item.provider_app_id)
|
||||||
|
_active_item = null
|
||||||
|
update_completed.emit(item, success)
|
||||||
|
logger.info("Update of '" + item.name + "' completed with status: " + str(success))
|
||||||
|
|
||||||
|
|
||||||
func uninstall(item: LibraryLaunchItem) -> void:
|
func uninstall(item: LibraryLaunchItem) -> void:
|
||||||
itch.uninstall(item.provider_app_id)
|
_active_item = item
|
||||||
|
var success: bool = await itch.uninstall(item.provider_app_id)
|
||||||
|
_active_item = null
|
||||||
|
uninstall_completed.emit(item, success)
|
||||||
|
logger.info("Uninstall of '" + item.name + "' completed with status: " + str(success))
|
||||||
|
|
||||||
|
|
||||||
## itch.io's CheckUpdate call is async (and rate-limited), so we don't poll it
|
## itch.io's CheckUpdate call is async (and rate-limited), so we don't poll it
|
||||||
|
|
@ -54,16 +71,17 @@ func _on_logged_in(status: ItchClient.LOGIN_STATUS, _profile: Dictionary) -> voi
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
## Re-emits itch.io's raw (id, current, total) install progress under the
|
## Forwards butlerd's install progress (current/total are percentage points,
|
||||||
## base [Library] signal contract (item, percent_completed) so the UI's
|
## 0-100) to the base [Library] install_progressed contract (a fraction,
|
||||||
## generic install-progress widgets pick it up regardless of provider.
|
## 0.0-1.0) that OGPU's InstallManager and launch menu render as a progress
|
||||||
## TODO: verify the exact LibraryManager lookup method/key for resolving a
|
## bar.
|
||||||
## provider_app_id back to its LibraryLaunchItem (this plugin was written
|
func _on_install_progressed(_id: String, current: int, total: int) -> void:
|
||||||
## against the public Library/LibraryLaunchItem API, but LibraryManager's
|
if _active_item == null:
|
||||||
## internals weren't available while writing this) and wire the emit below
|
return
|
||||||
## through it instead of dropping the notification.
|
if total <= 0:
|
||||||
func _on_install_progressed(_id: String, _current: int, _total: int) -> void:
|
return
|
||||||
pass
|
logger.info("Install progressing: " + str(current) + "/" + str(total))
|
||||||
|
install_progressed.emit(_active_item, float(current) / float(total))
|
||||||
|
|
||||||
|
|
||||||
## Builds a LibraryLaunchItem for a game, or null when the entry isn't an
|
## Builds a LibraryLaunchItem for a game, or null when the entry isn't an
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"plugin.id": "itch",
|
"plugin.id": "itch",
|
||||||
"plugin.name": "itch.io",
|
"plugin.name": "itch.io",
|
||||||
"plugin.version": "0.1.7",
|
"plugin.version": "0.1.8",
|
||||||
"plugin.min-api-version": "1.1.0",
|
"plugin.min-api-version": "1.1.0",
|
||||||
"plugin.link": "https://github.com/YOUR_USERNAME/OpenGamepadUI-itch",
|
"plugin.link": "https://github.com/YOUR_USERNAME/OpenGamepadUI-itch",
|
||||||
"plugin.source": "https://github.com/YOUR_USERNAME/OpenGamepadUI-itch",
|
"plugin.source": "https://github.com/YOUR_USERNAME/OpenGamepadUI-itch",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue