2 Commits

7 changed files with 237 additions and 85 deletions

View File

@@ -3,7 +3,7 @@ module W3DHubLauncher
def setup def setup
theme(THEME) theme(THEME)
background 0xee_222222 background TRANSLUCENT_GRAY
end end
end end
end end

View File

@@ -4,12 +4,12 @@ module W3DHubLauncher
def setup def setup
super super
stack(width: 1.0, max_width: 600, height: 1.0, max_height: 600, h_align: :center, v_align: :center, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_BLACK) do stack(width: 1.0, max_width: 600, height: 1.0, max_height: 600, h_align: :center, v_align: :center, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: 0xee_63452c) do
flow(width: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_TOP, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY) do flow(width: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_TOP, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: 0) do
banner "About", width: 1.0, text_align: :center banner "About", width: 1.0, text_align: :center
end end
stack(width: 1.0, fill: true, scroll: true, padding_left: PADDING, padding_right: PADDING) do stack(width: 1.0, fill: true, scroll: true, margin_left: PADDING, margin_right: PADDING, padding: HALF_PADDING, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_BLACK) do
title NAME title NAME
tagline format("v%s (%s)", VERSION, VERSION_NAME), margin_left: PADDING tagline format("v%s (%s)", VERSION, VERSION_NAME), margin_left: PADDING
para "© 2021 - #{Time.now.year} cyberarm", margin_left: PADDING para "© 2021 - #{Time.now.year} cyberarm", margin_left: PADDING
@@ -26,10 +26,10 @@ module W3DHubLauncher
end end
end end
flow(width: 1.0, padding: PADDING, background_nine_slice: NINE_SLICE_ROUNDED_BOTTOM, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY) do flow(width: 1.0, padding: PADDING, background_nine_slice: NINE_SLICE_ROUNDED_BOTTOM, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: 0) do
flow(fill: true) flow(fill: true)
button "Close" do button "Close", **CTA_BUTTON_THEME do
pop_state pop_state
end end

View File

