Access W3D Hub API

This commit is contained in:
2021-11-14 12:07:09 -06:00
parent c923a8d6d4
commit b2a2a961b3
7 changed files with 301 additions and 3 deletions

137
lib/api.rb Normal file
View File

@@ -0,0 +1,137 @@
class W3DHub
class Api
USER_AGENT = "Cyberarm's Linux Friendly W3D Hub Launcher v#{W3DHub::VERSION}"
DEFAULT_HEADERS = {
"User-Agent": USER_AGENT
}
#! === W3D Hub API === !#
ENDPOINT = "https://secure.w3dhub.com"
W3DHUB_API_CONNECTION = Excon.new(ENDPOINT, persistent: true, connect_timeout: 15)
# Method: POST
# FORMAT: JSON
# /apis/launcher/1/user-login
# For an already logged in user the launcher sends
# a "refreshToken" in the data field: data={"refreshToken":"TOKEN_STRING"}
#
# For a logging in user the launcher sends
# data={"username":"NAME","password":"password_as_plaintext_but_over_https"}
#
# On successful login/token refresh the service responds with:
# {"session_token":"string","userid:"1234"...}
#
# On a failed login the service responds with:
# {"error":"login-failed"}
def self.user_refresh_token(refresh_token)
end
# See #user_refresh_token
def self.user_login(username, password)
end
# /apis/launcher/1/user-login
# Client sends an Authorization header bearer token which is received from logging in (Required?)
#
# Response: avatar-uri (Image download uri), id, username
def self.user_details(id)
end
# /apis/w3dhub/1/get-service-status
# Service response:
# {"services":{"authentication":true,"packageDownload":true}}
def self.service_status
response = W3DHUB_API_CONNECTION.post(
path: "apis/w3dhub/1/get-service-status",
headers: DEFAULT_HEADERS
)
if response.status == 200
ServiceStatus.new(response.body)
else
false
end
end
# /apis/launcher/1/get-applications
# Client sends an Authorization header bearer token which is received from logging in (Optional)
# Launcher sends an empty data request: data={}
# Response is a list of applications/games
def self.applications
response = W3DHUB_API_CONNECTION.post(
path: "apis/launcher/1/get-applications",
headers: DEFAULT_HEADERS
)
if response.status == 200
Applications.new(response.body)
else
false
end
end
# /apis/w3dhub/1/get-news
# Client sends an Authorization header bearer token which is received from logging in (Optional)
# Client requests news for a specific application/game e.g.: data={"category":"ia"}
# Response is a JSON hash with a "highlighted" and "news" keys; the "news" on seems to be the desired one
def self.news(category)
end
# Downloading games
# /apis/launcher/1/get-package-details
# client requests package details: data={"packages":[{"category":"games","name":"apb.ico","subcategory":"apb","version":""}]}
def self.package_details()
end
# /apis/launcher/1/get-package
# client requests package: data={"category":"games","name":"ECW_Asteroids.zip","subcategory":"ecw","version":"1.0.0.0"}
#
# server responds with download bytes
def self.package(category, name, subcategory, version, &block)
end
#! === Server List API === !#
SERVER_LIST_ENDPOINT = "https://gsh.w3dhub.com"
# Method: GET
# FORMAT: JSON
# /listings/getAll/v2?statusLevel=#{0-2}
# statusLevel = 0 returns:
# id, game, address, port, and region
# statusLevel = 1 returns: (This is the default for the Launcher)
# id, game, address, port, region, and status:
# name, map, maxplayers, numplayers, started (DateTime), and remaining (RenTime)
# statusLevel = 2 returns:
# id, game, address, port, region, status:
# name, map, maxplayers, numplayers, started (DateTime), and remaining (RenTime)
# ...teams[]:
# id, name, score, kills, deaths
# ...players[]:
# nick, team (index of teams array), score, kills, deaths
def self.server_list(level = 1)
end
# /listings/getStatus/v2/:id?statusLevel=#{0-2}
# statusLevel = 0 returns:
# Empty/Blank response, assume 500 or 400 error
# statusLevel = 1 returns:
# name, map, maxplayers, numplayers, started (DateTime), remaining (RenTime)
# statusLevel = 2 returns:
# name, map, maxplayers, numplayers, started (DateTime), remaining (RenTime)
# ...teams[]:
# id, name, score, kills, deaths
# ...players[]:
# nick, team (index of teams array), score, kills, deaths
def self.server_details(id, level)
end
# /listings/push/v2/negotiate?negotiateVersion=1
##? /listings/push/v2/?id=#{websocket token?}
## Websocket server list listener
def self.server_list_push(id)
end
end
end

64
lib/api/applications.rb Normal file
View File

