mirror of
https://github.com/cyberarm/w3d_hub_linux_launcher.git
synced 2025-12-16 17:22:35 +00:00
Compare commits
4 Commits
02307f1789
...
f55924596d
| Author | SHA1 | Date | |
|---|---|---|---|
| f55924596d | |||
| d84c8321c5 | |||
| 38e0de76df | |||
| 9bdca9eba1 |
23
lib/api.rb
23
lib/api.rb
@@ -43,8 +43,9 @@ class W3DHub
|
|||||||
#! === W3D Hub API === !#
|
#! === W3D Hub API === !#
|
||||||
|
|
||||||
ENDPOINT = "https://secure.w3dhub.com".freeze
|
ENDPOINT = "https://secure.w3dhub.com".freeze
|
||||||
|
API_CONNECTION = Excon.new(ENDPOINT, persistent: true)
|
||||||
|
|
||||||
def self.excon(method, url, headers = DEFAULT_HEADERS, body = nil)
|
def self.excon(method, url, headers = DEFAULT_HEADERS, body = nil, api = :api)
|
||||||
logger.debug(LOG_TAG) { "Fetching #{method.to_s.upcase} \"#{url}\"..." }
|
logger.debug(LOG_TAG) { "Fetching #{method.to_s.upcase} \"#{url}\"..." }
|
||||||
|
|
||||||
# Inject Authorization header if account data is populated
|
# Inject Authorization header if account data is populated
|
||||||
@@ -54,10 +55,13 @@ class W3DHub
|
|||||||
headers["Authorization"] = "Bearer #{Store.account.access_token}"
|
headers["Authorization"] = "Bearer #{Store.account.access_token}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
connection = api == :api ? API_CONNECTION : GSH_CONNECTION
|
||||||
|
endpoint = api == :api ? ENDPOINT : SERVER_LIST_ENDPOINT
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Excon.send(
|
connection.send(
|
||||||
method,
|
method,
|
||||||
url,
|
path: url.sub(endpoint, ""),
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: body,
|
body: body,
|
||||||
nonblock: true,
|
nonblock: true,
|
||||||
@@ -82,7 +86,7 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.post(url, headers = DEFAULT_HEADERS, body = nil)
|
def self.post(url, headers = DEFAULT_HEADERS, body = nil, api = :api)
|
||||||
excon(:post, url, headers, body)
|
excon(:post, url, headers, body)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -258,9 +262,10 @@ class W3DHub
|
|||||||
#! === Server List API === !#
|
#! === Server List API === !#
|
||||||
|
|
||||||
SERVER_LIST_ENDPOINT = "https://gsh.w3dhub.com".freeze
|
SERVER_LIST_ENDPOINT = "https://gsh.w3dhub.com".freeze
|
||||||
|
GSH_CONNECTION = Excon.new(SERVER_LIST_ENDPOINT, persistent: true)
|
||||||
|
|
||||||
def self.get(url, headers = DEFAULT_HEADERS, body = nil)
|
def self.get(url, headers = DEFAULT_HEADERS, body = nil, api = :api)
|
||||||
excon(:get, url, headers, body)
|
excon(:get, url, headers, body, api)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Method: GET
|
# Method: GET
|
||||||
@@ -281,7 +286,7 @@ class W3DHub
|
|||||||
# ...players[]:
|
# ...players[]:
|
||||||
# nick, team (index of teams array), score, kills, deaths
|
# nick, team (index of teams array), score, kills, deaths
|
||||||
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}", DEFAULT_HEADERS, nil, :gsh)
|
||||||
|
|
||||||
if response.status == 200
|
if response.status == 200
|
||||||
data = JSON.parse(response.body, symbolize_names: true)
|
data = JSON.parse(response.body, symbolize_names: true)
|
||||||
@@ -303,7 +308,9 @@ class W3DHub
|
|||||||
# ...players[]:
|
# ...players[]:
|
||||||
# nick, team (index of teams array), score, kills, deaths
|
# nick, team (index of teams array), score, kills, deaths
|
||||||
def self.server_details(id, level)
|
def self.server_details(id, level)
|
||||||
response = get("#{SERVER_LIST_ENDPOINT}/listings/getStatus/v2/#{id}?statusLevel=#{level}")
|
return false unless id && level
|
||||||
|
|
||||||
|
response = get("#{SERVER_LIST_ENDPOINT}/listings/getStatus/v2/#{id}?statusLevel=#{level}", DEFAULT_HEADERS, nil, :gsh)
|
||||||
|
|
||||||
if response.status == 200
|
if response.status == 200
|
||||||
hash = JSON.parse(response.body, symbolize_names: true)
|
hash = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ class W3DHub
|
|||||||
@channel = @data[:channel] || "release"
|
@channel = @data[:channel] || "release"
|
||||||
@ping = -1
|
@ping = -1
|
||||||
|
|
||||||
@status = @data[:status] ? Status.new(@data[:status]) : nil
|
@status = Status.new(@data[:status])
|
||||||
|
|
||||||
@ping_interval = 30_000
|
@ping_interval = 30_000
|
||||||
@last_pinged = Gosu.milliseconds + @ping_interval + 1
|
@last_pinged = Gosu.milliseconds + @ping_interval + 1_000
|
||||||
end
|
end
|
||||||
|
|
||||||
def update(hash)
|
def update(hash)
|
||||||
@@ -34,11 +34,11 @@ class W3DHub
|
|||||||
@status.players = hash[:players]&.select { |t| t[:nick] != "Nod" && t[:nick] != "GDI" }&.map { |t| Player.new(t) } if hash[:players]
|
@status.players = hash[:players]&.select { |t| t[:nick] != "Nod" && t[:nick] != "GDI" }&.map { |t| Player.new(t) } if hash[:players]
|
||||||
|
|
||||||
send_ping
|
send_ping
|
||||||
|
else
|
||||||
return true
|
@status = Status.new(hash)
|
||||||
end
|
end
|
||||||
|
|
||||||
false
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_ping(force_ping = false)
|
def send_ping(force_ping = false)
|
||||||
@@ -70,18 +70,18 @@ class W3DHub
|
|||||||
attr_accessor :name, :password, :map, :max_players, :player_count, :started, :remaining, :teams, :players
|
attr_accessor :name, :password, :map, :max_players, :player_count, :started, :remaining, :teams, :players
|
||||||
|
|
||||||
def initialize(hash)
|
def initialize(hash)
|
||||||
@data = hash
|
@data = hash || {}
|
||||||
|
|
||||||
@teams = @data[:teams]&.map { |t| Team.new(t) }
|
@teams = @data[:teams]&.map { |t| Team.new(t) } || []
|
||||||
@players = @data[:players]&.select { |t| t[:nick] != "Nod" && t[:nick] != "GDI" }&.map { |t| Player.new(t) }
|
@players = @data[:players]&.select { |t| t[:nick] != "Nod" && t[:nick] != "GDI" }&.map { |t| Player.new(t) } || []
|
||||||
|
|
||||||
@name = @data[:name]
|
@name = @data[:name] || ""
|
||||||
@password = @data[:password] || false
|
@password = @data[:password] || false
|
||||||
@map = @data[:map]
|
@map = @data[:map] || ""
|
||||||
@max_players = @data[:maxplayers]
|
@max_players = @data[:maxplayers] || 0
|
||||||
@player_count = @players.size || @data[:numplayers].to_i
|
@player_count = @players.size || @data[:numplayers].to_i
|
||||||
@started = @data[:started]
|
@started = @data[:started] || Time.now
|
||||||
@remaining = @data[:remaining]
|
@remaining = @data[:remaining] || "00.00.00"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class W3DHub
|
|||||||
response = Excon.post("https://gsh.w3dhub.com/listings/push/v2/negotiate?negotiateVersion=1", headers: Api::DEFAULT_HEADERS, body: "")
|
response = Excon.post("https://gsh.w3dhub.com/listings/push/v2/negotiate?negotiateVersion=1", headers: Api::DEFAULT_HEADERS, body: "")
|
||||||
data = JSON.parse(response.body, symbolize_names: true)
|
data = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
invocation_id = 0
|
||||||
id = data[:connectionToken]
|
id = data[:connectionToken]
|
||||||
endpoint = "https://gsh.w3dhub.com/listings/push/v2?id=#{id}"
|
endpoint = "https://gsh.w3dhub.com/listings/push/v2?id=#{id}"
|
||||||
|
|
||||||
@@ -60,10 +61,10 @@ class W3DHub
|
|||||||
ws.send({ protocol: "json", version: 1 }.to_json + "\x1e")
|
ws.send({ protocol: "json", version: 1 }.to_json + "\x1e")
|
||||||
|
|
||||||
logger.debug(LOG_TAG) { "Subscribing to server changes..." }
|
logger.debug(LOG_TAG) { "Subscribing to server changes..." }
|
||||||
Store.server_list.each_with_index do |server, i|
|
Store.server_list.each do |server|
|
||||||
i += 1
|
invocation_id += 1
|
||||||
mode = 1 # 2 full details, 1 basic details
|
mode = 1 # 2 full details, 1 basic details
|
||||||
out = { "type": 1, "invocationId": "#{i}", "target": "SubscribeToServerStatusUpdates", "arguments": [server.id, mode] }
|
out = { "type": 1, "invocationId": "#{invocation_id}", "target": "SubscribeToServerStatusUpdates", "arguments": [server.id, mode] }
|
||||||
ws.send(out.to_json + "\x1e")
|
ws.send(out.to_json + "\x1e")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -84,15 +85,34 @@ class W3DHub
|
|||||||
case hash[:target]
|
case hash[:target]
|
||||||
when "ServerRegistered"
|
when "ServerRegistered"
|
||||||
data = hash[:arguments].first
|
data = hash[:arguments].first
|
||||||
server = ServerListServer.new(data)
|
|
||||||
Store.server_list.push(server)
|
invocation_id += 1
|
||||||
|
out = { "type": 1, "invocationId": "#{invocation_id}", "target": "SubscribeToServerStatusUpdates", "arguments": [data[:id], 1] }
|
||||||
|
ws.send(out.to_json + "\x1e")
|
||||||
|
|
||||||
|
BackgroundWorker.foreground_job(
|
||||||
|
->(data) { [Api.server_details(data[:id], 2), data] },
|
||||||
|
->(array) do
|
||||||
|
server_data, data = array
|
||||||
|
|
||||||
|
next unless server_data
|
||||||
|
|
||||||
|
data[:status] = server_data
|
||||||
|
|
||||||
|
server = ServerListServer.new(data)
|
||||||
|
Store.server_list.push(server)
|
||||||
|
States::Interface.instance&.update_server_browser(server, :update)
|
||||||
|
end,
|
||||||
|
nil,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
|
||||||
when "ServerStatusChanged"
|
when "ServerStatusChanged"
|
||||||
id, data = hash[:arguments]
|
id, data = hash[: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)
|
||||||
|
|
||||||
BackgroundWorker.foreground_job(-> {}, ->(result){ States::Interface.instance&.update_server_browser(server, :update) }) if server_updated
|
BackgroundWorker.foreground_job(->(server) { server }, ->(server) { States::Interface.instance&.update_server_browser(server, :update) }, nil, server) if server_updated
|
||||||
|
|
||||||
when "ServerUnregistered"
|
when "ServerUnregistered"
|
||||||
id = hash[:arguments].first
|
id = hash[:arguments].first
|
||||||
@@ -100,7 +120,7 @@ class W3DHub
|
|||||||
|
|
||||||
if server
|
if server
|
||||||
Store.server_list.delete(server)
|
Store.server_list.delete(server)
|
||||||
BackgroundWorker.foreground_job(-> {}, ->(result){ States::Interface.instance&.update_server_browser(server, :remove) })
|
BackgroundWorker.foreground_job(->(server) { server }, ->(server) { States::Interface.instance&.update_server_browser(server, :remove) }, nil, server)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -43,20 +43,20 @@ class W3DHub
|
|||||||
@@instance.kill!
|
@@instance.kill!
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.job(job, callback, error_handler = nil)
|
def self.job(job, callback, error_handler = nil, data = 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, data: data))
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.parallel_job(job, callback, error_handler = nil)
|
def self.parallel_job(job, callback, error_handler = nil, data = nil)
|
||||||
@@instance.add_parallel_job(Job.new(job: job, callback: callback, error_handler: error_handler))
|
@@instance.add_parallel_job(Job.new(job: job, callback: callback, error_handler: error_handler, data: data))
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.foreground_job(job, callback, error_handler = nil)
|
def self.foreground_job(job, callback, error_handler = nil, data = 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, data: data))
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.foreground_parallel_job(job, callback, error_handler = nil)
|
def self.foreground_parallel_job(job, callback, error_handler = nil, data = nil)
|
||||||
@@instance.add_parallel_job(Job.new(job: job, callback: callback, error_handler: error_handler, deliver_to_queue: true))
|
@@instance.add_parallel_job(Job.new(job: job, callback: callback, error_handler: error_handler, deliver_to_queue: true, data: data))
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@@ -136,16 +136,16 @@ class W3DHub
|
|||||||
end
|
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, data: nil)
|
||||||
@job = job
|
@job = job
|
||||||
@callback = callback
|
@callback = callback
|
||||||
@error_handler = error_handler
|
@error_handler = error_handler
|
||||||
|
|
||||||
@deliver_to_queue = deliver_to_queue
|
@deliver_to_queue = deliver_to_queue
|
||||||
|
@data = data
|
||||||
end
|
end
|
||||||
|
|
||||||
def do
|
def do
|
||||||
result = @job.call
|
result = @data ? @job.call(@data) : @job.call
|
||||||
deliver(result)
|
deliver(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ class W3DHub
|
|||||||
class Community < Page
|
class Community < Page
|
||||||
def setup
|
def setup
|
||||||
@w3dhub_news ||= nil
|
@w3dhub_news ||= nil
|
||||||
|
@w3dhub_news_expires ||= 0
|
||||||
|
|
||||||
body.clear do
|
body.clear do
|
||||||
stack(width: 1.0, height: 1.0, padding: 8) do
|
stack(width: 1.0, height: 1.0, padding: 8) do
|
||||||
@@ -76,6 +77,30 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
super
|
||||||
|
|
||||||
|
|
||||||
|
if Gosu.milliseconds >= @w3dhub_news_expires
|
||||||
|
@w3dhub_news = nil
|
||||||
|
@w3dhub_news_expires = Gosu.milliseconds + 30_000 # seconds
|
||||||
|
|
||||||
|
@wd3hub_news_container.clear do
|
||||||
|
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
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def fetch_w3dhub_news
|
def fetch_w3dhub_news
|
||||||
lock = Cache.acquire_net_lock("w3dhub_news")
|
lock = Cache.acquire_net_lock("w3dhub_news")
|
||||||
return false unless lock
|
return false unless lock
|
||||||
@@ -90,6 +115,7 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
|
|
||||||
@w3dhub_news = news
|
@w3dhub_news = news
|
||||||
|
@w3dhub_news_expires = Gosu.milliseconds + (60 * 60 * 1000) # 1 hour (in ms)
|
||||||
|
|
||||||
"w3dhub_news"
|
"w3dhub_news"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ class W3DHub
|
|||||||
|
|
||||||
# Game Menu
|
# Game Menu
|
||||||
@game_page_container = stack(width: 1.0, fill: true, background_image: "#{GAME_ROOT_PATH}/media/textures/noiseb.png", background_image_mode: :tiled) do
|
@game_page_container = stack(width: 1.0, fill: true, background_image: "#{GAME_ROOT_PATH}/media/textures/noiseb.png", background_image_mode: :tiled) do
|
||||||
# , background_image: "C:/Users/cyber/Downloads/vlcsnap-2022-04-24-22h24m15s854.png"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -29,6 +28,36 @@ class W3DHub
|
|||||||
populate_games_list
|
populate_games_list
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
super
|
||||||
|
|
||||||
|
|
||||||
|
@game_news.each do |key, value|
|
||||||
|
next if key.end_with?("_expires")
|
||||||
|
|
||||||
|
if Gosu.milliseconds >= @game_news["#{key}_expires"]
|
||||||
|
@game_news.delete(key)
|
||||||
|
@game_news["#{key}_expires"] = Gosu.milliseconds + 30_000 # seconds
|
||||||
|
|
||||||
|
if @focused_game && @focused_game.id == key
|
||||||
|
@game_news_container.clear do
|
||||||
|
title I18n.t(:"games.fetching_news"), padding: 8
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def populate_games_list
|
def populate_games_list
|
||||||
@games_list_container.clear do
|
@games_list_container.clear do
|
||||||
background 0xaa_121920
|
background 0xaa_121920
|
||||||
@@ -398,6 +427,7 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
|
|
||||||
@game_news[game.id] = news
|
@game_news[game.id] = news
|
||||||
|
@game_news["#{game.id}_expires"] = Gosu.milliseconds + (60 * 60 * 1000) # 1 hour (in ms)
|
||||||
|
|
||||||
"game_news_#{game.id}"
|
"game_news_#{game.id}"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -258,14 +258,14 @@ class W3DHub
|
|||||||
player_count = find_element_by_tag(server_container, :player_count)
|
player_count = find_element_by_tag(server_container, :player_count)
|
||||||
server_ping = find_element_by_tag(server_container, :ping)
|
server_ping = find_element_by_tag(server_container, :ping)
|
||||||
|
|
||||||
game_icon.value = game_icon(server)
|
game_icon&.value = game_icon(server)
|
||||||
server_name.value = "<b>#{server&.status&.name}</b>"
|
server_name&.value = "<b>#{server&.status&.name}</b>"
|
||||||
server_channel.value = Store.application_manager.channel_name(server.game, server.channel).to_s
|
server_channel&.value = Store.application_manager.channel_name(server.game, server.channel).to_s
|
||||||
server_region.value = server.region
|
server_region&.value = server.region
|
||||||
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)
|
server_ping&.parent.parent.tip = ping_tip(server)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_server_ping(server)
|
def update_server_ping(server)
|
||||||
@@ -308,7 +308,7 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
|
|
||||||
def populate_server_list
|
def populate_server_list
|
||||||
Store.server_list = Store.server_list.sort_by! { |s| [s&.status&.player_count, s&.id] }.reverse if Store.server_list
|
Store.server_list = Store.server_list.sort_by! { |s| [s.status.player_count, s.id] }.reverse
|
||||||
|
|
||||||
@server_list_container.clear do
|
@server_list_container.clear do
|
||||||
Store.server_list.each do |server|
|
Store.server_list.each do |server|
|
||||||
|
|||||||
Reference in New Issue
Block a user