@@ -5,86 +5,210 @@ module W3DHubLauncher
include GuiExt include GuiExt
def setup def setup
@steps = [
method(:step_connectivity),
method(:step_launcher_update),
method(:step_server_list),
method(:step_refresh_account_data),
method(:step_fetch_applications),
method(:step_battlefield_control_established)
]
@initialization_acceptable = false
@step_count = @steps.size
stack(width: 1.0, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: 8, background_nine_slice_color: 0x11_ffffff, padding: HALF_PADDING) do stack(width: 1.0, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: 8, background_nine_slice_color: 0x11_ffffff, padding: HALF_PADDING) do
banner "Establishing Battlefield Control", width: 1.0, text_align: :center banner "Establishing Battlefield Control", width: 1.0, text_align: :center
tagline "Please stand by...", width: 1.0, text_align: :center tagline "Please stand by...", width: 1.0, text_align: :center
end end
stack(width: 1.0, fill: true, padding: PADDING) do stack(width: 1.0, fill: true, padding: PADDING) do
stack(width: 1.0, fill: true, scroll: true) do @initialization_container = stack(width: 1.0, fill: true, scroll: true) do
a = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do # a = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do
image safe_get_image("#{ROOT_PATH}/media/icons/checkmark.png"), height: 1.0, v_align: :center # image safe_get_image("#{ROOT_PATH}/media/icons/checkmark.png"), height: 1.0, v_align: :center
tagline "DNS resolution", height: 1.0, text_v_align: :center # tagline "DNS resolution", height: 1.0, text_v_align: :center
end # end
after(500) do # after(500) do
a.show # a.show
end # end
b = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do # b = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do
image safe_get_image("#{ROOT_PATH}/media/icons/information.png"), height: 1.0, v_align: :center, color: 0xff_ff8800 # image safe_get_image("#{ROOT_PATH}/media/icons/information.png"), height: 1.0, v_align: :center, color: 0xff_ff8800
tagline "Upstream backend", height: 1.0, text_v_align: :center # tagline "Upstream backend", height: 1.0, text_v_align: :center
caption "Notice: Unreachable. Accounts will be unavailable.", height: 1.0, text_v_align: :center, color: 0xff_ff8800 # caption "Notice: Unreachable. Accounts will be unavailable.", height: 1.0, text_v_align: :center, color: 0xff_ff8800
end # end
after(1000) do # after(1000) do
b.show # b.show
end # end
c = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do # c = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do
image safe_get_image("#{ROOT_PATH}/media/icons/checkmark.png"), height: 1.0, v_align: :center # image safe_get_image("#{ROOT_PATH}/media/icons/checkmark.png"), height: 1.0, v_align: :center
tagline "Alternate backend", height: 1.0, text_v_align: :center # tagline "Alternate backend", height: 1.0, text_v_align: :center
end # end
after(1500) do # after(1500) do
c.show # c.show
end # end
d = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do # d = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do
image safe_get_image("#{ROOT_PATH}/media/icons/information.png"), height: 1.0, v_align: :center, color: 0xff_ff8800 # image safe_get_image("#{ROOT_PATH}/media/icons/information.png"), height: 1.0, v_align: :center, color: 0xff_ff8800
tagline "Refresh account session", height: 1.0, text_v_align: :center # tagline "Refresh account session", height: 1.0, text_v_align: :center
caption "Notice: Upstream backend unavailable, session not refreshed.", height: 1.0, text_v_align: :center, color: 0xff_ff8800 # caption "Notice: Upstream backend unavailable, session not refreshed.", height: 1.0, text_v_align: :center, color: 0xff_ff8800
end # end
after(2000) do # after(2000) do
d.show # d.show
end # end
e = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do # e = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do
image safe_get_image("#{ROOT_PATH}/media/icons/checkmark.png"), height: 1.0, v_align: :center # image safe_get_image("#{ROOT_PATH}/media/icons/checkmark.png"), height: 1.0, v_align: :center
tagline "Fetch game servers", height: 1.0, text_v_align: :center # tagline "Fetch game servers", height: 1.0, text_v_align: :center
end # end
after(2500) do # after(2500) do
e.show # e.show
end # end
f = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do # f = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do
image safe_get_image("#{ROOT_PATH}/media/icons/cross.png"), height: 1.0, v_align: :center, color: 0xff_ff0000 # image safe_get_image("#{ROOT_PATH}/media/icons/cross.png"), height: 1.0, v_align: :center, color: 0xff_ff0000
tagline "Fetch applications", height: 1.0, text_v_align: :center # tagline "Fetch applications", height: 1.0, text_v_align: :center
caption "Fatal: Failed to retrieve applications list and no local cache exists. Cannot continue.", height: 1.0, text_v_align: :center, color: 0xff_ff0000 # caption "Fatal: Failed to retrieve applications list and no local cache exists. Cannot continue.", height: 1.0, text_v_align: :center, color: 0xff_ff0000
end # end
after(3000) do # after(3000) do
puts "HELLO" # puts "HELLO"
W3DHubLauncher::Worker::Request.new(:w3dhub_api_call, { call: :fetch_applications }) do |result| # W3DHubLauncher::Worker::Request.new(:w3dhub_api_call, { call: :fetch_applications }) do |result|
# pp [:CALLBACK, result] # # pp [:CALLBACK, result]
File.write("applications.json", result.data) # File.write("applications.json", result.data)
hash = JSON.parse(result.data) # hash = JSON.parse(result.data)
applications = hash["applications"]&.map { |app| W3DHubLauncher::Worker::Api::Application.new(app) } || [] # applications = hash["applications"]&.map { |app| W3DHubLauncher::Worker::Api::Application.new(app) } || []
# pp applications.to_json # # pp applications.to_json
MemCache[:applications] = applications # MemCache[:applications] = applications
# end
# f.show
# @progress_bar.type = :linear
# @progress_bar.value = 0.0
# end
# after(35000) do
# parent.page_host.clear do
# banner "Battlefield control established".upcase, width: 1.0, height: 1.0, text_v_align: :center, text_align: :center
# end
# end
# after(36000) do
# pop_state
# push_state(States::Interface)
# end
end end
f.show flow(width: 1.0, padding_top: PADDING) do
@progress_bar.type = :linear @progress_bar = progress width: 1.0, fraction: 0.0
@progress_bar.value = 0.0 end
end end
after(3500) do next_step
parent.page_host.clear do
banner "Battlefield control established".upcase, width: 1.0, height: 1.0, text_v_align: :center, text_align: :center
end end
end
after(3600) do def next_step
step = @steps.shift
step&.call
pp (1.0 - (@steps.size / @step_count.to_f)), @steps.size, @step_count
@progress_bar.value = (1.0 - (@steps.size / @step_count.to_f))
puts
if step.nil? && @initialization_acceptable
after(100) do
pop_state pop_state
push_state(States::Interface) push_state(States::Interface)
end end
end end
end
flow(width: 1.0, padding_top: PADDING) do def step_connectivity
@progress_bar = progress width: 1.0, type: :marquee @initialization_container.append do
end tagline "Checking uplink..."
# caption "Primary backend services <c=080>OK</c>", margin_left: LARGE_PADDING
# caption "Upstream backend services <c=080>OK</c>", margin_left: LARGE_PADDING
end
Worker::Api.dns_resolution do |result|
@initialization_container.append do
if result.okay?
caption "DNS Resolution <c=0f0>OK</c>", margin_left: LARGE_PADDING
next_step
else
caption "DNS Resolution <c=f00>FAILED</c>", margin_left: LARGE_PADDING
caption "Failed to resolve: #{result.error}", color: 0xff_ff0000, margin_left: LARGE_PADDING * 2
end
end
end
end
def step_launcher_update
@initialization_container.append do
tagline "Checking for updates..."
caption "Launcher version <c=0f0>OK</c>", margin_left: LARGE_PADDING
end
after(1000) do
next_step
end
end
def step_server_list
@initialization_container.append do
tagline "Requesting server listing..."
caption "Found 21 servers <c=0f0>OK</c>", margin_left: LARGE_PADDING
end
after(1000) do
next_step
end
end
def step_refresh_account_data
@initialization_container.append do
tagline "Updating account information..."
caption "Refresh session <c=0f0>OK</c>", margin_left: LARGE_PADDING
caption "Profile data <c=0f0>OK</c>", margin_left: LARGE_PADDING
end
after(1000) do
next_step
end
end
def step_fetch_applications
@initialization_container.append do
tagline "Requesting application listing..."
end
Worker::Api.applications do |result|
if result.okay?
File.write("applications.json", result.data)
hash = JSON.parse(result.data)
applications = hash["applications"]&.map { |app| W3DHubLauncher::Worker::Api::Application.new(app) } || []
MemCache[:applications] = applications
@initialization_container.append do
caption "Refresh session <c=0f0>OK</c>", margin_left: LARGE_PADDING
caption "Profile data <c=0f0>OK</c>", margin_left: LARGE_PADDING
end
next_step
else
@initialization_container.append do
caption "A fatal error occurred while getting application data.", margin_left: LARGE_PADDING, color: 0xaa_ff0000
end
end
end
end
def step_battlefield_control_established
@initialization_acceptable = true
after(200) do
parent.page_host.clear do
banner "Battlefield control established".upcase, width: 1.0, height: 1.0, text_v_align: :center, text_align: :center
end
end
after(800) do
next_step
end end
end end
end end