@@ -0,0 +1,64 @@
class W3DHub
class Api
class Applications
def initialize(response)
@data = JSON.parse(response, symbolize_names: true)
games = @data[:applications].select { |a| a[:category] == "games" }
@games = []
games.each { |hash| @games << Game.new(hash) }
end
def games
@games
end
class Game
attr_reader :id, :name, :type, :category, :studio_id, :channels, :web_links, :color
def initialize(hash)
@data = hash
@id = @data[:id]
@name = @data[:name]
@type = @data[:type]
@category = @data[:category]
@studio_id = @data[:"studio-id"]
# TODO: Do processing
@channels = @data[:channels]
@web_links = @data[:"web-links"]
@extended_data = @data[:"extended-data"]
color = @data[:"extended-data"].find { |h| h[:name] == "colour" }[:value].sub("#", "")
@color = "ff#{color}".to_i(16)
end
class Channel
def initialize(hash)
@data = hash
@id = @data[:id]
@name = @data[:name]
@user_level = @data[:"user-level"]
@current_version = @data[:"current-version"]
end
end
class WebLink
attr_reader :name, :uri
def initialize(hash)
@data = hash
@name = hash[:name]
@uri = hash[:uri]
end
end
end
end
end
end

17
lib/api/service_status.rb Normal file
View File

@@ -0,0 +1,17 @@
class W3DHub
class Api
class ServiceStatus
def initialize(response)
@data = JSON.parse(response, symbolize_names: true)
end
def authentication?
@data[:services][:authentication]
end
def package_download?
@data[:services][:packageDownload]
end
end
end
end

View File

@@ -6,6 +6,13 @@ class W3DHub
@fraction = 0.0
@w3dhub_logo = get_image("#{GAME_ROOT_PATH}/media/icons/w3dhub.png")
@tasks = {
refresh_user_token: { started: false, complete: false },
service_status: { started: false, complete: false },
applications: { started: false, complete: false }
}
@task_index = 0
stack(width: 1.0, height: 1.0, border_thickness: 1, border_color: 0xff_aaaaaa) do
stack(width: 1.0, height: 0.925) do
@@ -14,7 +21,7 @@ class W3DHub
@progressbar = progress height: 0.025, width: 1.0, fraction_background: 0xff_00acff, border_thickness: 0
flow(width: 1.0, height: 0.05, padding_left: 16, padding_right: 16, padding_bottom: 8, padding_top: 8) do
caption "Checking for updates...", width: 0.5
@status_label = caption "Starting #{NAME}...", width: 0.5
inscription "W3D Hub Launcher 0.14.0.0", width: 0.5, text_align: :right
end
end
@@ -29,11 +36,70 @@ class W3DHub
def update
super
@fraction += 1.0 * window.dt
# @fraction += 1.0 * window.dt
@fraction = 1.0 / (@tasks.size / @task_index.to_f)
@progressbar.value = @fraction
push_state(States::Interface) if @progressbar.value >= 1.0
if @progressbar.value >= 1.0 && @task_index == @tasks.size
push_state(
States::Interface,
refresh_token: @refresh_token,
service_status: @service_status,
applications: @applications
)
end
send(:"#{@tasks.keys[@task_index]}") if @tasks.dig(@tasks.keys[@task_index], :complete) == false
@task_index += 1 if @tasks.dig(@tasks.keys[@task_index], :complete)
end
def refresh_user_token
@tasks[:refresh_user_token][:started] = true
@tasks[:refresh_user_token][:complete] = true
@refresh_token = nil
end
def service_status
@tasks[:service_status][:started] = true
Thread.new do
@service_status = Api.service_status
if service_status
if !service_status.authentication? || !service_status.package_download?
# FIXME: MAIN THREAD!
@status_label.value = "Authentication is #{service_status.authentication? ? 'Okay' : 'Down'}. Package Download is #{service_status.package_download? ? 'Okay' : 'Down'}."
end
@tasks[:service_status][:complete] = true
else
# FIXME: MAIN THREAD!
@status_label.value = "W3D Hub Service is down."
end
end
end
def applications
@status_label.value = "Checking for updates..."
warn "ALREADY STARTED APPLICATIONS!!!" if @tasks[:applications][:started]
return if @tasks[:applications][:started]
@tasks[:applications][:started] = true
Thread.new do
@applications = Api.applications
if applications
pp applications.games.first
@tasks[:applications][:complete] = true
end
end
end
end
end

View File

@@ -2,10 +2,15 @@ class W3DHub
class States
class Interface < CyberarmEngine::GuiState
attr_reader :main_thread_queue
attr_accessor :refresh_token, :service_status, :applications
def setup
window.show_cursor = true
@refresh_token = @options[:refresh_token]
@service_status = @options[:service_status]
@applications = @options[:applications]
@page = nil
@pages = {}

4
lib/version.rb Normal file
View File

@@ -0,0 +1,4 @@
class W3DHub
NAME = "W3D Hub Launcher"
VERSION = "0.1.0"
end

View File

@@ -8,10 +8,15 @@ GAME_ROOT_PATH = File.expand_path(".", __dir__)
EMPTY_IMAGE = Gosu::Image.from_blob(1, 1)
BLACK_IMAGE = Gosu::Image.from_blob(1, 1, "\x00\x00\x00\xff")
require_relative "lib/version"
require_relative "lib/window"
require_relative "lib/states/boot"
require_relative "lib/states/interface"
require_relative "lib/api"
require_relative "lib/api/service_status"
require_relative "lib/api/applications"
require_relative "lib/game"
require_relative "lib/games/renegade"
require_relative "lib/games/expansive_civilian_warfare"