mirror of
https://github.com/cyberarm/w3d_hub_linux_launcher.git
synced 2025-12-17 01:32:34 +00:00
Compare commits
5 Commits
7359d73027
...
4b230eb535
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b230eb535 | |||
| ab73b62c4b | |||
| 388c3a2606 | |||
| deaa6ee9d9 | |||
| 340c083a43 |
6
Gemfile
6
Gemfile
@@ -6,13 +6,11 @@ gem "i18n"
|
|||||||
gem "rexml"
|
gem "rexml"
|
||||||
gem "digest-crc"
|
gem "digest-crc"
|
||||||
gem "ffi"
|
gem "ffi"
|
||||||
gem "async", "~>1.30.1"
|
gem "websocket-client-simple"
|
||||||
gem "async-http"
|
|
||||||
gem "async-websocket"
|
|
||||||
gem "thread-local"
|
gem "thread-local"
|
||||||
gem "ircparser"
|
gem "ircparser"
|
||||||
gem "net-ping"
|
|
||||||
gem "win32-security", platforms: [:x64_mingw, :mingw]
|
gem "win32-security", platforms: [:x64_mingw, :mingw]
|
||||||
|
gem "win32-process", platforms: [:x64_mingw, :mingw]
|
||||||
|
|
||||||
# group :windows_packaging do
|
# group :windows_packaging do
|
||||||
# gem "rake"
|
# gem "rake"
|
||||||
|
|||||||
62
Gemfile.lock
62
Gemfile.lock
@@ -1,46 +1,22 @@
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
addressable (2.8.0)
|
addressable (2.8.1)
|
||||||
public_suffix (>= 2.0.2, < 5.0)
|
public_suffix (>= 2.0.2, < 6.0)
|
||||||
async (1.30.3)
|
|
||||||
console (~> 1.10)
|
|
||||||
nio4r (~> 2.3)
|
|
||||||
timers (~> 4.1)
|
|
||||||
async-http (0.56.6)
|
|
||||||
async (>= 1.25)
|
|
||||||
async-io (>= 1.28)
|
|
||||||
async-pool (>= 0.2)
|
|
||||||
protocol-http (~> 0.22.0)
|
|
||||||
protocol-http1 (~> 0.14.0)
|
|
||||||
protocol-http2 (~> 0.14.0)
|
|
||||||
traces (~> 0.4.0)
|
|
||||||
async-io (1.33.0)
|
|
||||||
async
|
|
||||||
async-pool (0.3.10)
|
|
||||||
async (>= 1.25)
|
|
||||||
async-websocket (0.19.0)
|
|
||||||
async-http (~> 0.54)
|
|
||||||
async-io (~> 1.23)
|
|
||||||
protocol-websocket (~> 0.7.0)
|
|
||||||
clipboard (1.3.6)
|
|
||||||
concurrent-ruby (1.1.10)
|
concurrent-ruby (1.1.10)
|
||||||
console (1.15.3)
|
cyberarm_engine (0.22.0)
|
||||||
fiber-local
|
|
||||||
cyberarm_engine (0.21.0)
|
|
||||||
clipboard (~> 1.3)
|
|
||||||
excon (~> 0.88)
|
excon (~> 0.88)
|
||||||
gosu (~> 1.1)
|
gosu (~> 1.1)
|
||||||
gosu_more_drawables (~> 0.3)
|
gosu_more_drawables (~> 0.3)
|
||||||
digest-crc (0.6.4)
|
digest-crc (0.6.4)
|
||||||
rake (>= 12.0.0, < 14.0.0)
|
rake (>= 12.0.0, < 14.0.0)
|
||||||
excon (0.92.4)
|
event_emitter (0.2.6)
|
||||||
|
excon (0.93.1)
|
||||||
ffi (1.15.5)
|
ffi (1.15.5)
|
||||||
ffi (1.15.5-x64-mingw-ucrt)
|
ffi (1.15.5-x64-mingw-ucrt)
|
||||||
ffi (1.15.5-x64-mingw32)
|
ffi (1.15.5-x64-mingw32)
|
||||||
ffi-win32-extensions (1.0.4)
|
ffi-win32-extensions (1.0.4)
|
||||||
ffi
|
ffi
|
||||||
fiber-local (1.0.0)
|
|
||||||
gosu (1.4.3)
|
gosu (1.4.3)
|
||||||
gosu_more_drawables (0.3.1)
|
gosu_more_drawables (0.3.1)
|
||||||
i18n (1.12.0)
|
i18n (1.12.0)
|
||||||
@@ -48,24 +24,16 @@ GEM
|
|||||||
ircparser (1.0.0)
|
ircparser (1.0.0)
|
||||||
launchy (2.5.0)
|
launchy (2.5.0)
|
||||||
addressable (~> 2.7)
|
addressable (~> 2.7)
|
||||||
net-ping (2.0.8)
|
public_suffix (5.0.0)
|
||||||
nio4r (2.5.8)
|
|
||||||
protocol-hpack (1.4.2)
|
|
||||||
protocol-http (0.22.6)
|
|
||||||
protocol-http1 (0.14.4)
|
|
||||||
protocol-http (~> 0.22)
|
|
||||||
protocol-http2 (0.14.2)
|
|
||||||
protocol-hpack (~> 1.4)
|
|
||||||
protocol-http (~> 0.18)
|
|
||||||
protocol-websocket (0.7.5)
|
|
||||||
protocol-http (~> 0.2)
|
|
||||||
protocol-http1 (~> 0.2)
|
|
||||||
public_suffix (4.0.7)
|
|
||||||
rake (13.0.6)
|
rake (13.0.6)
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
thread-local (1.1.0)
|
thread-local (1.1.0)
|
||||||
timers (4.3.3)
|
websocket (1.2.9)
|
||||||
traces (0.4.1)
|
websocket-client-simple (0.6.0)
|
||||||
|
event_emitter
|
||||||
|
websocket
|
||||||
|
win32-process (0.10.0)
|
||||||
|
ffi (>= 1.0.0)
|
||||||
win32-security (0.5.0)
|
win32-security (0.5.0)
|
||||||
ffi
|
ffi
|
||||||
ffi-win32-extensions
|
ffi-win32-extensions
|
||||||
@@ -76,18 +44,16 @@ PLATFORMS
|
|||||||
x86_64-linux
|
x86_64-linux
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
async (~> 1.30.1)
|
|
||||||
async-http
|
|
||||||
async-websocket
|
|
||||||
cyberarm_engine
|
cyberarm_engine
|
||||||
digest-crc
|
digest-crc
|
||||||
ffi
|
ffi
|
||||||
i18n
|
i18n
|
||||||
ircparser
|
ircparser
|
||||||
launchy
|
launchy
|
||||||
net-ping
|
|
||||||
rexml
|
rexml
|
||||||
thread-local
|
thread-local
|
||||||
|
websocket-client-simple
|
||||||
|
win32-process
|
||||||
win32-security
|
win32-security
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
|
|||||||
78
lib/api.rb
78
lib/api.rb
@@ -4,15 +4,17 @@ class W3DHub
|
|||||||
|
|
||||||
API_TIMEOUT = 10 # seconds
|
API_TIMEOUT = 10 # seconds
|
||||||
USER_AGENT = "Cyberarm's Linux Friendly W3D Hub Launcher v#{W3DHub::VERSION}".freeze
|
USER_AGENT = "Cyberarm's Linux Friendly W3D Hub Launcher v#{W3DHub::VERSION}".freeze
|
||||||
DEFAULT_HEADERS = [
|
DEFAULT_HEADERS = {
|
||||||
["User-Agent", USER_AGENT],
|
"User-Agent": USER_AGENT,
|
||||||
["Accept", "application/json"]
|
"Accept": "application/json"
|
||||||
].freeze
|
}.freeze
|
||||||
FORM_ENCODED_HEADERS = (
|
FORM_ENCODED_HEADERS = {
|
||||||
DEFAULT_HEADERS + [["Content-Type", "application/x-www-form-urlencoded"]]
|
"User-Agent": USER_AGENT,
|
||||||
).freeze
|
"Accept": "application/json",
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
|
}.freeze
|
||||||
|
|
||||||
def self.on_fiber(method, *args, &callback)
|
def self.on_thread(method, *args, &callback)
|
||||||
BackgroundWorker.job(-> { Api.send(method, *args) }, callback)
|
BackgroundWorker.job(-> { Api.send(method, *args) }, callback)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -27,8 +29,6 @@ class W3DHub
|
|||||||
ENDPOINT = "https://secure.w3dhub.com".freeze
|
ENDPOINT = "https://secure.w3dhub.com".freeze
|
||||||
|
|
||||||
def self.post(url, headers = DEFAULT_HEADERS, body = nil)
|
def self.post(url, headers = DEFAULT_HEADERS, body = nil)
|
||||||
@client ||= Async::HTTP::Client.new(Async::HTTP::Endpoint.parse(ENDPOINT, protocol: Async::HTTP::Protocol::HTTP10))
|
|
||||||
|
|
||||||
# TODO: Check if session has expired and attempt to refresh session before submitting request
|
# TODO: Check if session has expired and attempt to refresh session before submitting request
|
||||||
|
|
||||||
logger.debug(LOG_TAG) { "Fetching POST \"#{url}\"..." }
|
logger.debug(LOG_TAG) { "Fetching POST \"#{url}\"..." }
|
||||||
@@ -37,17 +37,15 @@ class W3DHub
|
|||||||
if Store.account
|
if Store.account
|
||||||
logger.debug(LOG_TAG) { " Injecting Authorization header..." }
|
logger.debug(LOG_TAG) { " Injecting Authorization header..." }
|
||||||
headers = headers.dup
|
headers = headers.dup
|
||||||
headers << ["Authorization", "Bearer #{Store.account.access_token}"]
|
headers["Authorization"] = "Bearer #{Store.account.access_token}"
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Async::Task.current.with_timeout(API_TIMEOUT) do
|
Excon.post(url, headers: headers, body: body, tcp_nodelay: true, write_timeout: API_TIMEOUT, read_timeout: API_TIMEOUT, connection_timeout: API_TIMEOUT)
|
||||||
@client.post(url, headers, body)
|
rescue Excon::Errors::Timeout
|
||||||
end
|
|
||||||
rescue Async::TimeoutError
|
|
||||||
logger.error(LOG_TAG) { "Connection to \"#{url}\" timed out after: #{API_TIMEOUT} seconds" }
|
logger.error(LOG_TAG) { "Connection to \"#{url}\" timed out after: #{API_TIMEOUT} seconds" }
|
||||||
DummyResponse.new
|
DummyResponse.new
|
||||||
rescue EOFError => e
|
rescue Excon::Socket::Error => e
|
||||||
logger.error(LOG_TAG) { "Connection to \"#{url}\" errored:" }
|
logger.error(LOG_TAG) { "Connection to \"#{url}\" errored:" }
|
||||||
logger.error(LOG_TAG) { e }
|
logger.error(LOG_TAG) { e }
|
||||||
DummyResponse.new
|
DummyResponse.new
|
||||||
@@ -73,16 +71,16 @@ class W3DHub
|
|||||||
body = "data=#{JSON.dump({refreshToken: refresh_token})}"
|
body = "data=#{JSON.dump({refreshToken: refresh_token})}"
|
||||||
response = post("#{ENDPOINT}/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body)
|
response = post("#{ENDPOINT}/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body)
|
||||||
|
|
||||||
if response.success?
|
if response.status == 200
|
||||||
user_data = JSON.parse(response.read, symbolize_names: true)
|
user_data = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
return false if user_data[:error]
|
return false if user_data[:error]
|
||||||
|
|
||||||
body = "data=#{JSON.dump({ id: user_data[:userid] })}"
|
body = "data=#{JSON.dump({ id: user_data[:userid] })}"
|
||||||
user_details = post("#{ENDPOINT}/apis/w3dhub/1/get-user-details", FORM_ENCODED_HEADERS, body)
|
user_details = post("#{ENDPOINT}/apis/w3dhub/1/get-user-details", FORM_ENCODED_HEADERS, body)
|
||||||
|
|
||||||
if user_details.success?
|
if user_details.status == 200
|
||||||
user_details_data = JSON.parse(user_details.read, symbolize_names: true)
|
user_details_data = JSON.parse(user_details.body, symbolize_names: true)
|
||||||
else
|
else
|
||||||
logger.error(LOG_TAG) { "Failed to fetch refresh user details:" }
|
logger.error(LOG_TAG) { "Failed to fetch refresh user details:" }
|
||||||
logger.error(LOG_TAG) { user_details }
|
logger.error(LOG_TAG) { user_details }
|
||||||
@@ -101,16 +99,16 @@ class W3DHub
|
|||||||
body = "data=#{JSON.dump({username: username, password: password})}"
|
body = "data=#{JSON.dump({username: username, password: password})}"
|
||||||
response = post("#{ENDPOINT}/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body)
|
response = post("#{ENDPOINT}/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body)
|
||||||
|
|
||||||
if response.success?
|
if response.status == 200
|
||||||
user_data = JSON.parse(response.read, symbolize_names: true)
|
user_data = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
return false if user_data[:error]
|
return false if user_data[:error]
|
||||||
|
|
||||||
body = "data=#{JSON.dump({ id: user_data[:userid] })}"
|
body = "data=#{JSON.dump({ id: user_data[:userid] })}"
|
||||||
user_details = post("#{ENDPOINT}/apis/w3dhub/1/get-user-details", FORM_ENCODED_HEADERS, body)
|
user_details = post("#{ENDPOINT}/apis/w3dhub/1/get-user-details", FORM_ENCODED_HEADERS, body)
|
||||||
|
|
||||||
if user_details.success?
|
if user_details.status == 200
|
||||||
user_details_data = JSON.parse(user_details.read, symbolize_names: true)
|
user_details_data = JSON.parse(user_details.body, symbolize_names: true)
|
||||||
else
|
else
|
||||||
logger.error(LOG_TAG) { "Failed to fetch user details:" }
|
logger.error(LOG_TAG) { "Failed to fetch user details:" }
|
||||||
logger.error(LOG_TAG) { user_details }
|
logger.error(LOG_TAG) { user_details }
|
||||||
@@ -137,8 +135,8 @@ class W3DHub
|
|||||||
def self.service_status
|
def self.service_status
|
||||||
response = post("#{ENDPOINT}/apis/w3dhub/1/get-service-status", DEFAULT_HEADERS)
|
response = post("#{ENDPOINT}/apis/w3dhub/1/get-service-status", DEFAULT_HEADERS)
|
||||||
|
|
||||||
if response.success?
|
if response.status == 200
|
||||||
ServiceStatus.new(response.read)
|
ServiceStatus.new(response.body)
|
||||||
else
|
else
|
||||||
logger.error(LOG_TAG) { "Failed to fetch service status:" }
|
logger.error(LOG_TAG) { "Failed to fetch service status:" }
|
||||||
logger.error(LOG_TAG) { response }
|
logger.error(LOG_TAG) { response }
|
||||||
@@ -153,8 +151,8 @@ class W3DHub
|
|||||||
def self.applications
|
def self.applications
|
||||||
response = post("#{ENDPOINT}/apis/launcher/1/get-applications")
|
response = post("#{ENDPOINT}/apis/launcher/1/get-applications")
|
||||||
|
|
||||||
if response.success?
|
if response.status == 200
|
||||||
Applications.new(response.read)
|
Applications.new(response.body)
|
||||||
else
|
else
|
||||||
logger.error(LOG_TAG) { "Failed to fetch applications list:" }
|
logger.error(LOG_TAG) { "Failed to fetch applications list:" }
|
||||||
logger.error(LOG_TAG) { response }
|
logger.error(LOG_TAG) { response }
|
||||||
@@ -170,8 +168,8 @@ class W3DHub
|
|||||||
body = "data=#{JSON.dump({category: category})}"
|
body = "data=#{JSON.dump({category: category})}"
|
||||||
response = post("#{ENDPOINT}/apis/w3dhub/1/get-news", FORM_ENCODED_HEADERS, body)
|
response = post("#{ENDPOINT}/apis/w3dhub/1/get-news", FORM_ENCODED_HEADERS, body)
|
||||||
|
|
||||||
if response.success?
|
if response.status == 200
|
||||||
News.new(response.read)
|
News.new(response.body)
|
||||||
else
|
else
|
||||||
logger.error(LOG_TAG) { "Failed to fetch news for:" }
|
logger.error(LOG_TAG) { "Failed to fetch news for:" }
|
||||||
logger.error(LOG_TAG) { category }
|
logger.error(LOG_TAG) { category }
|
||||||
@@ -188,8 +186,8 @@ class W3DHub
|
|||||||
body = URI.encode_www_form("data": JSON.dump({ packages: packages }))
|
body = URI.encode_www_form("data": JSON.dump({ packages: packages }))
|
||||||
response = post("#{ENDPOINT}/apis/launcher/1/get-package-details", FORM_ENCODED_HEADERS, body)
|
response = post("#{ENDPOINT}/apis/launcher/1/get-package-details", FORM_ENCODED_HEADERS, body)
|
||||||
|
|
||||||
if response.success?
|
if response.status == 200
|
||||||
hash = JSON.parse(response.read, symbolize_names: true)
|
hash = JSON.parse(response.body, symbolize_names: true)
|
||||||
hash[:packages].map { |pkg| Package.new(pkg) }
|
hash[:packages].map { |pkg| Package.new(pkg) }
|
||||||
else
|
else
|
||||||
logger.error(LOG_TAG) { "Failed to fetch package details for:" }
|
logger.error(LOG_TAG) { "Failed to fetch package details for:" }
|
||||||
@@ -214,8 +212,8 @@ class W3DHub
|
|||||||
body = URI.encode_www_form("data": JSON.dump({ serverPath: app_id }))
|
body = URI.encode_www_form("data": JSON.dump({ serverPath: app_id }))
|
||||||
response = post("#{ENDPOINT}/apis/w3dhub/1/get-server-events", FORM_ENCODED_HEADERS, body)
|
response = post("#{ENDPOINT}/apis/w3dhub/1/get-server-events", FORM_ENCODED_HEADERS, body)
|
||||||
|
|
||||||
if response.success?
|
if response.status == 200
|
||||||
array = JSON.parse(response.read, symbolize_names: true)
|
array = JSON.parse(response.body, symbolize_names: true)
|
||||||
array.map { |e| Event.new(e) }
|
array.map { |e| Event.new(e) }
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
@@ -227,11 +225,11 @@ class W3DHub
|
|||||||
SERVER_LIST_ENDPOINT = "https://gsh.w3dhub.com".freeze
|
SERVER_LIST_ENDPOINT = "https://gsh.w3dhub.com".freeze
|
||||||
|
|
||||||
def self.get(url, headers = DEFAULT_HEADERS, body = nil)
|
def self.get(url, headers = DEFAULT_HEADERS, body = nil)
|
||||||
@client ||= Async::HTTP::Client.new(Async::HTTP::Endpoint.parse(SERVER_LIST_ENDPOINT, protocol: Async::HTTP::Protocol::HTTP10))
|
@client ||= Excon.new(SERVER_LIST_ENDPOINT, persistent: true)
|
||||||
|
|
||||||
logger.debug(LOG_TAG) { "Fetching GET \"#{url}\"..." }
|
logger.debug(LOG_TAG) { "Fetching GET \"#{url}\"..." }
|
||||||
|
|
||||||
@client.get(url, headers, body)
|
Excon.get(url, headers: headers, body: body, persistent: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Method: GET
|
# Method: GET
|
||||||
@@ -254,8 +252,8 @@ class W3DHub
|
|||||||
def self.server_list(level = 1)
|
def self.server_list(level = 1)
|
||||||
response = get("#{SERVER_LIST_ENDPOINT}/listings/getAll/v2?statusLevel=#{level}")
|
response = get("#{SERVER_LIST_ENDPOINT}/listings/getAll/v2?statusLevel=#{level}")
|
||||||
|
|
||||||
if response.success?
|
if response.status == 200
|
||||||
data = JSON.parse(response.read, symbolize_names: true)
|
data = JSON.parse(response.body, symbolize_names: true)
|
||||||
return data.map { |hash| ServerListServer.new(hash) }
|
return data.map { |hash| ServerListServer.new(hash) }
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -276,8 +274,8 @@ class W3DHub
|
|||||||
def self.server_details(id, level)
|
def self.server_details(id, level)
|
||||||
response = get("#{SERVER_LIST_ENDPOINT}/listings/getStatus/v2/#{id}?statusLevel=#{level}")
|
response = get("#{SERVER_LIST_ENDPOINT}/listings/getStatus/v2/#{id}?statusLevel=#{level}")
|
||||||
|
|
||||||
if response.success?
|
if response.status == 200
|
||||||
hash = JSON.parse(response.read, symbolize_names: true)
|
hash = JSON.parse(response.body, symbolize_names: true)
|
||||||
return hash
|
return hash
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -45,12 +45,24 @@ class W3DHub
|
|||||||
if force_ping || Gosu.milliseconds - @last_pinged >= @ping_interval
|
if force_ping || Gosu.milliseconds - @last_pinged >= @ping_interval
|
||||||
@last_pinged = Gosu.milliseconds
|
@last_pinged = Gosu.milliseconds
|
||||||
|
|
||||||
Thread.new do
|
W3DHub::BackgroundWorker.parallel_job(
|
||||||
ping = Net::Ping::External.new(@address)
|
lambda do
|
||||||
@ping = (ping.duration * 1000.0).round if ping.ping?
|
@ping = -1
|
||||||
|
|
||||||
States::Interface.instance&.update_server_ping(self)
|
W3DHub.command("ping #{@address} #{W3DHub.windows? ? '-n 3' : '-c 3'}") do |line|
|
||||||
end
|
if W3DHub.windows? && line =~ /Minimum|Maximum|Maximum/i
|
||||||
|
@ping = line.strip.split(",").last.split("=").last.sub("ms", "").to_i
|
||||||
|
elsif W3DHub.unix? && line.start_with?("rtt min/avg/max/mdev")
|
||||||
|
@ping = line.strip.split("=").last.split("/")[1].to_i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@ping
|
||||||
|
end,
|
||||||
|
lambda do |_|
|
||||||
|
States::Interface.instance&.update_server_ping(self)
|
||||||
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -3,65 +3,6 @@ class W3DHub
|
|||||||
class ServerListUpdater
|
class ServerListUpdater
|
||||||
LOG_TAG = "W3DHub::Api::ServerListUpdater".freeze
|
LOG_TAG = "W3DHub::Api::ServerListUpdater".freeze
|
||||||
include CyberarmEngine::Common
|
include CyberarmEngine::Common
|
||||||
|
|
||||||
##!!! When this breaks update from: https://github.com/socketry/async-websocket/blob/master/lib/async/websocket/connection.rb
|
|
||||||
# refinements preserves super... 😢
|
|
||||||
class PatchedConnection < ::Protocol::WebSocket::Connection
|
|
||||||
include ::Protocol::WebSocket::Headers
|
|
||||||
|
|
||||||
def self.call(framer, protocol = [], **options)
|
|
||||||
instance = self.new(framer, Array(protocol).first, **options)
|
|
||||||
|
|
||||||
return instance unless block_given?
|
|
||||||
|
|
||||||
begin
|
|
||||||
yield instance
|
|
||||||
ensure
|
|
||||||
instance.close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(framer, protocol = nil, response: nil, **options)
|
|
||||||
super(framer, **options)
|
|
||||||
|
|
||||||
@protocol = protocol
|
|
||||||
@response = response
|
|
||||||
end
|
|
||||||
|
|
||||||
def close
|
|
||||||
super
|
|
||||||
|
|
||||||
if @response
|
|
||||||
@response.finish
|
|
||||||
@response = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
attr :protocol
|
|
||||||
|
|
||||||
def read
|
|
||||||
if (buffer = super)
|
|
||||||
buffer.split("\x1e").map { |json| parse(json) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def write(object)
|
|
||||||
super("#{dump(object)}\x1e")
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse(buffer)
|
|
||||||
JSON.parse(buffer, symbolize_names: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
def dump(object)
|
|
||||||
JSON.dump(object)
|
|
||||||
end
|
|
||||||
|
|
||||||
def call
|
|
||||||
self.close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@@instance = nil
|
@@instance = nil
|
||||||
|
|
||||||
def self.instance
|
def self.instance
|
||||||
@@ -87,45 +28,36 @@ class W3DHub
|
|||||||
retry
|
retry
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
logger.debug(LOG_TAG) { "Cleaning up..." }
|
||||||
|
@@instance = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def connect
|
def connect
|
||||||
Async do |task|
|
auto_reconnect = false
|
||||||
internet = Async::HTTP::Internet.instance
|
|
||||||
|
|
||||||
logger.debug(LOG_TAG) { "Requesting connection token..." }
|
logger.debug(LOG_TAG) { "Requesting connection token..." }
|
||||||
response = internet.post("https://gsh.w3dhub.com/listings/push/v2/negotiate?negotiateVersion=1", Api::DEFAULT_HEADERS, [""])
|
response = Excon.post("https://gsh.w3dhub.com/listings/push/v2/negotiate?negotiateVersion=1", headers: Api::DEFAULT_HEADERS, body: "")
|
||||||
data = JSON.parse(response.read, symbolize_names: true)
|
data = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
id = data[:connectionToken]
|
id = data[:connectionToken]
|
||||||
endpoint = Async::HTTP::Endpoint.parse("https://gsh.w3dhub.com/listings/push/v2?id=#{id}", alpn_protocols: Async::HTTP::Protocol::HTTP11.names)
|
endpoint = "https://gsh.w3dhub.com/listings/push/v2?id=#{id}"
|
||||||
|
|
||||||
logger.debug(LOG_TAG) { "Connecting to websocket..." }
|
logger.debug(LOG_TAG) { "Connecting to websocket..." }
|
||||||
Async::WebSocket::Client.connect(endpoint, headers: Api::DEFAULT_HEADERS, handler: PatchedConnection) do |connection|
|
WebSocket::Client::Simple.connect(endpoint, headers: Api::DEFAULT_HEADERS) do |ws|
|
||||||
logger.debug(LOG_TAG) { "Requesting json protocol, v1..." }
|
ws.on(:message) do |msg|
|
||||||
connection.write({ protocol: "json", version: 1 })
|
msg = msg.data.split("\x1e").first
|
||||||
connection.flush
|
|
||||||
logger.debug(LOG_TAG) { "Received: #{connection.read}" }
|
|
||||||
logger.debug(LOG_TAG) { "Sending \"PING\"(?)" }
|
|
||||||
connection.write({ "type": 6 })
|
|
||||||
|
|
||||||
logger.debug(LOG_TAG) { "Subscribing to server changes..." }
|
hash = JSON.parse(msg, symbolize_names: true)
|
||||||
Store.server_list.each_with_index do |server, i|
|
|
||||||
i += 1
|
|
||||||
mode = 1 # 2 full details, 1 basic details
|
|
||||||
out = { "type": 1, "invocationId": "#{i}", "target": "SubscribeToServerStatusUpdates", "arguments": [server.id, mode] }
|
|
||||||
connection.write(out)
|
|
||||||
end
|
|
||||||
|
|
||||||
logger.debug(LOG_TAG) { "Waiting for data..." }
|
# Send PING(?)
|
||||||
while (message = connection.read)
|
if hash.empty? || hash[:type] == 6
|
||||||
connection.write({ type: 6 }) if message.first[:type] == 6
|
ws.send({ type: 6 }.to_json + "\x1e")
|
||||||
|
else
|
||||||
if message&.first&.fetch(:type) == 1
|
case hash[:type]
|
||||||
message.each do |rpc|
|
when 1
|
||||||
next unless rpc[:target] == "ServerStatusChanged"
|
if hash[:target] == "ServerStatusChanged"
|
||||||
|
id, data = hash[:arguments]
|
||||||
id, data = rpc[:arguments]
|
|
||||||
server = Store.server_list.find { |s| s.id == id }
|
server = Store.server_list.find { |s| s.id == id }
|
||||||
server_updated = server&.update(data)
|
server_updated = server&.update(data)
|
||||||
States::Interface.instance&.update_server_browser(server) if server_updated
|
States::Interface.instance&.update_server_browser(server) if server_updated
|
||||||
@@ -133,10 +65,32 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
ensure
|
|
||||||
logger.debug(LOG_TAG) { "Cleaning up..." }
|
ws.on(:open) do
|
||||||
@@instance = nil
|
logger.debug(LOG_TAG) { "Requesting json protocol, v1..." }
|
||||||
|
ws.send({ protocol: "json", version: 1 }.to_json + "\x1e")
|
||||||
|
|
||||||
|
logger.debug(LOG_TAG) { "Subscribing to server changes..." }
|
||||||
|
Store.server_list.each_with_index do |server, i|
|
||||||
|
i += 1
|
||||||
|
mode = 1 # 2 full details, 1 basic details
|
||||||
|
out = { "type": 1, "invocationId": "#{i}", "target": "SubscribeToServerStatusUpdates", "arguments": [server.id, mode] }
|
||||||
|
ws.send(out.to_json + "\x1e")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ws.on(:close) do |e|
|
||||||
|
p e
|
||||||
|
auto_reconnect = true
|
||||||
|
end
|
||||||
|
|
||||||
|
ws.on(:error) do |e|
|
||||||
|
p e
|
||||||
|
auto_reconnect = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
connect if auto_reconnect
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -298,12 +298,19 @@ class W3DHub
|
|||||||
exe_path = app_id == "ecw" ? "#{install_path}/game750.exe" : "#{install_path}/game.exe"
|
exe_path = app_id == "ecw" ? "#{install_path}/game750.exe" : "#{install_path}/game.exe"
|
||||||
|
|
||||||
if File.exist?(exe_path)
|
if File.exist?(exe_path)
|
||||||
installed_version = reg["InstalledVersion"] unless app_id == "ren"
|
installed_version = app_id == "ren" ? "1.0.0.0" : reg["InstalledVersion"]
|
||||||
|
|
||||||
|
if (installed_app = installed?(app_id, channel_id))
|
||||||
|
current_version = Gem::Version.new(installed_app[:installed_version])
|
||||||
|
listed_version = installed_version
|
||||||
|
|
||||||
|
next if current_version >= listed_version
|
||||||
|
end
|
||||||
|
|
||||||
application_data = {
|
application_data = {
|
||||||
name: game.name,
|
name: game.name,
|
||||||
install_directory: install_path,
|
install_directory: install_path,
|
||||||
installed_version: app_id == "ren" ? "1.0.0.0" : installed_version,
|
installed_version: installed_version,
|
||||||
install_path: exe_path,
|
install_path: exe_path,
|
||||||
wine_prefix: nil
|
wine_prefix: nil
|
||||||
}
|
}
|
||||||
@@ -327,6 +334,33 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def write_application_version_to_win32_registry(app_id, channel_id, version)
|
||||||
|
# TODO: Figure out how to trigger UAC, but only for this so games DO NOT spawn with admin privileges.
|
||||||
|
return
|
||||||
|
return unless W3DHub.windows?
|
||||||
|
return if app_id == "ren"
|
||||||
|
|
||||||
|
require "win32/registry"
|
||||||
|
|
||||||
|
registry_path ||= "SOFTWARE\\W3D Hub\\games\\#{app_id}-#{channel_id}"
|
||||||
|
reg_type = Win32::Registry::KEY_ALL_ACCESS
|
||||||
|
|
||||||
|
Win32::Registry::HKEY_LOCAL_MACHINE.open(registry_path, reg_type) do |reg|
|
||||||
|
reg.write_s("InstalledVersion", version)
|
||||||
|
end
|
||||||
|
|
||||||
|
rescue => e
|
||||||
|
puts e.class, e.message, e.backtrace
|
||||||
|
if Win32::Registry::Error
|
||||||
|
logger.warn(LOG_TAG) { " Failed to update #{app_id}-#{channel_id} version in the registry" }
|
||||||
|
else
|
||||||
|
logger.warn(LOG_TAG) { " An error occurred while tying to update #{app_id}-#{channel_id} version in the registry" }
|
||||||
|
logger.warn(LOG_TAG) { e }
|
||||||
|
end
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
def imported!(task, exe_path)
|
def imported!(task, exe_path)
|
||||||
application_data = {
|
application_data = {
|
||||||
name: task.application.name,
|
name: task.application.name,
|
||||||
@@ -359,6 +393,8 @@ class W3DHub
|
|||||||
Store.settings[:games] ||= {}
|
Store.settings[:games] ||= {}
|
||||||
Store.settings[:games][:"#{task.app_id}_#{task.release_channel}"] = application_data
|
Store.settings[:games][:"#{task.app_id}_#{task.release_channel}"] = application_data
|
||||||
Store.settings.save_settings
|
Store.settings.save_settings
|
||||||
|
|
||||||
|
write_application_version_to_win32_registry(task.app_id, task.release_channel, task.target_version)
|
||||||
end
|
end
|
||||||
|
|
||||||
def installed?(app_id, channel)
|
def installed?(app_id, channel)
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class W3DHub
|
|||||||
@task_state = :running
|
@task_state = :running
|
||||||
|
|
||||||
Thread.new do
|
Thread.new do
|
||||||
Sync do
|
# Sync do
|
||||||
begin
|
begin
|
||||||
status = execute_task
|
status = execute_task
|
||||||
rescue FailFast
|
rescue FailFast
|
||||||
@@ -78,7 +78,7 @@ class W3DHub
|
|||||||
|
|
||||||
hide_application_taskbar if @task_state == :failed
|
hide_application_taskbar if @task_state == :failed
|
||||||
send_message_dialog(:failure, "Task #{type.inspect} failed for #{@application.name}", @task_failure_reason) if @task_state == :failed && !@fail_silently
|
send_message_dialog(:failure, "Task #{type.inspect} failed for #{@application.name}", @task_failure_reason) if @task_state == :failed && !@fail_silently
|
||||||
end
|
# end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -147,12 +147,12 @@ class W3DHub
|
|||||||
# FIXME: Check that there is enough disk space
|
# FIXME: Check that there is enough disk space
|
||||||
|
|
||||||
# tar present?
|
# tar present?
|
||||||
bsdtar_present = system("#{W3DHub.tar_command} --help")
|
bsdtar_present = W3DHub.command("#{W3DHub.tar_command} --help")
|
||||||
fail!("FAIL FAST: `#{W3DHub.tar_command} --help` command failed, #{W3DHub.tar_command} is not installed. Will be unable to unpack packages.") unless bsdtar_present
|
fail!("FAIL FAST: `#{W3DHub.tar_command} --help` command failed, #{W3DHub.tar_command} is not installed. Will be unable to unpack packages.") unless bsdtar_present
|
||||||
|
|
||||||
# Wine present?
|
# Wine present?
|
||||||
if W3DHub.unix?
|
if W3DHub.unix?
|
||||||
wine_present = system("which #{Store.settings[:wine_command]}")
|
wine_present = W3DHub.command("which #{Store.settings[:wine_command]}")
|
||||||
fail!("FAIL FAST: `which #{Store.settings[:wine_command]}` command failed, wine is not installed. Will be unable to create prefixes or launch games.") unless wine_present
|
fail!("FAIL FAST: `which #{Store.settings[:wine_command]}` command failed, wine is not installed. Will be unable to create prefixes or launch games.") unless wine_present
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -636,7 +636,7 @@ class W3DHub
|
|||||||
package_path = Cache.package_path(package.category, package.subcategory, package.name, package.version)
|
package_path = Cache.package_path(package.category, package.subcategory, package.name, package.version)
|
||||||
|
|
||||||
logger.info(LOG_TAG) { " Running #{W3DHub.tar_command} command: #{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{path}\"" }
|
logger.info(LOG_TAG) { " Running #{W3DHub.tar_command} command: #{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{path}\"" }
|
||||||
return system("#{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{path}\"")
|
return W3DHub.command("#{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{path}\"")
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_patch(package, path)
|
def apply_patch(package, path)
|
||||||
@@ -648,7 +648,7 @@ class W3DHub
|
|||||||
Cache.create_directories(temp_path, true)
|
Cache.create_directories(temp_path, true)
|
||||||
|
|
||||||
logger.info(LOG_TAG) { " Running #{W3DHub.tar_command} command: #{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{temp_path}\"" }
|
logger.info(LOG_TAG) { " Running #{W3DHub.tar_command} command: #{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{temp_path}\"" }
|
||||||
system("#{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{temp_path}\"")
|
W3DHub.command("#{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{temp_path}\"")
|
||||||
|
|
||||||
logger.info(LOG_TAG) { " Loading #{temp_path}/#{manifest_file.name}.patch..." }
|
logger.info(LOG_TAG) { " Loading #{temp_path}/#{manifest_file.name}.patch..." }
|
||||||
patch_mix = W3DHub::Mixer::Reader.new(file_path: "#{temp_path}/#{manifest_file.name}.patch", ignore_crc_mismatches: false)
|
patch_mix = W3DHub::Mixer::Reader.new(file_path: "#{temp_path}/#{manifest_file.name}.patch", ignore_crc_mismatches: false)
|
||||||
|
|||||||
@@ -9,13 +9,12 @@ class W3DHub
|
|||||||
logger.info(LOG_TAG) { "Starting background job worker..." }
|
logger.info(LOG_TAG) { "Starting background job worker..." }
|
||||||
|
|
||||||
|
|
||||||
|
@@thread = Thread.current
|
||||||
@@alive = true
|
@@alive = true
|
||||||
@@run = true
|
@@run = true
|
||||||
@@instance = self.new
|
@@instance = self.new
|
||||||
|
|
||||||
Async do
|
@@instance.handle_jobs
|
||||||
@@instance.handle_jobs
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.instance
|
def self.instance
|
||||||
@@ -30,32 +29,82 @@ class W3DHub
|
|||||||
@@alive
|
@@alive
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.busy?
|
||||||
|
instance&.busy?
|
||||||
|
end
|
||||||
|
|
||||||
def self.shutdown!
|
def self.shutdown!
|
||||||
@@run = false
|
@@run = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.kill!
|
||||||
|
@@thread.kill
|
||||||
|
|
||||||
|
@@instance.kill!
|
||||||
|
end
|
||||||
|
|
||||||
def self.job(job, callback, error_handler = nil)
|
def self.job(job, callback, error_handler = nil)
|
||||||
@@instance.add_job(Job.new(job: job, callback: callback, error_handler: error_handler))
|
@@instance.add_job(Job.new(job: job, callback: callback, error_handler: error_handler))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.parallel_job(job, callback, error_handler = nil)
|
||||||
|
@@instance.add_parallel_job(Job.new(job: job, callback: callback, error_handler: error_handler))
|
||||||
|
end
|
||||||
|
|
||||||
def self.foreground_job(job, callback, error_handler = nil)
|
def self.foreground_job(job, callback, error_handler = nil)
|
||||||
@@instance.add_job(Job.new(job: job, callback: callback, error_handler: error_handler, deliver_to_queue: true))
|
@@instance.add_job(Job.new(job: job, callback: callback, error_handler: error_handler, deliver_to_queue: true))
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
|
@busy = false
|
||||||
@jobs = []
|
@jobs = []
|
||||||
|
|
||||||
|
# Jobs which are order independent
|
||||||
|
@parallel_busy = false
|
||||||
|
@thread_pool = []
|
||||||
|
@parallel_jobs = []
|
||||||
|
end
|
||||||
|
|
||||||
|
def kill!
|
||||||
|
@thread_pool.each(&:kill)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_jobs
|
def handle_jobs
|
||||||
|
8.times do |i|
|
||||||
|
Thread.new do |thread|
|
||||||
|
@thread_pool << thread
|
||||||
|
|
||||||
|
while BackgroundWorker.run?
|
||||||
|
job = @parallel_jobs.shift
|
||||||
|
|
||||||
|
@parallel_busy = true
|
||||||
|
|
||||||
|
begin
|
||||||
|
job&.do
|
||||||
|
rescue => e
|
||||||
|
job&.raise_error(e)
|
||||||
|
end
|
||||||
|
|
||||||
|
@parallel_busy = !@parallel_jobs.empty?
|
||||||
|
|
||||||
|
sleep 0.1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
while BackgroundWorker.run?
|
while BackgroundWorker.run?
|
||||||
job = @jobs.shift
|
job = @jobs.shift
|
||||||
|
|
||||||
|
@busy = true
|
||||||
|
|
||||||
begin
|
begin
|
||||||
job&.do
|
job&.do
|
||||||
rescue => error
|
rescue => e
|
||||||
job&.raise_error(error)
|
job&.raise_error(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@busy = !@jobs.empty?
|
||||||
|
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -67,6 +116,14 @@ class W3DHub
|
|||||||
@jobs << job
|
@jobs << job
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_parallel_job(job)
|
||||||
|
@parallel_jobs << job
|
||||||
|
end
|
||||||
|
|
||||||
|
def busy?
|
||||||
|
@busy || @parallel_busy
|
||||||
|
end
|
||||||
|
|
||||||
class Job
|
class Job
|
||||||
def initialize(job:, callback:, error_handler: nil, deliver_to_queue: false)
|
def initialize(job:, callback:, error_handler: nil, deliver_to_queue: false)
|
||||||
@job = job
|
@job = job
|
||||||
|
|||||||
10
lib/cache.rb
10
lib/cache.rb
@@ -16,12 +16,12 @@ class W3DHub
|
|||||||
path
|
path
|
||||||
elsif async
|
elsif async
|
||||||
BackgroundWorker.job(
|
BackgroundWorker.job(
|
||||||
-> { Async::HTTP::Internet.instance.get(uri, W3DHub::Api::DEFAULT_HEADERS) },
|
-> { Api.get(uri, W3DHub::Api::DEFAULT_HEADERS) },
|
||||||
->(response) { response.save(path, "wb") if response.success? }
|
->(response) { File.open(path, "wb") { |f| f.write response.body } if response.status == 200 }
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
response = Async::HTTP::Internet.instance.get(uri, W3DHub::Api::DEFAULT_HEADERS)
|
response = Api.get(uri, W3DHub::Api::DEFAULT_HEADERS)
|
||||||
response.save(path, "wb") if response.success?
|
File.open(path, "wb") { |f| f.write response.body } if response.status == 200
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ class W3DHub
|
|||||||
block.call(chunk, remaining_bytes, total_bytes)
|
block.call(chunk, remaining_bytes, total_bytes)
|
||||||
end
|
end
|
||||||
|
|
||||||
response.success?
|
response.status == 200
|
||||||
ensure
|
ensure
|
||||||
file&.close
|
file&.close
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -40,6 +40,59 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.command(command, &block)
|
||||||
|
if windows?
|
||||||
|
stdout_read, stdout_write = IO.pipe if block
|
||||||
|
|
||||||
|
hash = {
|
||||||
|
command_line: command,
|
||||||
|
creation_flags: Process::DETACHED_PROCESS,
|
||||||
|
process_inherit: true,
|
||||||
|
thread_inherit: true,
|
||||||
|
close_handles: false,
|
||||||
|
inherit: true
|
||||||
|
}
|
||||||
|
|
||||||
|
if block
|
||||||
|
hash[:startup_info] = {
|
||||||
|
stdout: stdout_write,
|
||||||
|
stderr: stdout_write
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
process_info = Process.create(**hash)
|
||||||
|
|
||||||
|
pid = process_info.process_id
|
||||||
|
status = -1
|
||||||
|
|
||||||
|
until (status = Process.get_exitcode(pid))
|
||||||
|
if block
|
||||||
|
readable, _writable, _errorable = IO.select([stdout_read], [], [], 1)
|
||||||
|
|
||||||
|
readable&.each do |io|
|
||||||
|
line = io.readpartial(1024)
|
||||||
|
|
||||||
|
block&.call(line)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
sleep 0.1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
status.zero?
|
||||||
|
else
|
||||||
|
IO.popen(command) do |io|
|
||||||
|
if block
|
||||||
|
io.each_line do |line|
|
||||||
|
block&.call(line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
$CHILD_STATUS.success?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.home_directory
|
def self.home_directory
|
||||||
File.expand_path("~")
|
File.expand_path("~")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -218,6 +218,8 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
|
|
||||||
def find_element_by_tag(container, tag, list = [])
|
def find_element_by_tag(container, tag, list = [])
|
||||||
|
return unless container
|
||||||
|
|
||||||
container.children.each do |child|
|
container.children.each do |child|
|
||||||
list << child if child.style.tag == tag
|
list << child if child.style.tag == tag
|
||||||
|
|
||||||
@@ -249,6 +251,7 @@ class W3DHub
|
|||||||
server_map.value = server&.status&.map
|
server_map.value = server&.status&.map
|
||||||
player_count.value = "#{server&.status&.player_count}/#{server&.status&.max_players}"
|
player_count.value = "#{server&.status&.player_count}/#{server&.status&.max_players}"
|
||||||
server_ping.value = ping_icon(server)
|
server_ping.value = ping_icon(server)
|
||||||
|
server_ping.parent.parent.tip = ping_tip(server)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_server_ping(server)
|
def update_server_ping(server)
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class W3DHub
|
|||||||
logger.info(LOG_TAG) { "Refreshing user login..." }
|
logger.info(LOG_TAG) { "Refreshing user login..." }
|
||||||
|
|
||||||
# TODO: Check without network
|
# TODO: Check without network
|
||||||
Api.on_fiber(:refresh_user_login, account.refresh_token) do |refreshed_account|
|
Api.on_thread(:refresh_user_login, account.refresh_token) do |refreshed_account|
|
||||||
update_account_data(refreshed_account)
|
update_account_data(refreshed_account)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
|
|
||||||
def service_status
|
def service_status
|
||||||
Api.on_fiber(:service_status) do |service_status|
|
Api.on_thread(:service_status) do |service_status|
|
||||||
@service_status = service_status
|
@service_status = service_status
|
||||||
|
|
||||||
if @service_status
|
if @service_status
|
||||||
@@ -132,7 +132,7 @@ class W3DHub
|
|||||||
def applications
|
def applications
|
||||||
@status_label.value = I18n.t(:"boot.checking_for_updates")
|
@status_label.value = I18n.t(:"boot.checking_for_updates")
|
||||||
|
|
||||||
Api.on_fiber(:applications) do |applications|
|
Api.on_thread(:applications) do |applications|
|
||||||
if applications
|
if applications
|
||||||
Store.applications = applications
|
Store.applications = applications
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ class W3DHub
|
|||||||
packages << { category: app.category, subcategory: app.id, name: "#{app.id}.ico", version: "" }
|
packages << { category: app.category, subcategory: app.id, name: "#{app.id}.ico", version: "" }
|
||||||
end
|
end
|
||||||
|
|
||||||
Api.on_fiber(:package_details, packages) do |package_details|
|
Api.on_thread(:package_details, packages) do |package_details|
|
||||||
package_details&.each do |package|
|
package_details&.each do |package|
|
||||||
path = Cache.package_path(package.category, package.subcategory, package.name, package.version)
|
path = Cache.package_path(package.category, package.subcategory, package.name, package.version)
|
||||||
generated_icon_path = "#{GAME_ROOT_PATH}/media/icons/#{package.subcategory}.png"
|
generated_icon_path = "#{GAME_ROOT_PATH}/media/icons/#{package.subcategory}.png"
|
||||||
@@ -180,7 +180,7 @@ class W3DHub
|
|||||||
def server_list
|
def server_list
|
||||||
@status_label.value = I18n.t(:"server_browser.fetching_server_list")
|
@status_label.value = I18n.t(:"server_browser.fetching_server_list")
|
||||||
|
|
||||||
Api.on_fiber(:server_list, 2) do |list|
|
Api.on_thread(:server_list, 2) do |list|
|
||||||
Store.server_list = list.sort_by! { |s| s&.status&.players&.size }.reverse if list
|
Store.server_list = list.sort_by! { |s| s&.status&.players&.size }.reverse if list
|
||||||
|
|
||||||
Store.server_list_last_fetch = Gosu.milliseconds
|
Store.server_list_last_fetch = Gosu.milliseconds
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ class W3DHub
|
|||||||
while (block = Store.main_thread_queue.shift)
|
while (block = Store.main_thread_queue.shift)
|
||||||
block&.call
|
block&.call
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Manually sleep main thread so that the BackgroundWorker thread can be scheduled
|
||||||
|
sleep(update_interval / 1000.0) if W3DHub::BackgroundWorker.busy? || Store.application_manager.busy?
|
||||||
end
|
end
|
||||||
|
|
||||||
def gain_focus
|
def gain_focus
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ require "fileutils"
|
|||||||
require "digest"
|
require "digest"
|
||||||
require "rexml"
|
require "rexml"
|
||||||
require "logger"
|
require "logger"
|
||||||
|
require "time"
|
||||||
|
|
||||||
class W3DHub
|
class W3DHub
|
||||||
W3DHUB_DEBUG = ARGV.join.include?("--debug")
|
W3DHUB_DEBUG = ARGV.join.include?("--debug")
|
||||||
@@ -22,7 +23,31 @@ end
|
|||||||
|
|
||||||
module Kernel
|
module Kernel
|
||||||
def logger
|
def logger
|
||||||
W3DHub::LOGGER
|
@logger = W3DHub::LOGGER
|
||||||
|
end
|
||||||
|
|
||||||
|
class W3DHubLogger
|
||||||
|
def initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
def level=(options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def info(tag, &block)
|
||||||
|
pp [tag, block&.call]
|
||||||
|
end
|
||||||
|
|
||||||
|
def debug(tag, &block)
|
||||||
|
pp [tag, block&.call]
|
||||||
|
end
|
||||||
|
|
||||||
|
def warn(tag, &block)
|
||||||
|
pp [tag, block&.call]
|
||||||
|
end
|
||||||
|
|
||||||
|
def error(tag, &block)
|
||||||
|
pp [tag, block&.call]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -42,15 +67,8 @@ end
|
|||||||
|
|
||||||
require "i18n"
|
require "i18n"
|
||||||
require "launchy"
|
require "launchy"
|
||||||
|
require "websocket-client-simple"
|
||||||
require "async"
|
require "English"
|
||||||
require "async/barrier"
|
|
||||||
require "async/semaphore"
|
|
||||||
require "async/http/internet/instance"
|
|
||||||
require "async/http/endpoint"
|
|
||||||
require "async/websocket/client"
|
|
||||||
require "protocol/websocket/connection"
|
|
||||||
require "net/ping"
|
|
||||||
|
|
||||||
I18n.load_path << Dir["#{W3DHub::GAME_ROOT_PATH}/locales/*.yml"]
|
I18n.load_path << Dir["#{W3DHub::GAME_ROOT_PATH}/locales/*.yml"]
|
||||||
I18n.default_locale = :en
|
I18n.default_locale = :en
|
||||||
@@ -118,20 +136,30 @@ require_relative "lib/asterisk/states/game_form"
|
|||||||
require_relative "lib/asterisk/states/irc_profile_form"
|
require_relative "lib/asterisk/states/irc_profile_form"
|
||||||
require_relative "lib/asterisk/states/server_profile_form"
|
require_relative "lib/asterisk/states/server_profile_form"
|
||||||
|
|
||||||
|
require "win32/process" if W3DHub.windows?
|
||||||
|
|
||||||
logger.info(W3DHub::LOG_TAG) { "W3D Hub Linux Launcher v#{W3DHub::VERSION}" }
|
logger.info(W3DHub::LOG_TAG) { "W3D Hub Linux Launcher v#{W3DHub::VERSION}" }
|
||||||
|
|
||||||
Thread.new do
|
Thread.new do
|
||||||
W3DHub::BackgroundWorker.create
|
W3DHub::BackgroundWorker.create
|
||||||
end
|
end
|
||||||
|
|
||||||
|
until W3DHub::BackgroundWorker.alive?
|
||||||
|
sleep 0.1
|
||||||
|
end
|
||||||
|
|
||||||
logger.info(W3DHub::LOG_TAG) { "Launching window..." }
|
logger.info(W3DHub::LOG_TAG) { "Launching window..." }
|
||||||
# W3DHub::Window.new(width: 980, height: 720, borderless: false, resizable: true).show unless defined?(Ocra)
|
# W3DHub::Window.new(width: 980, height: 720, borderless: false, resizable: true).show unless defined?(Ocra)
|
||||||
W3DHub::Window.new(width: 1280, height: 800, borderless: false, resizable: true).show unless defined?(Ocra)
|
W3DHub::Window.new(width: 1280, height: 800, borderless: false, resizable: true).show unless defined?(Ocra)
|
||||||
# W3DHub::Window.new(width: 1920, height: 1080, borderless: false, resizable: true).show unless defined?(Ocra)
|
# W3DHub::Window.new(width: 1920, height: 1080, borderless: false, resizable: true).show unless defined?(Ocra)
|
||||||
W3DHub::BackgroundWorker.shutdown!
|
W3DHub::BackgroundWorker.shutdown!
|
||||||
|
|
||||||
|
worker_soft_halt = Gosu.milliseconds
|
||||||
|
|
||||||
# Wait for BackgroundWorker to return
|
# Wait for BackgroundWorker to return
|
||||||
while W3DHub::BackgroundWorker.alive?
|
while W3DHub::BackgroundWorker.alive?
|
||||||
|
W3DHub::BackgroundWorker.kill! if Gosu.milliseconds - worker_soft_halt >= 1_000
|
||||||
|
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user