diff --git a/lib/api.rb b/lib/api.rb
index 3318c5d..dbe4a4e 100644
--- a/lib/api.rb
+++ b/lib/api.rb
@@ -3,7 +3,7 @@ class W3DHub
LOG_TAG = "W3DHub::Api".freeze
- API_TIMEOUT = 30 # seconds
+ API_TIMEOUT = 10 # seconds
USER_AGENT = "Cyberarm's Linux Friendly W3D Hub Launcher v#{W3DHub::VERSION}".freeze
DEFAULT_HEADERS = [
["user-agent", USER_AGENT],
@@ -25,7 +25,7 @@ class W3DHub
HTTP_CLIENTS = {}
- def self.async_http(method, path, headers = DEFAULT_HEADERS, body = nil, backend = :w3dhub, &callback)
+ def self.async_http(method:, path:, headers:, body:, backend:, async:, &callback)
raise "NO CALLBACK DEFINED!" unless callback
case backend
@@ -56,35 +56,20 @@ class W3DHub
headers << ["authorization", "Bearer #{Store.account.access_token}"]
end
- Store.network_manager.request(method, url, headers, body, nil, &callback)
+ Store.network_manager.request(method, url, headers, body, async, &callback)
end
- def self.provision_http_client(hostname)
- # Pin http clients to their host Thread so the fiber scheduler doesn't get upset and raise an error
- HTTP_CLIENTS[Thread.current] ||= {}
- return HTTP_CLIENTS[Thread.current][hostname.downcase] if HTTP_CLIENTS[Thread.current][hostname.downcase]
-
- ssl_context = W3DHub.ca_bundle_path ? OpenSSL::SSL::SSLContext.new : nil
- ssl_context&.set_params(
- ca_file: W3DHub.ca_bundle_path,
- verify_mode: OpenSSL::SSL::VERIFY_PEER
- )
-
- endpoint = Async::HTTP::Endpoint.parse(hostname, ssl_context: ssl_context)
- HTTP_CLIENTS[Thread.current][hostname.downcase] = Async::HTTP::Client.new(endpoint)
+ def self.post(path:, headers: DEFAULT_HEADERS, body: nil, backend: :w3dhub, async: true, &callback)
+ async_http(method: :post, path: path, headers: headers, body: body, backend: backend, async: async, &callback)
end
- def self.post(path, headers = DEFAULT_HEADERS, body = nil, backend = :w3dhub, &callback)
- async_http(:post, path, headers, body, backend, &callback)
- end
-
- def self.get(path, headers = DEFAULT_HEADERS, body = nil, backend = :w3dhub, &callback)
- async_http(:get, path, headers, body, backend, &callback)
+ def self.get(path:, headers: DEFAULT_HEADERS, body: nil, backend: :w3dhub, async: true, &callback)
+ async_http(method: :get, path: path, headers: headers, body: body, backend: backend, async: async, &callback)
end
# Api.get but handles any URL instead of known hosts
- def self.fetch(path, headers = DEFAULT_HEADERS, body = nil, backend = nil, &callback)
- async_http(:get, path, headers, body, backend, &callback)
+ def self.fetch(path:, headers: DEFAULT_HEADERS, body: nil, backend: :w3dhub, async: true, &callback)
+ async_http(method: :get, path: path, headers: headers, body: body, backend: backend, async: async, &callback)
end
# Method: POST
@@ -103,73 +88,76 @@ class W3DHub
# On a failed login the service responds with:
# {"error":"login-failed"}
def self.refresh_user_login(refresh_token, backend = :w3dhub, &callback)
+ body = URI.encode_www_form("data": JSON.dump({ refreshToken: refresh_token }))
+
handler = lambda do |result|
if result.okay?
user_data = JSON.parse(result.data, symbolize_names: true)
if user_data[:error]
- callback.call(false)
+ callback.call(CyberarmEngine::Result.new(data: false))
next
end
user_details_data = user_details(user_data[:userid]) || {}
- callback.call(Account.new(user_data, user_details_data))
+ callback.call(CyberarmEngine::Result.new(data: Account.new(user_data, user_details_data)))
else
logger.error(LOG_TAG) { "Failed to fetch refresh user login:" }
logger.error(LOG_TAG) { result.error }
- callback.call(false)
+ callback.call(result)
end
end
- body = URI.encode_www_form("data": JSON.dump({ refreshToken: refresh_token }))
- post("/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body, backend, &handler)
+ post(path: "/apis/launcher/1/user-login", headers: FORM_ENCODED_HEADERS, body: body, backend: backend, &handler)
end
# See #user_refresh_token
def self.user_login(username, password, backend = :w3dhub, &callback)
+ body = URI.encode_www_form("data": JSON.dump({ username: username, password: password }))
+
handler = lambda do |result|
if result.okay?
user_data = JSON.parse(result.data, symbolize_names: true)
if user_data[:error]
- callback.call(false)
+ callback.call(CyberarmEngine::Result.new(data: false))
next
end
user_details_data = user_details(user_data[:userid]) || {}
- callback.call(Account.new(user_data, user_details_data))
+ callback.call(CyberarmEngine::Result.new(data: Account.new(user_data, user_details_data)))
else
logger.error(LOG_TAG) { "Failed to fetch user login:" }
logger.error(LOG_TAG) { result.error }
- callback.call(false)
+ callback.call(result)
end
end
- body = URI.encode_www_form("data": JSON.dump({ username: username, password: password }))
- post("/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body, backend, &handler)
+ post(path: "/apis/launcher/1/user-login", headers: FORM_ENCODED_HEADERS, body: body, backend: backend, &handler)
end
# /apis/w3dhub/1/get-user-details
#
# Response: avatar-uri (Image download uri), id, username
def self.user_details(id, backend = :w3dhub, &callback)
+ body = URI.encode_www_form("data": JSON.dump({ id: id }))
+
handler = lambda do |result|
if result.okay?
- callback.call(JSON.parse(result.data, symbolize_names: true))
+ callback.call(CyberarmEngine::Result.new(data: JSON.parse(result.data, symbolize_names: true)))
else
logger.error(LOG_TAG) { "Failed to fetch user details:" }
logger.error(LOG_TAG) { result.error }
- callback.call(false)
+ callback.call(result)
end
end
- body = URI.encode_www_form("data": JSON.dump({ id: id }))
- post("/apis/w3dhub/1/get-user-details", FORM_ENCODED_HEADERS, body, backend, &handler)
+ post(path: "/apis/w3dhub/1/get-user-details", headers: FORM_ENCODED_HEADERS, body: body, backend: backend, &handler)
end
# /apis/w3dhub/1/get-service-status
@@ -178,16 +166,16 @@ class W3DHub
def self.service_status(backend = :w3dhub, &callback)
handler = lambda do |result|
if result.okay?
- callback.call(ServiceStatus.new(result.data))
+ callback.call(CyberarmEngine::Result.new(data: ServiceStatus.new(result.data)))
else
logger.error(LOG_TAG) { "Failed to fetch service status:" }
logger.error(LOG_TAG) { result.error }
- callback.call(false)
+ callback.call(result)
end
end
- post("/apis/w3dhub/1/get-service-status", DEFAULT_HEADERS, nil, backend, &handler)
+ post(path: "/apis/w3dhub/1/get-service-status", backend: backend, &handler)
end
# /apis/launcher/1/get-applications
@@ -195,87 +183,104 @@ class W3DHub
# Launcher sends an empty data request: data={}
# Response is a list of applications/games
def self.applications(backend = :w3dhub, &callback)
+ async = !callback.nil?
+
+ # Complicated why to "return" direct value
+ callback = ->(result) { result }
+
handler = lambda do |result|
if result.okay?
- callback.call(Applications.new(result.data, backend))
+ callback.call(CyberarmEngine::Result.new(data: Applications.new(result.data, backend)))
else
logger.error(LOG_TAG) { "Failed to fetch applications list:" }
logger.error(LOG_TAG) { result.error }
- callback.call(false)
+ callback.call(result)
end
end
- post("/apis/launcher/1/get-applications", DEFAULT_HEADERS, nil, backend, &handler)
+ post(path: "/apis/launcher/1/get-applications", async: async, backend: backend, &handler)
end
# Populate applications list from primary and alternate backends
# (alternate only has latest public builds of _most_ games)
- def self._applications
- applications_primary = Store.account ? Api.applications(:w3dhub) : false
- applications_alternate = Api.applications(:alt_w3dhub)
+ def self._applications(&callback)
+ handler = lambda do |result|
+ # nothing special on offer if we're not logged in
+ applications_primary = Store.account ? Api.applications(:w3dhub).data : false
+ applications_alternate = Api.applications(:alt_w3dhub).data
- # Fail if we fail to fetch applications list from either backend
- return false unless applications_primary || applications_alternate
+ # Fail if we fail to fetch applications list from either backend
+ unless applications_primary || applications_alternate
+ callback.call(CyberarmEngine::Result.new)
+ next
+ end
- return applications_alternate unless applications_primary
+ unless applications_primary
+ callback.call(CyberarmEngine::Result.new(data: applications_alternate))
+ next
+ end
- # Merge the two app lists together
- apps = applications_alternate
- if applications_primary
- applications_primary.games.each do |game|
- # Check if game exists in alternate list
- _game = apps.games.find { |g| g.id == game.id }
- unless _game
- apps.games << game
+ # Merge the two app lists together
+ apps = applications_alternate
+ if applications_primary
+ applications_primary.games.each do |game|
+ # Check if game exists in alternate list
+ _game = apps.games.find { |g| g.id == game.id }
+ unless _game
+ apps.games << game
- # App didn't exist in alternates list
- # comparing channels isn't useful
- next
- end
-
- # If it does, check that all of its channels also exist in alternate list
- # and that the primary versions are the same as the alternates list
- game.channels.each do |channel|
- _channel = _game.channels.find { |c| c.id == channel.id }
-
- unless _channel
- _game.channels << channel
-
- # App didn't have channel in alternates list
- # comparing channel isn't useful
+ # App didn't exist in alternates list
+ # comparing channels isn't useful
next
end
- # If channel versions and access levels match then all's well
- if channel.current_version == _channel.current_version &&
- channel.user_level == _channel.user_level
+ # If it does, check that all of its channels also exist in alternate list
+ # and that the primary versions are the same as the alternates list
+ game.channels.each do |channel|
+ _channel = _game.channels.find { |c| c.id == channel.id }
- # All's Well!
- next
- end
+ unless _channel
+ _game.channels << channel
- # If the access levels don't match then overwrite alternate's channel with primary's channel
- if channel.user_level != _channel.user_level
- # Replace alternate's channel with primary's channel
- _game.channels[_game.channels.index(_channel)] = channel
+ # App didn't have channel in alternates list
+ # comparing channel isn't useful
+ next
+ end
- # Replaced, continue.
- next
- end
+ # If channel versions and access levels match then all's well
+ if channel.current_version == _channel.current_version &&
+ channel.user_level == _channel.user_level
- # If versions don't match then pick whichever one is higher
- if Gem::Version.new(channel.current_version) > Gem::Version.new(_channel.current_version)
- # Replace alternate's channel with primary's channel
- _game.channels[_game.channels.index(_channel)] = channel
- else
- # Do nothing, alternate backend version is greater.
+ # All's Well!
+ next
+ end
+
+ # If the access levels don't match then overwrite alternate's channel with primary's channel
+ if channel.user_level != _channel.user_level
+ # Replace alternate's channel with primary's channel
+ _game.channels[_game.channels.index(_channel)] = channel
+
+ # Replaced, continue.
+ next
+ end
+
+ # If versions don't match then pick whichever one is higher
+ if Gem::Version.new(channel.current_version) > Gem::Version.new(_channel.current_version)
+ # Replace alternate's channel with primary's channel
+ _game.channels[_game.channels.index(_channel)] = channel
+ else
+ # Do nothing, alternate backend version is greater.
+ end
end
end
end
+
+ callback.call(CyberarmEngine::Result.new(data: apps))
end
- apps
+ # Bit hacky but we just need to run this handler from the networking thread and async reactor
+ get(path: "", backend: nil, &handler)
end
# /apis/w3dhub/1/get-news
@@ -285,18 +290,18 @@ class W3DHub
def self.news(category, backend = :w3dhub, &callback)
handler = lambda do |result|
if result.okay?
- callback.call(News.new(result.data))
+ callback.call(CyberarmEngine::Result.new(data: News.new(result.data)))
else
logger.error(LOG_TAG) { "Failed to fetch news for:" }
logger.error(LOG_TAG) { category }
logger.error(LOG_TAG) { result.error }
- callback.call(false)
+ callback.call(result)
end
end
body = URI.encode_www_form("data": JSON.dump({ category: category }))
- post("/apis/w3dhub/1/get-news", FORM_ENCODED_HEADERS, body, backend, &handler)
+ post(path: "/apis/w3dhub/1/get-news", headers: FORM_ENCODED_HEADERS, body: body, backend: backend, &handler)
end
# Downloading games
@@ -308,18 +313,18 @@ class W3DHub
if result.okay?
hash = JSON.parse(result.data, symbolize_names: true)
- callback.call(hash[:packages].map { |pkg| Package.new(pkg) })
+ callback.call(CyberarmEngine::Result.new(data: hash[:packages].map { |pkg| Package.new(pkg) }))
else
logger.error(LOG_TAG) { "Failed to fetch package details for:" }
logger.error(LOG_TAG) { packages }
logger.error(LOG_TAG) { result.error }
- callback.call(false)
+ callback.call(result)
end
end
body = URI.encode_www_form("data": JSON.dump({ packages: packages }))
- post("/apis/launcher/1/get-package-details", FORM_ENCODED_HEADERS, body, backend, &handler)
+ post(path: "/apis/launcher/1/get-package-details", headers: FORM_ENCODED_HEADERS, body: body, backend: backend, &handler)
end
# /apis/launcher/1/get-package
@@ -337,15 +342,15 @@ class W3DHub
def self.events(app_id, backend = :w3dhub, &callback)
handler = lambda do |result|
if result.okay?
- array = JSON.parse(response.body, symbolize_names: true)
- callback.call(array.map { |e| Event.new(e) })
+ array = JSON.parse(result.data, symbolize_names: true)
+ callback.call(CyberarmEngine::Result.new(data: array.map { |e| Event.new(e) }))
else
- callback.call(false)
+ callback.call(result)
end
end
body = URI.encode_www_form("data": JSON.dump({ serverPath: app_id }))
- post("/apis/w3dhub/1/get-server-events", FORM_ENCODED_HEADERS, body, backend, &handler)
+ post(path: "/apis/w3dhub/1/get-server-events", headers: FORM_ENCODED_HEADERS, body: body, backend: backend, &handler)
end
#! === Server List API === !#
@@ -375,13 +380,13 @@ class W3DHub
handler = lambda do |result|
if result.okay?
data = JSON.parse(result.data, symbolize_names: true)
- callback.call(data.map { |hash| ServerListServer.new(hash) })
+ callback.call(CyberarmEngine::Result.new(data: data.map { |hash| ServerListServer.new(hash) }))
else
- callback.call(false)
+ callback.call(result)
end
end
- get("/listings/getAll/v2?statusLevel=#{level}", DEFAULT_HEADERS, nil, backend, &handler)
+ get(path: "/listings/getAll/v2?statusLevel=#{level}", backend: backend, &handler)
end
# /listings/getStatus/v2/:id?statusLevel=#{0-2}
@@ -400,13 +405,13 @@ class W3DHub
handler = lambda do |result|
if result.okay?
- callback.call(JSON.parse(response.body, symbolize_names: true))
+ callback.call(CyberarmEngine::Result.new(data: JSON.parse(result.data, symbolize_names: true)))
else
- callback.call(false)
+ callback.call(result)
end
end
- get("/listings/getStatus/v2/#{id}?statusLevel=#{level}", DEFAULT_HEADERS, nil, backend, &handler)
+ get(path: "/listings/getStatus/v2/#{id}?statusLevel=#{level}", backend: backend, &handler)
end
# /listings/push/v2/negotiate?negotiateVersion=1
diff --git a/lib/cache.rb b/lib/cache.rb
index 0e265e8..89b8ff6 100644
--- a/lib/cache.rb
+++ b/lib/cache.rb
@@ -15,7 +15,7 @@ class W3DHub
if !force_fetch && File.exist?(path)
path
else
- Api.fetch(uri, W3DHub::Api::DEFAULT_HEADERS, nil, backend) do |result|
+ Api.fetch(path: uri, backend: backend) do |result|
if result.okay?
File.open(path, "wb") { |f| f.write result.data }
end
diff --git a/lib/network_manager.rb b/lib/network_manager.rb
index 7e77e96..49e5fa2 100644
--- a/lib/network_manager.rb
+++ b/lib/network_manager.rb
@@ -2,22 +2,21 @@ class W3DHub
# all http(s) requests for API calls and downloading images run through here
class NetworkManager
NetworkEvent = Data.define(:context, :result)
- Request = Struct.new(:active, :context, :callback)
+ Request = Struct.new(:active, :context, :async, :callback)
Context = Data.define(
:request_id,
:method,
:url,
:headers,
- :body,
- :bearer_token
+ :body
)
def initialize
@requests = []
@running = true
- Thread.new do
- http_client = HttpClient.new
+ @thread = Thread.new do
+ @http_client = HttpClient.new
Sync do
while @running
@@ -33,18 +32,25 @@ class W3DHub
Async do |task|
assigned_request = request
- result = http_client.handle(task, assigned_request)
+ result = if assigned_request.context.url.empty?
+ assigned_request.callback.call(nil)
+ else
+ @http_client.handle(task, assigned_request)
+ end
@requests.delete(assigned_request)
- Store.main_thread_queue << -> { assigned_request.callback.call(result) }
+ # callback for this is already handled!
+ unless assigned_request.context.url.empty?
+ Store.main_thread_queue << -> { assigned_request.callback.call(result) }
+ end
end
end
end
end
end
- def request(method, url, headers, body, bearer_token, &block)
+ def request(method, url, headers, body, async, &block)
request_id = SecureRandom.hex
request = Request.new(
@@ -54,15 +60,29 @@ class W3DHub
method,
url,
headers,
- body,
- bearer_token
+ body
),
+ async,
block
)
@requests << request
- request_id
+
+ if async
+ request_id
+ else # Not async, process immediately.
+ raise "WTF? This should NOT happen!" unless Async::Task.current?
+
+ Sync do |task|
+ assigned_request = request
+ result = @http_client.handle(task, assigned_request)
+
+ @requests.delete(assigned_request)
+ # "return" callback "value"
+ assigned_request.callback.call(result)
+ end
+ end
end
def busy?
diff --git a/lib/network_manager/http_client.rb b/lib/network_manager/http_client.rb
index a891d1c..46139e9 100644
--- a/lib/network_manager/http_client.rb
+++ b/lib/network_manager/http_client.rb
@@ -10,22 +10,18 @@ class W3DHub
result = CyberarmEngine::Result.new
context = request.context
- task.with_timeout(30) do
+ task.with_timeout(W3DHub::Api::API_TIMEOUT) do
uri = URI(context.url)
- pp uri
-
response = provision_http_client(uri.origin).send(
context.method,
- uri.path,
+ uri.request_uri,
context.headers,
context.body
)
- pp response
-
if response.success?
- result.data = response.body.read
+ result.data = response.read
else
result.error = response
end
diff --git a/lib/pages/community.rb b/lib/pages/community.rb
index 4ae3fdd..19cbe9f 100644
--- a/lib/pages/community.rb
+++ b/lib/pages/community.rb
@@ -65,15 +65,7 @@ class W3DHub
para I18n.t(:"games.fetching_news"), padding: 8
end
- BackgroundWorker.foreground_job(
- -> { fetch_w3dhub_news },
- lambda do |result|
- if result
- populate_w3dhub_news
- Cache.release_net_lock(result)
- end
- end
- )
+ fetch_w3dhub_news
end
end
@@ -89,15 +81,7 @@ class W3DHub
title I18n.t(:"games.fetching_news"), padding: 8
end
- BackgroundWorker.foreground_job(
- -> { fetch_w3dhub_news },
- lambda do |result|
- if result
- populate_w3dhub_news
- Cache.release_net_lock(result)
- end
- end
- )
+ fetch_w3dhub_news
end
end
@@ -105,19 +89,24 @@ class W3DHub
lock = Cache.acquire_net_lock("w3dhub_news")
return false unless lock
- news = Api.news("launcher-home")
- Cache.release_net_lock("w3dhub_news") unless news
+ Api.news("launcher-home") do |result|
+ news = result.data
- return unless news
+ Cache.release_net_lock("w3dhub_news") unless news
- news.items[0..15].each do |item|
- Cache.fetch(uri: item.image, async: false, backend: :w3dhub)
+ next false unless news
+
+ news.items[0..15].each do |item|
+ Cache.fetch(uri: item.image, backend: :w3dhub)
+ end
+
+ @w3dhub_news = news
+ @w3dhub_news_expires = Gosu.milliseconds + (60 * 60 * 1000) # 1 hour (in ms)
+
+ populate_w3dhub_news
+ ensure
+ Cache.release_net_lock("w3dhub_news")
end
-
- @w3dhub_news = news
- @w3dhub_news_expires = Gosu.milliseconds + (60 * 60 * 1000) # 1 hour (in ms)
-
- "w3dhub_news"
end
def populate_w3dhub_news
@@ -125,37 +114,7 @@ class W3DHub
if (feed = @w3dhub_news)
@wd3hub_news_container.clear do
- # feed.items.sort_by { |i| i.timestamp }.reverse[0..9].each do |item|
- # flow(width: 0.5, max_width: 312, height: 128, margin: 4) do
- # # background 0x88_000000
-
- # path = Cache.path(item.image)
-
- # if File.exist?(path)
- # image path, height: 1.0, padding: 4
- # else
- # image BLACK_IMAGE, height: 1.0, padding: 4
- # end
-
- # stack(width: 0.6, height: 1.0) do
- # stack(width: 1.0, height: 112) do
- # link "#{item.title}", text_size: 22 do
- # W3DHub.url(item.uri)
- # end
- # para item.blurb.gsub(/\n+/, "\n").strip[0..180]
- # end
-
- # flow(width: 1.0) do
- # para item.timestamp.strftime("%Y-%m-%d"), width: 0.499
- # link I18n.t(:"games.read_more"), width: 0.5, text_align: :right, text_size: 22 do
- # W3DHub.url(item.uri)
- # end
- # end
- # end
- # end
- # end
-
- feed.items.sort_by { |i| i.timestamp }.reverse[0..9].each do |item|
+ feed.items.sort_by(&:timestamp).reverse[0..9].each do |item|
image_path = Cache.path(item.image)
flow(width: 1.0, max_width: 1230, height: 200, margin: 8, border_thickness: 1, border_color: lighten(Gosu::Color.new(0xff_252525))) do
diff --git a/lib/pages/games.rb b/lib/pages/games.rb
index 81389ed..d551a45 100644
--- a/lib/pages/games.rb
+++ b/lib/pages/games.rb
@@ -31,30 +31,16 @@ class W3DHub
def update
super
-
@game_news.each do |key, value|
- next if key.end_with?("_expires")
+ next unless key.end_with?("_expires")
- if Gosu.milliseconds >= @game_news["#{key}_expires"]
- @game_news.delete(key)
- @game_news["#{key}_expires"] = Gosu.milliseconds + 30_000 # seconds
+ next unless Gosu.milliseconds >= value
- if @focused_game && @focused_game.id == key
- @game_news_container.clear do
- title I18n.t(:"games.fetching_news"), padding: 8
- end
+ # try to refresh game news after last data 'expired', every 30 seconds until success
+ @game_news[key] = Gosu.milliseconds + 30_000 # seconds
- BackgroundWorker.foreground_job(
- -> { fetch_game_news(@focused_game) },
- lambda do |result|
- if result
- populate_game_news(@focused_game)
- Cache.release_net_lock(result)
- end
- end
- )
- end
- end
+ game = Store.applications.games.find { |g| g.id == key.split("_").first }
+ fetch_game_news(game)
end
end
@@ -292,22 +278,6 @@ class W3DHub
return if Store.offline_mode
unless Cache.net_lock?("game_news_#{game.id}")
- if @game_events[game.id]
- populate_game_events(game)
- else
- # BackgroundWorker.foreground_job(
- # -> { fetch_game_events(game) },
- # lambda do |result|
- # if result
- # populate_game_events(game)
- # Cache.release_net_lock(result)
- # end
- # end
- # )
- end
- end
-
- unless Cache.net_lock?("game_events_#{game.id}")
if @game_news[game.id]
populate_game_news(game)
else
@@ -315,15 +285,15 @@ class W3DHub
title I18n.t(:"games.fetching_news"), padding: 8
end
- # BackgroundWorker.foreground_job(
- # -> { fetch_game_news(game) },
- # lambda do |result|
- # if result
- # populate_game_news(game)
- # Cache.release_net_lock(result)
- # end
- # end
- # )
+ fetch_game_news(game)
+ end
+ end
+
+ unless Cache.net_lock?("game_events_#{game.id}")
+ if @game_events[game.id]
+ populate_game_events(game)
+ else
+ fetch_game_events(game)
end
end
end
@@ -413,19 +383,25 @@ class W3DHub
lock = Cache.acquire_net_lock("game_news_#{game.id}")
return false unless lock
- news = Api.news(game.id)
- Cache.release_net_lock("game_news_#{game.id}") unless news
+ Api.news(game.id) do |result|
+ news = result.data
- return false unless news
+ unless news
+ @game_news["#{game.id}_expires"] = Gosu.milliseconds + 30_000 # retry in 30 seconds
+ next false
+ end
- news.items[0..15].each do |item|
- Cache.fetch(uri: item.image, async: false, backend: :w3dhub)
+ news.items[0..15].each do |item|
+ Cache.fetch(uri: item.image, backend: :w3dhub)
+ end
+
+ @game_news[game.id] = news
+ @game_news["#{game.id}_expires"] = Gosu.milliseconds + (60 * 60 * 1000) # 1 hour (in ms)
+
+ populate_game_news(@focused_game)
+ ensure
+ Cache.release_net_lock("game_news_#{game.id}")
end
-
- @game_news[game.id] = news
- @game_news["#{game.id}_expires"] = Gosu.milliseconds + (60 * 60 * 1000) # 1 hour (in ms)
-
- "game_news_#{game.id}"
end
def populate_game_news(game)
@@ -436,38 +412,11 @@ class W3DHub
game_color.alpha = 0xaa
@game_news_container.clear do
- # Patch Notes
- if false # Patch notes
- flow(width: 1.0, max_width: 346 * 3 + (8 * 4), height: 346, margin: 8, margin_right: 32, border_thickness: 1, border_color: darken(Gosu::Color.new(game.color))) do
- background darken(Gosu::Color.new(game.color), 10)
-
- stack(width: 346, height: 1.0, padding: 8) do
- background 0xff_181d22
-
- para "Patch Notes"
-
- tagline "Patch 2.0 is now out!"
-
- para "words go here " * 20
-
- flow(fill: true)
-
- button "Read More", width: 1.0
- end
-
- flow(fill: true)
-
- title "Eye Candy Banner Goes Here."
- end
- end
-
- feed.items.sort_by { |i| i.timestamp }.reverse[0..9].each do |item|
+ feed.items.sort_by(&:timestamp).reverse[0..9].each do |item|
image_path = Cache.path(item.image)
flow(width: 1.0, max_width: 869, height: 200, margin: 8, background: game_color, border_thickness: 1, border_color: lighten(Gosu::Color.new(game.color))) do
- if File.file?(image_path)
- image image_path, height: 1.0
- end
+ image image_path, height: 1.0 if File.file?(image_path)
stack(fill: true, height: 1.0, padding: 4, border_thickness_left: 1, border_color_left: lighten(Gosu::Color.new(game.color))) do
tagline "#{item.title}", width: 1.0
@@ -494,14 +443,14 @@ class W3DHub
lock = Cache.acquire_net_lock("game_events_#{game.id}")
return false unless lock
- events = Api.events(game.id)
- Cache.release_net_lock("game_events_#{game.id}") unless events
+ Api.events(game.id) do |result|
+ next unless result.okay?
- return false unless events
-
- @game_events[game.id] = events
-
- "game_events_#{game.id}"
+ @game_events[game.id] = result.data
+ populate_game_events(game)
+ ensure
+ Cache.release_net_lock("game_events_#{game.id}")
+ end
end
def populate_game_events(game)
diff --git a/lib/pages/server_browser.rb b/lib/pages/server_browser.rb
index cd2232f..d842407 100644
--- a/lib/pages/server_browser.rb
+++ b/lib/pages/server_browser.rb
@@ -145,15 +145,7 @@ class W3DHub
reorder_server_list
if @selected_server&.id == @refresh_server&.id
- if @refresh_server
- BackgroundWorker.foreground_job(
- -> { fetch_server_details(@refresh_server) },
- ->(result) {
- populate_server_info(@refresh_server) if @refresh_server == @selected_server
- @refresh_server = nil
- }
- )
- end
+ fetch_server_details(@refresh_server) if @refresh_server
end
end
end
@@ -353,10 +345,7 @@ class W3DHub
reorder_server_list if @selected_server_container
- BackgroundWorker.foreground_job(
- -> { fetch_server_details(server) },
- ->(result) { populate_server_info(server) if server == @selected_server }
- )
+ fetch_server_details(server)
end
stylize_selected_server(server_container) if server.id == @selected_server&.id
@@ -523,10 +512,13 @@ class W3DHub
end
def fetch_server_details(server)
- BackgroundWorker.foreground_job(
- -> { Api.server_details(server.id, 2) },
- ->(server_data) { server.update(server_data) if server_data }
- )
+ Api.server_details(server.id, 2) do |result|
+ if result.okay?
+ server.update(result.data)
+ populate_server_info(server) if server == @selected_server
+ @refresh_server = nil
+ end
+ end
end
def game_icon(server)
diff --git a/lib/states/boot.rb b/lib/states/boot.rb
index 04f686a..269b205 100644
--- a/lib/states/boot.rb
+++ b/lib/states/boot.rb
@@ -130,7 +130,7 @@ class W3DHub
Store.settings[:account][:data] = account
- Cache.fetch(uri: account.avatar_uri, force_fetch: true, async: false, backend: :w3dhub)
+ Cache.fetch(uri: account.avatar_uri, force_fetch: true, backend: :w3dhub)
else
Store.settings[:account] = {}
end
@@ -176,10 +176,8 @@ class W3DHub
def service_status
@status_label.value = "Checking service status..." #I18n.t(:"server_browser.fetching_server_list")
- Api.on_thread(:service_status) do |service_status|
- pp service_status
-
- @service_status = service_status
+ Api.on_thread(:service_status) do |result|
+ @service_status = result.okay? ? result.data : nil
if @service_status
Store.service_status = @service_status
@@ -190,9 +188,7 @@ class W3DHub
@tasks[:service_status][:complete] = true
else
- BackgroundWorker.foreground_job(-> {}, lambda { |_|
- @status_label.value = I18n.t(:"boot.w3dhub_service_is_down")
- })
+ Store.main_thread_queue << -> { @status_label.value = I18n.t(:"boot.w3dhub_service_is_down") }
@tasks[:service_status][:complete] = true
@offline_mode = true
@@ -204,9 +200,9 @@ class W3DHub
def launcher_updater
@status_label.value = "Checking for Launcher updates..." # I18n.t(:"boot.checking_for_updates")
- Api.on_thread(:fetch, "https://api.github.com/repos/cyberarm/w3d_hub_linux_launcher/releases/latest") do |response|
- if response.status == 200
- hash = JSON.parse(response.body, symbolize_names: true)
+ Api.on_thread(:fetch, "https://api.github.com/repos/cyberarm/w3d_hub_linux_launcher/releases/latest") do |result|
+ if result.okay?
+ hash = JSON.parse(result.data, symbolize_names: true)
available_version = hash[:tag_name].downcase.sub("v", "")
pp Gem::Version.new(available_version) > Gem::Version.new(W3DHub::VERSION)
@@ -230,14 +226,13 @@ class W3DHub
def applications
@status_label.value = I18n.t(:"boot.checking_for_updates")
- # Api.on_thread(:_applications) do |applications|
- Api.on_thread(:applications, :alt_w3dhub) do |applications|
- if applications
- Store.applications = applications
- Store.settings.save_application_cache(applications.data.to_json)
+ Api.on_thread(:_applications) do |result|
+ if result.okay?
+ Store.applications = result.data
+ Store.settings.save_application_cache(Store.applications.data.to_json)
@tasks[:applications][:complete] = true
else
- @status_label.value = "FAILED TO RETREIVE APPS LIST"
+ @status_label.value = "FAILED TO RETRIEVE APPS LIST"
@offline_mode = true
Store.offline_mode = true
@@ -256,40 +251,39 @@ class W3DHub
packages << { category: app.category, subcategory: app.id, name: "#{app.id}.ico", version: "" }
end
- Api.on_thread(:package_details, packages, :alt_w3dhub) do |package_details|
- package_details ||= nil
+ Api.on_thread(:package_details, packages, :alt_w3dhub) do |result|
+ if result.okay?
+ result.data.each do |package|
+ next if package.error?
- package_details&.each do |package|
- next if package.error?
+ path = Cache.package_path(package.category, package.subcategory, package.name, package.version)
+ generated_icon_path = "#{CACHE_PATH}/#{package.subcategory}.png"
- path = Cache.package_path(package.category, package.subcategory, package.name, package.version)
- generated_icon_path = "#{CACHE_PATH}/#{package.subcategory}.png"
+ regenerate = false
- regenerate = false
-
- if File.exist?(path)
- broken_or_out_dated_icon = Digest::SHA256.new.hexdigest(File.binread(path)).upcase != package.checksum.upcase
- end
-
- if File.exist?(path) && !broken_or_out_dated_icon
- regenerate = !File.exist?(generated_icon_path)
- else
- begin
- Cache.fetch_package(package, proc {})
- regenerate = true
- rescue Errno::EACCES => e
- failure = true
- push_state(MessageDialog, title: "Fatal Error",
- message: "Directory Permission Error (#{e.class}):\n#{e}.\n\nIs the required drive mounted?",
- accept_callback: -> { window.close })
+ if File.exist?(path)
+ broken_or_out_dated_icon = Digest::SHA256.new.hexdigest(File.binread(path)).upcase != package.checksum.upcase
end
+
+ if File.exist?(path) && !broken_or_out_dated_icon
+ regenerate = !File.exist?(generated_icon_path)
+ else
+ begin
+ Cache.fetch_package(package, proc {})
+ regenerate = true
+ rescue Errno::EACCES => e
+ failure = true
+ push_state(MessageDialog, title: "Fatal Error",
+ message: "Directory Permission Error (#{e.class}):\n#{e}.\n\nIs the required drive mounted?",
+ accept_callback: -> { window.close })
+ end
+ end
+
+ next unless regenerate
+
+ icon = ICO.new(file: path)
+ icon.save(icon.images.max_by(&:width), generated_icon_path)
end
-
- next unless regenerate
-
- BackgroundWorker.foreground_job(-> { ICO.new(file: path) }, lambda { |result|
- result.save(result.images.max_by(&:width), generated_icon_path)
- })
end
@tasks[:app_icons][:complete] = true unless failure
@@ -307,18 +301,18 @@ class W3DHub
packages << { category: app.category, subcategory: app.id, name: "background.png", version: "" }
end
- Api.on_thread(:package_details, packages, :alt_w3dhub) do |package_details|
- package_details ||= nil
+ Api.on_thread(:package_details, packages, :alt_w3dhub) do |result|
+ if result.okay?
+ result.data.each do |package|
+ next if package.error?
- package_details&.each do |package|
- next if package.error?
+ package_cache_path = Cache.package_path(package.category, package.subcategory, package.name,
+ package.version)
- package_cache_path = Cache.package_path(package.category, package.subcategory, package.name,
- package.version)
+ missing_or_broken_image = File.exist?(package_cache_path) ? Digest::SHA256.new.hexdigest(File.binread(package_cache_path)).upcase != package.checksum.upcase : true
- missing_or_broken_image = File.exist?(package_cache_path) ? Digest::SHA256.new.hexdigest(File.binread(package_cache_path)).upcase != package.checksum.upcase : true
-
- Cache.fetch_package(package, proc {}) if missing_or_broken_image
+ Cache.fetch_package(package, proc {}) if missing_or_broken_image
+ end
end
@tasks[:app_logos_and_backgrounds][:complete] = true
@@ -328,15 +322,15 @@ class W3DHub
def server_list
@status_label.value = I18n.t(:"server_browser.fetching_server_list")
- Api.on_thread(:server_list, 2) do |list|
- if list
- Store.server_list = list.sort_by! { |s| s&.status&.players&.size }.reverse
+ Api.on_thread(:server_list, 2) do |result|
+ if result.okay?
+ Store.server_list = result.data.sort_by! { |s| s&.status&.players&.size }.reverse
Store.server_list_last_fetch = Gosu.milliseconds
Api::ServerListUpdater.instance
- list.each do |server|
+ Store.server_list.each do |server|
server.send_ping(true)
end
else
diff --git a/lib/states/interface.rb b/lib/states/interface.rb
index a0b461e..fd864c5 100644
--- a/lib/states/interface.rb
+++ b/lib/states/interface.rb
@@ -164,15 +164,15 @@ class W3DHub
if Gosu.milliseconds >= @server_list_expire
@server_list_expire = Gosu.milliseconds + 30_000
- Api.on_thread(:server_list, 2) do |list|
- if list
+ Api.on_thread(:server_list, 2) do |result|
+ if result.okay?
@server_list_expire = Gosu.milliseconds + SERVER_LIST_UPDATE_INTERVAL # five minutes
Store.server_list_last_fetch = Gosu.milliseconds
- Api::ServerListUpdater.instance.refresh_server_list(list)
+ Api::ServerListUpdater.instance.refresh_server_list(result.data)
- BackgroundWorker.foreground_job(-> {}, ->(_) { States::Interface.instance&.update_server_browser(nil, :refresh_all) })
+ Store.main_thread_queue << -> { States::Interface.instance&.update_server_browser(nil, :refresh_all) }
end
end
end