mirror of
https://github.com/cyberarm/cyberarm_engine.git
synced 2025-12-16 21:22:33 +00:00
Added download manager, added excon dependency
This commit is contained in:
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
|
|||||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||||
spec.require_paths = ["lib", "assets"]
|
spec.require_paths = ["lib", "assets"]
|
||||||
|
|
||||||
|
spec.add_dependency "excon", "~> 0.76.0"
|
||||||
spec.add_dependency "gosu", "~> 0.15.0"
|
spec.add_dependency "gosu", "~> 0.15.0"
|
||||||
spec.add_dependency "gosu_more_drawables", "~> 0.3"
|
spec.add_dependency "gosu_more_drawables", "~> 0.3"
|
||||||
spec.add_dependency "clipboard", "~> 1.3.4"
|
spec.add_dependency "clipboard", "~> 1.3.4"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ rescue LoadError => e
|
|||||||
require "gosu"
|
require "gosu"
|
||||||
end
|
end
|
||||||
require "json"
|
require "json"
|
||||||
|
require "excon"
|
||||||
require "gosu_more_drawables"
|
require "gosu_more_drawables"
|
||||||
require "clipboard"
|
require "clipboard"
|
||||||
|
|
||||||
|
|||||||
4
lib/cyberarm_engine/cache.rb
Normal file
4
lib/cyberarm_engine/cache.rb
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
module CyberarmEngine
|
||||||
|
module Cache
|
||||||
|
end
|
||||||
|
end
|
||||||
119
lib/cyberarm_engine/cache/download_manager.rb
vendored
Normal file
119
lib/cyberarm_engine/cache/download_manager.rb
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
module CyberarmEngine
|
||||||
|
module Cache
|
||||||
|
class DownloadManager
|
||||||
|
attr_reader :downloads
|
||||||
|
|
||||||
|
def initialize(max_parallel_downloads: 4)
|
||||||
|
@max_parallel_downloads = max_parallel_downloads
|
||||||
|
@downloads = []
|
||||||
|
end
|
||||||
|
|
||||||
|
def download(url:, save_as: nil, &callback)
|
||||||
|
uri = URI(url)
|
||||||
|
save_as ||= "filename_path" # TODO: if no save_as path is provided, then get one from the Cache controller
|
||||||
|
|
||||||
|
@downloads << Download.new(uri: uri, save_as: save_as, callback: callback)
|
||||||
|
end
|
||||||
|
|
||||||
|
def status
|
||||||
|
if active_downloads > 0
|
||||||
|
:busy
|
||||||
|
else
|
||||||
|
:idle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def progress
|
||||||
|
remaining_bytes = @downloads.map { |d| d.remaining_bytes }.sum
|
||||||
|
total_bytes = @downloads.map { |d| d.total_bytes }.sum
|
||||||
|
|
||||||
|
v = 1.0 - (remaining_bytes.to_f / total_bytes.to_f)
|
||||||
|
return 0.0 if v.nan?
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
def active_downloads
|
||||||
|
@downloads.select { |d| [:pending, :downloading].include?(d.status) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@downloads.each do |download|
|
||||||
|
if download.status == :pending && active_downloads.size <= @max_parallel_downloads
|
||||||
|
download.status = :downloading
|
||||||
|
Thread.start { download.download }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def prune
|
||||||
|
@downloads.delete_if { |d| d.status == :finished || d.status == :failed }
|
||||||
|
end
|
||||||
|
|
||||||
|
class Download
|
||||||
|
attr_accessor :status
|
||||||
|
attr_reader :uri, :save_as, :callback, :remaining_bytes, :total_downloaded_bytes, :total_bytes,
|
||||||
|
:error_message, :started_at, :finished_at
|
||||||
|
def initialize(uri:, save_as:, callback: nil)
|
||||||
|
@uri = uri
|
||||||
|
@save_as = save_as
|
||||||
|
@callback = callback
|
||||||
|
|
||||||
|
@status = :pending
|
||||||
|
|
||||||
|
@remaining_bytes = 0.0
|
||||||
|
@total_downloaded_bytes = 0.0
|
||||||
|
@total_bytes = 0.0
|
||||||
|
|
||||||
|
@error_message = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def progress
|
||||||
|
v = 1.0 - (@remaining_bytes.to_f / total_bytes.to_f)
|
||||||
|
return 0.0 if v.nan?
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
def download
|
||||||
|
@status = :downloading
|
||||||
|
@started_at = Time.now # TODO: monotonic time
|
||||||
|
|
||||||
|
io = File.open(@save_as, "w")
|
||||||
|
streamer = lambda do |chunk, remaining_bytes, total_bytes|
|
||||||
|
io.write(chunk)
|
||||||
|
|
||||||
|
@remaining_bytes = remaining_bytes.to_f
|
||||||
|
@total_downloaded_bytes += chunk.size
|
||||||
|
@total_bytes = total_bytes.to_f
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
response = Excon.get(
|
||||||
|
@uri.to_s,
|
||||||
|
middlewares: Excon.defaults[:middlewares] + [Excon::Middleware::RedirectFollower],
|
||||||
|
response_block: streamer
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.status == 200
|
||||||
|
@status = :finished
|
||||||
|
@finished_at = Time.now # TODO: monotonic time
|
||||||
|
@callback.call(self) if @callback
|
||||||
|
else
|
||||||
|
@error_message = "Got a non 200 HTTP status of #{response.status}"
|
||||||
|
@status = :failed
|
||||||
|
@finished_at = Time.now # TODO: monotonic time
|
||||||
|
@callback.call(self) if @callback
|
||||||
|
end
|
||||||
|
rescue => e # TODO: cherrypick errors to cature
|
||||||
|
@status = :failed
|
||||||
|
@finished_at = Time.now # TODO: monotonic time
|
||||||
|
@error_message = e.message
|
||||||
|
@callback.call(self) if @callback
|
||||||
|
end
|
||||||
|
|
||||||
|
ensure
|
||||||
|
io.close if io
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user