Compare commits

..

4 Commits

7 changed files with 132 additions and 49 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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|