134 lines
4.3 KiB
GDScript
134 lines
4.3 KiB
GDScript
extends Node
|
|
class_name DownloadManager
|
|
## Handles downloading game files with progress tracking and checksum verification
|
|
|
|
signal download_started(file_name: String, total_size: int)
|
|
signal download_progress(downloaded: int, total: int, percentage: float)
|
|
signal download_completed(file_path: String)
|
|
signal download_failed(error: String)
|
|
|
|
var http_request: HTTPRequest
|
|
var download_path: String = ""
|
|
var expected_checksum_md5: String = ""
|
|
var expected_checksum_sha256: String = ""
|
|
var total_size: int = 0
|
|
var is_downloading: bool = false
|
|
|
|
func _ready() -> void:
|
|
http_request = HTTPRequest.new()
|
|
add_child(http_request)
|
|
http_request.request_completed.connect(_on_download_completed)
|
|
http_request.download_file = "" # We'll set this per download
|
|
|
|
# Ensure directories exist
|
|
_ensure_directories()
|
|
|
|
func _ensure_directories() -> void:
|
|
var dir := DirAccess.open("user://")
|
|
if dir:
|
|
if not dir.dir_exists("game"):
|
|
dir.make_dir("game")
|
|
if not dir.dir_exists("backup"):
|
|
dir.make_dir("backup")
|
|
if not dir.dir_exists("temp"):
|
|
dir.make_dir("temp")
|
|
|
|
func _process(_delta: float) -> void:
|
|
if is_downloading and http_request:
|
|
var downloaded := http_request.get_downloaded_bytes()
|
|
var body_size := http_request.get_body_size()
|
|
|
|
if body_size > 0:
|
|
var percentage := (float(downloaded) / float(body_size)) * 100.0
|
|
emit_signal("download_progress", downloaded, body_size, percentage)
|
|
|
|
func download_file(url: String, file_name: String, size: int = 0, md5: String = "", sha256: String = "") -> void:
|
|
if is_downloading:
|
|
emit_signal("download_failed", "Download already in progress")
|
|
return
|
|
|
|
download_path = "user://temp/" + file_name
|
|
expected_checksum_md5 = md5
|
|
expected_checksum_sha256 = sha256
|
|
total_size = size
|
|
is_downloading = true
|
|
|
|
# Set download file path
|
|
http_request.download_file = download_path
|
|
|
|
print("[DownloadManager] Starting download: ", url)
|
|
print("[DownloadManager] Saving to: ", download_path)
|
|
|
|
emit_signal("download_started", file_name, size)
|
|
|
|
var error := http_request.request(url)
|
|
if error != OK:
|
|
is_downloading = false
|
|
emit_signal("download_failed", "Failed to initiate download: " + str(error))
|
|
|
|
func _on_download_completed(result: int, response_code: int, _headers: PackedStringArray, _body: PackedByteArray) -> void:
|
|
is_downloading = false
|
|
|
|
if result != HTTPRequest.RESULT_SUCCESS:
|
|
emit_signal("download_failed", "Download failed with result: " + str(result))
|
|
return
|
|
|
|
if response_code != 200:
|
|
emit_signal("download_failed", "Server returned error: " + str(response_code))
|
|
return
|
|
|
|
# Verify checksum if provided
|
|
if expected_checksum_md5 != "" or expected_checksum_sha256 != "":
|
|
if not _verify_checksum():
|
|
emit_signal("download_failed", "Checksum verification failed - file may be corrupted")
|
|
# Delete corrupted file
|
|
var dir := DirAccess.open("user://temp/")
|
|
if dir:
|
|
dir.remove(download_path.get_file())
|
|
return
|
|
|
|
print("[DownloadManager] Download completed: ", download_path)
|
|
emit_signal("download_completed", download_path)
|
|
|
|
func _verify_checksum() -> bool:
|
|
## Verify the downloaded file's checksum
|
|
var file := FileAccess.open(download_path, FileAccess.READ)
|
|
if not file:
|
|
print("[DownloadManager] Could not open file for checksum verification")
|
|
return false
|
|
|
|
var content := file.get_buffer(file.get_length())
|
|
file.close()
|
|
|
|
# Verify MD5 if provided
|
|
if expected_checksum_md5 != "":
|
|
var ctx := HashingContext.new()
|
|
ctx.start(HashingContext.HASH_MD5)
|
|
ctx.update(content)
|
|
var calculated_md5 := ctx.finish().hex_encode()
|
|
|
|
if calculated_md5.to_lower() != expected_checksum_md5.to_lower():
|
|
print("[DownloadManager] MD5 mismatch! Expected: ", expected_checksum_md5, " Got: ", calculated_md5)
|
|
return false
|
|
print("[DownloadManager] MD5 checksum verified")
|
|
|
|
# Verify SHA256 if provided
|
|
if expected_checksum_sha256 != "":
|
|
var ctx := HashingContext.new()
|
|
ctx.start(HashingContext.HASH_SHA256)
|
|
ctx.update(content)
|
|
var calculated_sha256 := ctx.finish().hex_encode()
|
|
|
|
if calculated_sha256.to_lower() != expected_checksum_sha256.to_lower():
|
|
print("[DownloadManager] SHA256 mismatch! Expected: ", expected_checksum_sha256, " Got: ", calculated_sha256)
|
|
return false
|
|
print("[DownloadManager] SHA256 checksum verified")
|
|
|
|
return true
|
|
|
|
func cancel_download() -> void:
|
|
if is_downloading:
|
|
http_request.cancel_request()
|
|
is_downloading = false
|
|
print("[DownloadManager] Download cancelled")
|