Initial commit
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
@tool
|
||||
extends Node
|
||||
class_name CghUpdater
|
||||
## Checks the public update endpoint; if a newer semver exists, downloads the
|
||||
## addon zip and extracts it over res://addons/cgheven, then asks for an editor
|
||||
## restart (Godot has no silent plugin hot-reload).
|
||||
|
||||
signal update_available(version: String, notes: String, url: String)
|
||||
signal up_to_date()
|
||||
signal update_ready_to_restart()
|
||||
signal update_failed(message: String)
|
||||
|
||||
var _check_http: HTTPRequest
|
||||
var _dl: CghDownloader
|
||||
|
||||
func _ready() -> void:
|
||||
_check_http = HTTPRequest.new(); add_child(_check_http)
|
||||
_check_http.request_completed.connect(_on_check)
|
||||
_dl = CghDownloader.new(); add_child(_dl)
|
||||
_dl.finished.connect(_on_zip_downloaded)
|
||||
_dl.failed.connect(func(m): update_failed.emit(m))
|
||||
|
||||
func check() -> void:
|
||||
# Backend contract: POST /api/addon-updates/check with body {addon_slug,
|
||||
# current_version}; public, no auth (matches autoupdate-public-popup). Response:
|
||||
# {update_available, latest_version, changelog, download_url}.
|
||||
var body := JSON.stringify({
|
||||
"addon_slug": CghConfig.ADDON_SLUG,
|
||||
"current_version": CghConfig.ADDON_VERSION,
|
||||
})
|
||||
_check_http.request(CghConfig.check_update_url(),
|
||||
PackedStringArray(["Content-Type: application/json"]),
|
||||
HTTPClient.METHOD_POST, body)
|
||||
|
||||
func _on_check(_r: int, code: int, _h: PackedStringArray, b: PackedByteArray) -> void:
|
||||
if code < 200 or code >= 300:
|
||||
update_failed.emit("Update check failed (HTTP %d)" % code)
|
||||
return
|
||||
var d = JSON.parse_string(b.get_string_from_utf8())
|
||||
if typeof(d) != TYPE_DICTIONARY:
|
||||
update_failed.emit("Bad update response")
|
||||
return
|
||||
if d.get("update_available", false):
|
||||
var ver := str(d.get("latest_version", "?"))
|
||||
var notes_v = d.get("changelog", "")
|
||||
var notes := str(notes_v) if notes_v != null else ""
|
||||
var url_v = d.get("download_url", "")
|
||||
var url := str(url_v) if url_v != null else ""
|
||||
if url == "":
|
||||
# Update exists but no ZIP uploaded to the release yet — don't prompt a
|
||||
# download that can't complete; surface only on a manual check.
|
||||
update_failed.emit("Update %s available, but no download is published yet." % ver)
|
||||
return
|
||||
update_available.emit(ver, notes, url)
|
||||
else:
|
||||
up_to_date.emit()
|
||||
|
||||
func download_and_stage(url: String) -> void:
|
||||
_dl.download(url, "cgheven_update.zip")
|
||||
|
||||
func _on_zip_downloaded(zip_path: String) -> void:
|
||||
var reader := ZIPReader.new()
|
||||
if reader.open(zip_path) != OK:
|
||||
update_failed.emit("Could not open update zip")
|
||||
return
|
||||
var base := "res://addons/cgheven/"
|
||||
for entry in reader.get_files():
|
||||
if entry.ends_with("/"):
|
||||
continue
|
||||
# entries are expected under addons/cgheven/... ; strip leading path to map onto base
|
||||
var rel := entry
|
||||
var idx := rel.find("addons/cgheven/")
|
||||
if idx != -1:
|
||||
rel = rel.substr(idx + "addons/cgheven/".length())
|
||||
var out_path := base + rel
|
||||
DirAccess.make_dir_recursive_absolute(out_path.get_base_dir())
|
||||
var f := FileAccess.open(out_path, FileAccess.WRITE)
|
||||
if f:
|
||||
f.store_buffer(reader.read_file(entry))
|
||||
f.close()
|
||||
reader.close()
|
||||
update_ready_to_restart.emit() # caller shows "Restart editor?" dialog -> EditorInterface.restart_editor()
|
||||
Reference in New Issue
Block a user