From 6c18e163576826d0aa8380452de364a719a464a4 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Fri, 26 Nov 2021 12:17:26 -0600 Subject: [PATCH] Added ApplicationManager::Status, DownloadManager now displays data from Status, added improved progress information to DownloadManager via Task updating its Status object --- lib/api/package.rb | 7 +- lib/application_manager/status.rb | 40 ++++++ lib/application_manager/task.rb | 138 ++++++++++++++++----- lib/application_manager/tasks/installer.rb | 14 +-- lib/cache.rb | 4 +- lib/page.rb | 3 - lib/pages/download_manager.rb | 45 ++++--- lib/states/interface.rb | 48 +++---- lib/window.rb | 1 - w3dhub.rb | 1 + 10 files changed, 220 insertions(+), 81 deletions(-) create mode 100644 lib/application_manager/status.rb diff --git a/lib/api/package.rb b/lib/api/package.rb index 2b0fafa..20ed8bb 100644 --- a/lib/api/package.rb +++ b/lib/api/package.rb @@ -2,7 +2,7 @@ class W3DHub class Api class Package attr_reader :category, :subcategory, :name, :version, :size, :checksum, :checksum_chunk_size, :checksum_chunks, - :custom_partially_valid_at_bytes + :custom_partially_valid_at_bytes, :custom_is_patch def initialize(hash) @data = hash @@ -18,6 +18,7 @@ class W3DHub @checksum_chunks = @data[:"checksum-chunks"] @custom_partially_valid_at_bytes = 0 + @custom_is_patch = false end def chunk(key) @@ -28,6 +29,10 @@ class W3DHub @custom_partially_valid_at_bytes = i end + def is_patch=(file) + @custom_is_patch = file + end + class Chunk attr_reader :chunk, :checksum diff --git a/lib/application_manager/status.rb b/lib/application_manager/status.rb new file mode 100644 index 0000000..3bea864 --- /dev/null +++ b/lib/application_manager/status.rb @@ -0,0 +1,40 @@ +class W3DHub + class ApplicationManager + class Status + attr_reader :application, :channel, :step, :operations, :data + attr_accessor :label, :value, :progress + + def initialize(application:, channel:, label: "", value: "", progress: 0.0, step: :pending, operations: {}, &callback) + @application = application + @channel = channel + + @label = label + @value = value + @progress = progress + + @step = step + @operations = operations + + @callback = callback + + @data = {} + end + + def step=(sym) + @step = sym + @callback&.call(self) + @step + end + + class Operation + attr_accessor :label, :value, :progress + + def initialize(label:, value:, progress:) + @label = label + @value = value + @progress = progress + end + end + end + end +end diff --git a/lib/application_manager/task.rb b/lib/application_manager/task.rb index bbbb959..1dcf240 100644 --- a/lib/application_manager/task.rb +++ b/lib/application_manager/task.rb @@ -4,8 +4,7 @@ class W3DHub include CyberarmEngine::Common attr_reader :app_id, :release_channel, :application, :channel, - :total_bytes_to_download, :bytes_downloaded, :packages_to_download, - :manifests, :packages, :files, :wine_prefix + :manifests, :packages, :files, :wine_prefix, :status def initialize(app_id, release_channel) @app_id = app_id @@ -26,6 +25,8 @@ class W3DHub @wine_prefix = nil + @status = Status.new(application: @application, channel: channel) { update_interface_task_status } + setup end @@ -119,19 +120,10 @@ class W3DHub ) end - def update_application_taskbar(message, status, progress) + def update_interface_task_status run_on_main_thread( proc do - window.current_state.show_application_taskbar - window.current_state.update_application_taskbar(message, status, progress) - end - ) - end - - def update_download_manager_task(checksum, message, status, progress) - run_on_main_thread( - proc do - window.current_state.update_download_manager_task(checksum, message, status, progress) + window.current_state.update_interface_task_status(self) end ) end @@ -149,6 +141,13 @@ class W3DHub ############### def fetch_manifests + @status.operations.clear + @status.label = "Downloading #{@application.name}..." + @status.value = "Fetching manifests..." + @status.progress = 0.0 + + @status.step = :fetching_manifests + if fetch_manifest("games", app_id, "manifest.xml", @channel.current_version) manifest = load_manifest("games", app_id, "manifest.xml", @channel.current_version) @manifests << manifest @@ -164,6 +163,13 @@ class W3DHub end def build_package_list(manifests) + @status.operations.clear + @status.label = "Downloading #{@application.name}..." + @status.value = "Building package list..." + @status.progress = 0.0 + + @status.step = :build_package_list + packages = [] manifests.reverse.each do |manifest| @@ -191,6 +197,8 @@ class W3DHub { category: "games", subcategory: @app_id, name: file.package, version: manifest.version } ) ) + + packages.last.is_patch = file if file.patch? end # TODO: Dependencies @@ -215,34 +223,58 @@ class W3DHub @packages = [package_details].flatten @packages_to_download = [] - update_application_taskbar("Downloading #{@application.name}...", "Verifying local packages...", 0.0) + @status.label = "Downloading #{@application.name}..." + @status.value = "Verifying local packages..." + @status.progress = 0.0 package_details.each do |pkg| - @packages_to_download << pkg unless verify_package(pkg) + @status.operations[:"#{pkg.checksum}"] = Status::Operation.new( + label: pkg.name, + value: "Verifying...", + progress: 0.0 + ) end + @status.step = :prefetch_verifying_packages + + package_details.each do |pkg| + operation = @status.operations[:"#{pkg.checksum}"] + + if verify_package(pkg) + operation.value = "Verified." + operation.progress = 1.0 + else + @packages_to_download << pkg + + operation.value = "#{W3DHub.format_size(pkg.custom_partially_valid_at_bytes)} / #{W3DHub.format_size(pkg.size)}" + operation.progress = pkg.custom_partially_valid_at_bytes.to_f / pkg.size + end + + update_interface_task_status + end + + @status.operations.delete_if { |key, o| o.progress >= 1.0 } + + @status.step = :fetch_packages + @total_bytes_to_download = @packages_to_download.sum { |pkg| pkg.size - pkg.custom_partially_valid_at_bytes } @bytes_downloaded = 0 @packages_to_download.each do |pkg| - package_bytes_downloaded = 0 + package_bytes_downloaded = pkg.custom_partially_valid_at_bytes package_fetch(pkg) do |chunk, remaining_bytes, total_bytes| @bytes_downloaded += chunk.to_s.length package_bytes_downloaded += chunk.to_s.length - update_application_taskbar( - "Downloading #{@application.name}...", - "#{W3DHub.format_size(@bytes_downloaded)} / #{W3DHub.format_size(@total_bytes_to_download)}", - @bytes_downloaded.to_f / @total_bytes_to_download - ) + @status.value = "#{W3DHub.format_size(@bytes_downloaded)} / #{W3DHub.format_size(@total_bytes_to_download)}" + @status.progress = @bytes_downloaded.to_f / @total_bytes_to_download - update_download_manager_task( - pkg.checksum, - pkg.name, - "#{W3DHub.format_size(package_bytes_downloaded)} / #{W3DHub.format_size(total_bytes)}", - package_bytes_downloaded.to_f / total_bytes - ) + operation = @status.operations[:"#{pkg.checksum}"] + operation.value = "#{W3DHub.format_size(package_bytes_downloaded)} / #{W3DHub.format_size(pkg.size)}" + operation.progress = package_bytes_downloaded.to_f / total_bytes + + update_interface_task_status end end else @@ -260,33 +292,75 @@ class W3DHub puts "Unpacking packages in '#{path}'..." Cache.create_directories(path, true) + @status.operations.clear + @status.label = "Installing #{@application.name}..." + @status.value = "Unpacking..." + @status.progress = 0.0 + + packages.each do |pkg| + @status.operations[:"#{pkg.checksum}"] = Status::Operation.new( + label: pkg.name, + value: "Pending", + progress: 0.0 + ) + end + + @status.step = :unpacking + + # TODO: Add support for patches packages.each do |package| puts " #{package.name}:#{package.version}" package_path = Cache.package_path(package.category, package.subcategory, "#{package.name}.zip", package.version) puts " Running #{W3DHub.tar_command} command: #{"#{W3DHub.tar_command} -xf #{package_path} -C #{path}"}" status = system("#{W3DHub.tar_command} -xf #{package_path} -C #{path}") + if status + @status.operations[:"#{pkg.checksum}"].value = "Unpacked" + @status.operations[:"#{pkg.checksum}"].progress = 1.0 + + update_interface_task_status else puts "COMMAND FAILED!" fail!("Failed to unpack #{package.name}") + break end end end def create_wine_prefix - if W3DHub.unix? + if W3DHub.unix? && @wine_prefix # TODO: create a wine prefix if configured + @status.operations.clear + @status.label = "Installing #{@application.name}..." + @status.value = "Creating wine prefix..." + @status.progress = 0.0 + + @status.step = :create_wine_prefix end end def install_dependencies(packages) + # TODO: install dependencies + @status.operations.clear + @status.label = "Installing #{@application.name}..." + @status.value = "Installing dependencies..." + @status.progress = 0.0 + + @status.step = :install_dependencies end def mark_application_installed Store.application_manager.installed!(self) + @status.operations.clear + @status.label = "Installed #{@application.name}" + @status.value = "" + @status.progress = 1.0 + + @status.step = :mark_application_installed + puts "#{@app_id} has been installed." end @@ -353,12 +427,20 @@ class W3DHub return false unless File.exist?(path) + operation = @status.operations[:"#{package.checksum}"] + operation&.value = "Verifying..." + file_size = File.size(path) puts " File size: #{file_size}" chunk_size = package.checksum_chunk_size + chunks = package.checksum_chunks.size File.open(path) do |f| + i = -1 package.checksum_chunks.each do |chunk_start, checksum| + i += 1 + operation&.progress = i.to_f / chunks + chunk_start = Integer(chunk_start.to_s) read_length = chunk_size diff --git a/lib/application_manager/tasks/installer.rb b/lib/application_manager/tasks/installer.rb index ffbd05f..7a8a2f8 100644 --- a/lib/application_manager/tasks/installer.rb +++ b/lib/application_manager/tasks/installer.rb @@ -9,11 +9,11 @@ class W3DHub fail_fast return false if failed? - update_application_taskbar("Downloading #{@application.name}...", "Fetching manifests...", 0.0) + # update_application_taskbar("Downloading #{@application.name}...", "Fetching manifests...", 0.0) manifests = fetch_manifests return false if failed? - update_application_taskbar("Downloading #{@application.name}...", "Building package list...", 0.0) + # update_application_taskbar("Downloading #{@application.name}...", "Building package list...", 0.0) packages = build_package_list(manifests) return false if failed? @@ -21,21 +21,21 @@ class W3DHub fetch_packages(packages) return false if failed? - update_application_taskbar("Downloading #{@application.name}...", "Verifying packages...", 0.0) + # update_application_taskbar("Downloading #{@application.name}...", "Verifying packages...", 0.0) verify_packages(packages) return false if failed? - update_application_taskbar("Installing #{@application.name}...", "Unpacking...", 0.0) + # update_application_taskbar("Installing #{@application.name}...", "Unpacking...", 0.0) unpack_packages(packages) return false if failed? sleep 1 - update_application_taskbar("Installing #{@application.name}...", "Creating wine prefix...", 0.0) + # update_application_taskbar("Installing #{@application.name}...", "Creating wine prefix...", 0.0) create_wine_prefix return false if failed? sleep 1 - update_application_taskbar("Installing #{@application.name}...", "Installing dependencies...", 0.0) + # update_application_taskbar("Installing #{@application.name}...", "Installing dependencies...", 0.0) install_dependencies(packages) return false if failed? sleep 1 @@ -43,7 +43,7 @@ class W3DHub mark_application_installed return false if failed? - update_application_taskbar("Installed #{@application.name}", "", 1.0) + # update_application_taskbar("Installed #{@application.name}", "", 1.0) sleep 5 hide_application_taskbar diff --git a/lib/cache.rb b/lib/cache.rb index 30abda4..e717ecf 100644 --- a/lib/cache.rb +++ b/lib/cache.rb @@ -55,10 +55,10 @@ class W3DHub create_directories(path) - file = File.open(path, "wb") + file = File.open(path, "ab") if (start_from_bytes > 0) headers["Range"] = "bytes=#{start_from_bytes}-#{package.size}" - file.seek(start_from_bytes) + file.pos = start_from_bytes end streamer = lambda do |chunk, remaining_bytes, total_bytes| diff --git a/lib/page.rb b/lib/page.rb index eef9942..25410ec 100644 --- a/lib/page.rb +++ b/lib/page.rb @@ -19,9 +19,6 @@ class W3DHub @host.main_thread_queue end - def update_application_manager_status - end - def options=(options) @options = options end diff --git a/lib/pages/download_manager.rb b/lib/pages/download_manager.rb index 86a9cc4..0043edd 100644 --- a/lib/pages/download_manager.rb +++ b/lib/pages/download_manager.rb @@ -1,13 +1,13 @@ class W3DHub class Pages class DownloadManager < Page - attr_reader :download_package_info + attr_reader :operation_info def setup - @download_package_info ||= {} - @task = Store.application_manager.current_task + @operation_info ||= {} + task = Store.application_manager.current_task - unless @task + unless task body.clear do tagline "No operations pending.", width: 1.0, text_align: :center, margin: 128 end @@ -15,50 +15,61 @@ class W3DHub return end + regenerate(task) + end + + def regenerate(task) + @operation_info[:___step] = task.status.step + body.clear do stack(width: 1.0, height: 1.0) do # TODO: Show correct application details here flow(width: 1.0, height: 0.1, padding: 8) do - background @task.application.color + background task.application.color flow(width: 0.70, height: 1.0) do - @application_image = image "#{GAME_ROOT_PATH}/media/icons/#{@task.app_id}.png", height: 1.0 + @application_image = image "#{GAME_ROOT_PATH}/media/icons/#{task.app_id}.png", height: 1.0 stack(margin_left: 8) do - @application_name_label = tagline "#{@task.application.name}" - @application_version_label = inscription "Version: #{@task.channel.current_version} (#{@task.channel.id})" + @application_name_label = tagline "#{task.application.name}" + @application_version_label = inscription "Version: #{task.channel.current_version} (#{task.channel.id})" end end - puts "OKAY" - flow(width: 0.30, height: 1.0) do stack(width: 0.499, height: 1.0) do para "Download Speed", width: 1.0, text_align: :center - @download_speed_label = inscription "0 b/s", width: 1.0, text_align: :center + @download_speed_label = inscription "- b/s", width: 1.0, text_align: :center end stack(width: 0.5, height: 1.0) do para "Downloaded", width: 1.0, text_align: :center - inscription "325.8 MB / 1.39 GB", width: 1.0, text_align: :center + inscription "---- b / ---- b", width: 1.0, text_align: :center end end end # Operations - @downloads_container = stack(width: 1.0, height: 0.9, padding: 8, scroll: true) do + @operations_container = stack(width: 1.0, height: 0.9, padding: 8, scroll: true) do # TODO: Show actual list of downloads - @task&.packages_to_download&.each_with_index do |pkg, i| + p ["DOWNLOAD MANAGER", task.status.operations.size] + + i = -1 + task.status.operations.each do |key, operation| + i += 1 + + p [key, operation.label] + stack(width: 1.0, height: 24, padding: 8) do background 0xff_333333 if i.odd? flow(width: 1.0, height: 22) do - @download_package_info["#{pkg.checksum}_name"] = inscription pkg.name, width: 0.7, text_wrap: :none, tag: "#{pkg.checksum}_name" - @download_package_info["#{pkg.checksum}_status"] = inscription "Pending...", width: 0.3, text_align: :right, text_wrap: :none, tag: "#{pkg.checksum}_status" + @operation_info["#{key}_name"] = inscription operation.label, width: 0.7, text_wrap: :none, tag: "#{key}_name" + @operation_info["#{key}_status"] = inscription operation.value, width: 0.3, text_align: :right, text_wrap: :none, tag: "#{key}_status" end - @download_package_info["#{pkg.checksum}_progress"] = progress fraction: 0.0, height: 2, width: 1.0, tag: "#{pkg.checksum}_progress" + @operation_info["#{key}_progress"] = progress fraction: operation.progress, height: 2, width: 1.0, tag: "#{key}_progress" end end end diff --git a/lib/states/interface.rb b/lib/states/interface.rb index 23ad9c2..3d451d0 100644 --- a/lib/states/interface.rb +++ b/lib/states/interface.rb @@ -174,10 +174,6 @@ class W3DHub @page.focus end - def update_application_manager_status - @page.update_application_manager_status - end - def show_application_taskbar @application_taskbar_container.show end @@ -186,30 +182,38 @@ class W3DHub @application_taskbar_container.hide end - def update_application_taskbar(message, status, progress) - @application_taskbar_label.value = message - @application_taskbar_status_label.value = status - @application_taskbar_progressbar.value = progress.clamp(0.0, 1.0) - end + def update_interface_task_status(task) + show_application_taskbar - # def update_download_manager_state(application, channel) - # end + @application_taskbar_label.value = task.status.label + @application_taskbar_status_label.value = task.status.value + @application_taskbar_progressbar.value = task.status.progress.clamp(0.0, 1.0) - def update_download_manager_list - end - - def update_download_manager_task(checksum, name, status, progress) return unless @page.is_a?(Pages::DownloadManager) - download_package_info = @page.download_package_info + operation_info = @page.operation_info + operation_step = @page.operation_info[:___step] - name_ = download_package_info["#{checksum}_name"] - status_ = download_package_info["#{checksum}_status"] - progress_ = download_package_info["#{checksum}_progress"] + if task.status.step != operation_step + @page.regenerate(task) - name_.value = name if name - status_.value = status if status - progress_.value = progress if progress + return + end + + task.status.operations.each do |key, operation| + + name_ = operation_info["#{key}_name"] + status_ = operation_info["#{key}_status"] + progress_ = operation_info["#{key}_progress"] + + next if name_.value == operation.label && + status_.value == operation.value && + progress_.value == operation.value + + name_.value = operation.label if operation.label + status_.value = operation.value if operation.value + progress_.value = operation.progress.clamp(0.0, 1.0) if operation.progress + end end end end diff --git a/lib/window.rb b/lib/window.rb index f2f6dc1..3f929b8 100644 --- a/lib/window.rb +++ b/lib/window.rb @@ -22,7 +22,6 @@ class W3DHub super Store.application_manager.start_next_available_task if Store.application_manager.idle? - current_state.update_application_manager_status if current_state.is_a?(States::Interface) end def close diff --git a/w3dhub.rb b/w3dhub.rb index a51b64c..9e9310b 100644 --- a/w3dhub.rb +++ b/w3dhub.rb @@ -35,6 +35,7 @@ require_relative "lib/settings" require_relative "lib/mixer" require_relative "lib/application_manager" require_relative "lib/application_manager/manifest" +require_relative "lib/application_manager/status" require_relative "lib/application_manager/task" require_relative "lib/application_manager/tasks/installer" require_relative "lib/application_manager/tasks/uninstaller"