mirror of
https://github.com/cyberarm/w3d_hub_linux_launcher.git
synced 2025-12-16 01:02:34 +00:00
202 lines
6.3 KiB
Ruby
202 lines
6.3 KiB
Ruby
class W3DHub
|
|
class Api
|
|
class ServerListUpdater
|
|
LOG_TAG = "W3DHub::Api::ServerListUpdater".freeze
|
|
include CyberarmEngine::Common
|
|
@@instance = nil
|
|
|
|
def self.instance
|
|
return @@instance if @@instance
|
|
|
|
@@instance = ServerListUpdater.new
|
|
end
|
|
|
|
attr_accessor :auto_reconnect, :invocation_id
|
|
|
|
def initialize
|
|
@auto_reconnect = false
|
|
|
|
@invocation_id = 0
|
|
|
|
logger.info(LOG_TAG) { "Starting emulated SignalR Server List Updater..." }
|
|
run
|
|
end
|
|
|
|
def run
|
|
Thread.new do
|
|
begin
|
|
connect
|
|
|
|
while W3DHub::BackgroundWorker.alive?
|
|
connect if @auto_reconnect
|
|
sleep 1
|
|
end
|
|
rescue => e
|
|
puts e
|
|
puts e.backtrace
|
|
|
|
sleep 30
|
|
retry
|
|
end
|
|
end
|
|
|
|
logger.debug(LOG_TAG) { "Cleaning up..." }
|
|
@@instance = nil
|
|
end
|
|
|
|
def connect
|
|
@auto_reconnect = false
|
|
|
|
logger.debug(LOG_TAG) { "Requesting connection token..." }
|
|
response = Api.post("/listings/push/v2/negotiate?negotiateVersion=1", Api::DEFAULT_HEADERS, "", :gsh)
|
|
|
|
if response.status != 200
|
|
@auto_reconnect = true
|
|
return
|
|
end
|
|
|
|
data = JSON.parse(response.body, symbolize_names: true)
|
|
|
|
@invocation_id = 0 if @invocation_id > 9095
|
|
id = data[:connectionToken]
|
|
endpoint = "#{Api::SERVER_LIST_ENDPOINT}/listings/push/v2?id=#{id}"
|
|
|
|
logger.debug(LOG_TAG) { "Connecting to websocket..." }
|
|
this = self
|
|
@ws = WebSocket::Client::Simple.connect(endpoint, headers: Api::DEFAULT_HEADERS) do |ws|
|
|
ws.on(:open) do
|
|
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 do |server|
|
|
this.invocation_id += 1
|
|
mode = 1 # 2 full details, 1 basic details
|
|
out = { "type": 1, "invocationId": "#{this.invocation_id}", "target": "SubscribeToServerStatusUpdates", "arguments": [server.id, mode] }
|
|
ws.send(out.to_json + "\x1e")
|
|
end
|
|
end
|
|
|
|
ws.on(:message) do |msg|
|
|
msg = msg.data.split("\x1e").first
|
|
|
|
hash = JSON.parse(msg, symbolize_names: true)
|
|
|
|
# pp hash if hash[:target] != "ServerStatusChanged" && hash[:type] != 6 && hash[:type] != 3
|
|
|
|
# Send PING(?)
|
|
if hash.empty? || hash[:type] == 6
|
|
ws.send({ type: 6 }.to_json + "\x1e")
|
|
else
|
|
case hash[:type]
|
|
when 1
|
|
case hash[:target]
|
|
when "ServerRegistered"
|
|
data = hash[:arguments].first
|
|
|
|
this.invocation_id += 1
|
|
out = { "type": 1, "invocationId": "#{this.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"
|
|
id, data = hash[:arguments]
|
|
server = Store.server_list.find { |s| s.id == id }
|
|
server_updated = server&.update(data)
|
|
|
|
BackgroundWorker.foreground_job(->(server) { server }, ->(server) { States::Interface.instance&.update_server_browser(server, :update) }, nil, server) if server_updated
|
|
|
|
when "ServerUnregistered"
|
|
id = hash[:arguments].first
|
|
server = Store.server_list.find { |s| s.id == id }
|
|
|
|
if server
|
|
Store.server_list.delete(server)
|
|
BackgroundWorker.foreground_job(->(server) { server }, ->(server) { States::Interface.instance&.update_server_browser(server, :remove) }, nil, server)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ws.on(:close) do |e|
|
|
logger.error(LOG_TAG) { e }
|
|
this.auto_reconnect = true
|
|
ws.close
|
|
end
|
|
|
|
ws.on(:error) do |e|
|
|
logger.error(LOG_TAG) { e }
|
|
this.auto_reconnect = true
|
|
ws.close
|
|
end
|
|
end
|
|
|
|
@ws = nil
|
|
end
|
|
|
|
def refresh_server_list(list)
|
|
new_servers = []
|
|
removed_servers = []
|
|
|
|
# find new servers
|
|
list.each do |server|
|
|
found_server = Store.server_list.find { |s| s.id == server.id }
|
|
|
|
new_servers << server unless found_server
|
|
end
|
|
|
|
# find removed servers
|
|
Store.server_list.each do |server|
|
|
found_server = list.find { |s| s.id == server.id }
|
|
|
|
removed_servers << server unless found_server
|
|
end
|
|
|
|
# purge removed servers from list
|
|
Store.server_list.reject! do |server|
|
|
removed_servers.find { |s| server.id == s.id }
|
|
end
|
|
|
|
# add new servers to list
|
|
Store.server_list = Store.server_list + new_servers
|
|
|
|
if @ws
|
|
# unsubscribe from removed servers
|
|
removed_servers.each do
|
|
@invocation_id += 1
|
|
out = { "type": 1, "invocationId": "#{@invocation_id}", "target": "SubscribeToServerStatusUpdates", "arguments": [server.id, 0] }
|
|
ws.send(out.to_json + "\x1e")
|
|
end
|
|
|
|
# subscribe to new servers
|
|
new_servers.each do
|
|
@invocation_id += 1
|
|
out = { "type": 1, "invocationId": "#{@invocation_id}", "target": "SubscribeToServerStatusUpdates", "arguments": [server.id, 1] }
|
|
ws.send(out.to_json + "\x1e")
|
|
end
|
|
end
|
|
|
|
# sort list
|
|
Store.server_list.sort_by! { |s| [s.status.player_count, s.id] }.reverse!
|
|
end
|
|
end
|
|
end
|
|
end
|