From 92f6a763819f1b7fd26175cd9802309ca95a2197 Mon Sep 17 00:00:00 2001 From: Cyberarm Date: Mon, 27 Dec 2021 18:37:02 -0600 Subject: [PATCH] Almost functional websocket based server list updater --- lib/api/server_list_updater.rb | 104 +++++++++++++++++++++++++-------- lib/states/boot.rb | 2 + 2 files changed, 83 insertions(+), 23 deletions(-) diff --git a/lib/api/server_list_updater.rb b/lib/api/server_list_updater.rb index ea5c712..c99bc75 100644 --- a/lib/api/server_list_updater.rb +++ b/lib/api/server_list_updater.rb @@ -1,62 +1,120 @@ class W3DHub class Api class ServerListUpdater - class Connection < ::Protocol::WebSocket::Connection + ##!!! 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 read1 - read1&.first - 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 + + def self.instance + return @@instance if @@instance + + @@instance = ServerListUpdater.new + end + + def initialize + run end # TODO: Properly start up and monitor for updates to server list - def initialize + def run Async do |task| - headers = [["User-Agent", "Cyberarm's Websocket Testing"]] - internet = Async::HTTP::Internet.instance - response = internet.post("https://gsh.w3dhub.com/listings/push/v2/negotiate?negotiateVersion=1", headers, [""]) + response = internet.post("https://gsh.w3dhub.com/listings/push/v2/negotiate?negotiateVersion=1", Api::DEFAULT_HEADERS, [""]) data = JSON.parse(response.read, symbolize_names: true) - # TODO: Replace with Api.server_list - response = internet.get("https://gsh.w3dhub.com/listings/getAll/v2?statusLevel=2", headers, [""]) - servers = JSON.parse(response.read, symbolize_names: true) - id = data[:connectionToken] endpoint = Async::HTTP::Endpoint.parse("https://gsh.w3dhub.com/listings/push/v2?id=#{id}", alpn_protocols: Async::HTTP::Protocol::HTTP11.names) - Async::WebSocket::Client.connect(endpoint, headers: headers, handler: WSS::Connection) do |connection| + Async::WebSocket::Client.connect(endpoint, headers: Api::DEFAULT_HEADERS, handler: PatchedConnection) do |connection| connection.write({ protocol: "json", version: 1 }) connection.flush - # Should be an empty hash for protocol agreement - connection.read - # Write keep alive? + pp connection.read connection.write({ "type": 6 }) - # Subscribe to server changes - servers.each_with_index do |server, i| + puts "servers: #{Store.server_list&.count}" + + Store.server_list.each_with_index do |server, i| i += 1 - out = { "type": 1, "invocationId": "#{i}", "target": "SubscribeToServerStatusUpdates", "arguments": [server[:id], 2] } + mode = 1 # 2 full details, 1 basic details + out = { "type": 1, "invocationId": "#{i}", "target": "SubscribeToServerStatusUpdates", "arguments": [server.id, 1] } connection.write(out) end while (message = connection.read) - # Keep alive? connection.write({ type: 6 }) if message.first[:type] == 6 - # TODO: process messages (of type 3?) - pp message + if message&.first&.fetch(:type) == 1 + message.each do |rpc| + next unless rpc[:target] == "ServerStatusChanged" + + id, data = rpc[:arguments] + pp [id, data.length, data] + server = Api::ServerListServer.new(data) + + pp [server.player_count, server.max_players] + end + end end end + ensure + @@instance = nil end end end diff --git a/lib/states/boot.rb b/lib/states/boot.rb index d8f0607..b8158dd 100644 --- a/lib/states/boot.rb +++ b/lib/states/boot.rb @@ -122,6 +122,8 @@ class W3DHub Store.server_list_last_fetch = Gosu.milliseconds + Api::ServerListUpdater.instance + @tasks[:server_list][:complete] = true rescue => e # Something went wrong!