View File

@@ -118,10 +118,10 @@ module W3DHubLauncher
button safe_get_image("#{ROOT_PATH}/media/icons/gear.png"), tip: "Options", image_height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME button safe_get_image("#{ROOT_PATH}/media/icons/gear.png"), tip: "Options", image_height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME
elsif @current_app.servicable? elsif @current_app.servicable?
pp @current_app pp @current_app
button "Import", tip: "Import existing application installation", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_LEFT, **CTA_BUTTON_THEME button "Import", enabled: false, tip: "Import existing application installation", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_LEFT, **CTA_BUTTON_THEME
button "Download", tip: "Download and install application", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME button "Download", tip: "Download and install application", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME
else else
button "Import", tip: "Import existing application installation", fill: true, height: 1.0, **CTA_BUTTON_THEME button "Import", enabled: false, tip: "Import existing application installation", fill: true, height: 1.0, **CTA_BUTTON_THEME
end end
end end
# FIXME: the reported version should be the _installed_ version, not the current channel version # FIXME: the reported version should be the _installed_ version, not the current channel version

View File

@@ -2,8 +2,10 @@ module W3DHubLauncher
LARGE_PADDING = 40 LARGE_PADDING = 40
PADDING = 20 PADDING = 20
HALF_PADDING = 10 HALF_PADDING = 10
ALPHA_BLACK = 0x88_000000 ALPHA_BLACK = 0x88_000000
ALPHA_GRAY = 0x88_5e5c64 ALPHA_GRAY = 0x88_5e5c64
TRANSLUCENT_GRAY = 0xaa_3d3846
FONT_LIGHT = "#{ROOT_PATH}/media/fonts/NotoSans-Light.ttf" FONT_LIGHT = "#{ROOT_PATH}/media/fonts/NotoSans-Light.ttf"
FONT_REGULAR = "#{ROOT_PATH}/media/fonts/NotoSans-Regular.ttf" FONT_REGULAR = "#{ROOT_PATH}/media/fonts/NotoSans-Regular.ttf"
@@ -95,7 +97,9 @@ module W3DHubLauncher
background_nine_slice_color: 0xaa_5e5c64 background_nine_slice_color: 0xaa_5e5c64
}, },
disabled: { disabled: {
background: 0 color: 0x88_c0bfbc,
background: 0,
background_nine_slice_color: 0xaa_77767b
} }
}, },
EditLine: { EditLine: {

View File

@@ -5,7 +5,7 @@ module W3DHubLauncher
].freeze ].freeze
DEFAULT_NETWORK_TIMEOUT = 30 DEFAULT_NETWORK_TIMEOUT = 30
Response = Data.define(:status, :request_id, :data) Response = Data.define(:status, :request_id, :result)
def initialize def initialize
end end
@@ -50,7 +50,7 @@ module W3DHubLauncher
if respond_to?(query.type) if respond_to?(query.type)
response = send(query.type, query) response = send(query.type, query)
pp [:server_to_client, response] pp [:server_to_client, response]
payload = { status: response.status, request_id: response.request_id, data: response.data.data }.to_json payload = { status: response.status, request_id: response.request_id, data: response.result.data, error: response.result.error }.to_json
socket.puts(payload) socket.puts(payload)
end end
end end
@@ -84,16 +84,15 @@ module W3DHubLauncher
data = @socket.read_nonblock(1_048_576) # 1 MB data = @socket.read_nonblock(1_048_576) # 1 MB
pp [:CLIENT, data] pp [:CLIENT, data]
json = JSON.parse(data) json = JSON.parse(data)
response = Response.new(status: json["status"], request_id: json["request_id"], data: json["data"]) request = W3DHubLauncher::Worker::Request.requests.find { |r| r.request_id == json["request_id"] }
request = W3DHubLauncher::Worker::Request.requests.find { |r| r.request_id == response.request_id }
pp [json, response, request] pp [json, request]
return unless request return unless request
CyberarmEngine::Window.instance&.add_to_queue(proc { CyberarmEngine::Window.instance&.add_to_queue(proc {
request.handle_event( request.handle_event(
response.status, json["status"],
CyberarmEngine::Result.new(data: response.data, error: response.status.negative? ? true : nil) CyberarmEngine::Result.new(data: json["data"], error: json["error"])
) )
}) })
@@ -159,6 +158,26 @@ module W3DHubLauncher
deliver_response(result, query) deliver_response(result, query)
end end
def dns_resolution(query)
result = CyberarmEngine::Result.new
domains = [
"w3dhub-api.w3d.cyberarm.dev",
"s3.w3d.cyberarm.dev",
"secure.w3dhub.com"
]
domains.each do |domain|
Resolv.getaddress(domain)
rescue StandardError => e
result.error = "Failed to resolve: #{domain}"
end
result.data = true if result.error.nil?
deliver_response(result, query)
end
def w3dhub_api_call(query) def w3dhub_api_call(query)
result = @w3dhub_api.send(query.data["call"], *(query.data["arguments"] || [])) result = @w3dhub_api.send(query.data["call"], *(query.data["arguments"] || []))

View File

@@ -12,6 +12,10 @@ module W3DHubLauncher
Worker::Request.new(:download_url, { url: url, path: path, method: method, headers: headers, body: body }, &block) Worker::Request.new(:download_url, { url: url, path: path, method: method, headers: headers, body: body }, &block)
end end
def self.dns_resolution(&block)
Worker::Request.new(:dns_resolution, "", &block)
end
# returns user account data # returns user account data
# #
# automatically handles signing in / refreshing token (DOES NOT remove account data if failed to refresh token due to network timeout) # automatically handles signing in / refreshing token (DOES NOT remove account data if failed to refresh token due to network timeout)
@@ -35,7 +39,8 @@ module W3DHubLauncher
# returns list of available applications # returns list of available applications
# #
# if updated list is requested, return cached version immediately and then the updated list later. # if updated list is requested, return cached version immediately and then the updated list later.
def self.applications def self.applications(&block)
W3DHubLauncher::Worker::Request.new(:w3dhub_api_call, { call: :fetch_applications }, &block)
end end
# returns current list of servers as reported from GSH / cache # returns current list of servers as reported from GSH / cache