mirror of
https://github.com/cyberarm/w3d_hub_linux_launcher.git
synced 2026-03-21 19:56:14 +00:00
Compare commits
2 Commits
f98d8c3394
...
f651143937
| Author | SHA1 | Date | |
|---|---|---|---|
| f651143937 | |||
| 1425225eef |
@@ -43,7 +43,7 @@ GEM
|
|||||||
fiber-storage (1.0.1)
|
fiber-storage (1.0.1)
|
||||||
fiddle (1.1.8)
|
fiddle (1.1.8)
|
||||||
gosu (1.4.6)
|
gosu (1.4.6)
|
||||||
io-endpoint (0.17.1)
|
io-endpoint (0.17.2)
|
||||||
io-event (1.14.2)
|
io-event (1.14.2)
|
||||||
io-stream (0.11.1)
|
io-stream (0.11.1)
|
||||||
ircparser (1.0.0)
|
ircparser (1.0.0)
|
||||||
@@ -97,4 +97,4 @@ DEPENDENCIES
|
|||||||
win32-security
|
win32-security
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.6.8
|
4.0.3
|
||||||
|
|||||||
287
lib/api.rb
287
lib/api.rb
@@ -16,32 +16,7 @@ class W3DHub
|
|||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
def self.on_thread(method, *args, &callback)
|
def self.on_thread(method, *args, &callback)
|
||||||
raise "Renew."
|
Api.send(method, *args, &callback)
|
||||||
BackgroundWorker.foreground_job(-> { Api.send(method, *args) }, callback)
|
|
||||||
end
|
|
||||||
|
|
||||||
class Response
|
|
||||||
def initialize(error: nil, status: -1, body: "")
|
|
||||||
@status = status
|
|
||||||
@body = body
|
|
||||||
@error = error
|
|
||||||
end
|
|
||||||
|
|
||||||
def success?
|
|
||||||
@status == 200
|
|
||||||
end
|
|
||||||
|
|
||||||
def status
|
|
||||||
@status
|
|
||||||
end
|
|
||||||
|
|
||||||
def body
|
|
||||||
@body
|
|
||||||
end
|
|
||||||
|
|
||||||
def error
|
|
||||||
@error
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#! === W3D Hub API === !#
|
#! === W3D Hub API === !#
|
||||||
@@ -50,7 +25,9 @@ class W3DHub
|
|||||||
|
|
||||||
HTTP_CLIENTS = {}
|
HTTP_CLIENTS = {}
|
||||||
|
|
||||||
def self.async_http(method, path, headers = DEFAULT_HEADERS, body = nil, backend = :w3dhub)
|
def self.async_http(method, path, headers = DEFAULT_HEADERS, body = nil, backend = :w3dhub, &callback)
|
||||||
|
raise "NO CALLBACK DEFINED!" unless callback
|
||||||
|
|
||||||
case backend
|
case backend
|
||||||
when :w3dhub
|
when :w3dhub
|
||||||
endpoint = W3DHUB_API_ENDPOINT
|
endpoint = W3DHUB_API_ENDPOINT
|
||||||
@@ -79,24 +56,7 @@ class W3DHub
|
|||||||
headers << ["authorization", "Bearer #{Store.account.access_token}"]
|
headers << ["authorization", "Bearer #{Store.account.access_token}"]
|
||||||
end
|
end
|
||||||
|
|
||||||
Sync do
|
Store.network_manager.request(method, url, headers, body, nil, &callback)
|
||||||
begin
|
|
||||||
response = provision_http_client(endpoint).send(method, path, headers, body)
|
|
||||||
|
|
||||||
Response.new(status: response.status, body: response.read)
|
|
||||||
rescue Async::TimeoutError => e
|
|
||||||
logger.error(LOG_TAG) { "Connection to \"#{url}\" timed out after: #{API_TIMEOUT} seconds" }
|
|
||||||
|
|
||||||
Response.new(error: e)
|
|
||||||
rescue StandardError => e
|
|
||||||
logger.error(LOG_TAG) { "Connection to \"#{url}\" errored:" }
|
|
||||||
logger.error(LOG_TAG) { e }
|
|
||||||
|
|
||||||
Response.new(error: e)
|
|
||||||
ensure
|
|
||||||
response&.close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.provision_http_client(hostname)
|
def self.provision_http_client(hostname)
|
||||||
@@ -114,17 +74,17 @@ class W3DHub
|
|||||||
HTTP_CLIENTS[Thread.current][hostname.downcase] = Async::HTTP::Client.new(endpoint)
|
HTTP_CLIENTS[Thread.current][hostname.downcase] = Async::HTTP::Client.new(endpoint)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.post(path, headers = DEFAULT_HEADERS, body = nil, backend = :w3dhub)
|
def self.post(path, headers = DEFAULT_HEADERS, body = nil, backend = :w3dhub, &callback)
|
||||||
async_http(:post, path, headers, body, backend)
|
async_http(:post, path, headers, body, backend, &callback)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get(path, headers = DEFAULT_HEADERS, body = nil, backend = :w3dhub)
|
def self.get(path, headers = DEFAULT_HEADERS, body = nil, backend = :w3dhub, &callback)
|
||||||
async_http(:get, path, headers, body, backend)
|
async_http(:get, path, headers, body, backend, &callback)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Api.get but handles any URL instead of known hosts
|
# Api.get but handles any URL instead of known hosts
|
||||||
def self.fetch(path, headers = DEFAULT_HEADERS, body = nil, backend = nil)
|
def self.fetch(path, headers = DEFAULT_HEADERS, body = nil, backend = nil, &callback)
|
||||||
async_http(:get, path, headers, body, backend)
|
async_http(:get, path, headers, body, backend, &callback)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Method: POST
|
# Method: POST
|
||||||
@@ -142,90 +102,111 @@ class W3DHub
|
|||||||
#
|
#
|
||||||
# On a failed login the service responds with:
|
# On a failed login the service responds with:
|
||||||
# {"error":"login-failed"}
|
# {"error":"login-failed"}
|
||||||
def self.refresh_user_login(refresh_token, backend = :w3dhub)
|
def self.refresh_user_login(refresh_token, backend = :w3dhub, &callback)
|
||||||
body = URI.encode_www_form("data": JSON.dump({refreshToken: refresh_token}))
|
handler = lambda do |result|
|
||||||
response = post("/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body, backend)
|
if result.okay?
|
||||||
|
user_data = JSON.parse(result.data, symbolize_names: true)
|
||||||
|
|
||||||
if response.status == 200
|
if user_data[:error]
|
||||||
user_data = JSON.parse(response.body, symbolize_names: true)
|
callback.call(false)
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
return false if user_data[:error]
|
user_details_data = user_details(user_data[:userid]) || {}
|
||||||
|
|
||||||
user_details_data = user_details(user_data[:userid]) || {}
|
callback.call(Account.new(user_data, user_details_data))
|
||||||
|
else
|
||||||
|
logger.error(LOG_TAG) { "Failed to fetch refresh user login:" }
|
||||||
|
logger.error(LOG_TAG) { result.error }
|
||||||
|
|
||||||
Account.new(user_data, user_details_data)
|
callback.call(false)
|
||||||
else
|
end
|
||||||
logger.error(LOG_TAG) { "Failed to fetch refresh user login:" }
|
|
||||||
logger.error(LOG_TAG) { response }
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
body = URI.encode_www_form("data": JSON.dump({ refreshToken: refresh_token }))
|
||||||
|
post("/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
# See #user_refresh_token
|
# See #user_refresh_token
|
||||||
def self.user_login(username, password, backend = :w3dhub)
|
def self.user_login(username, password, backend = :w3dhub, &callback)
|
||||||
body = URI.encode_www_form("data": JSON.dump({username: username, password: password}))
|
handler = lambda do |result|
|
||||||
response = post("/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body, backend)
|
if result.okay?
|
||||||
|
user_data = JSON.parse(result.data, symbolize_names: true)
|
||||||
|
|
||||||
if response.status == 200
|
if user_data[:error]
|
||||||
user_data = JSON.parse(response.body, symbolize_names: true)
|
callback.call(false)
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
return false if user_data[:error]
|
user_details_data = user_details(user_data[:userid]) || {}
|
||||||
|
|
||||||
user_details_data = user_details(user_data[:userid]) || {}
|
callback.call(Account.new(user_data, user_details_data))
|
||||||
|
else
|
||||||
|
logger.error(LOG_TAG) { "Failed to fetch user login:" }
|
||||||
|
logger.error(LOG_TAG) { result.error }
|
||||||
|
|
||||||
Account.new(user_data, user_details_data)
|
callback.call(false)
|
||||||
else
|
end
|
||||||
logger.error(LOG_TAG) { "Failed to fetch user login:" }
|
|
||||||
logger.error(LOG_TAG) { response }
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
body = URI.encode_www_form("data": JSON.dump({ username: username, password: password }))
|
||||||
|
post("/apis/launcher/1/user-login", FORM_ENCODED_HEADERS, body, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
# /apis/w3dhub/1/get-user-details
|
# /apis/w3dhub/1/get-user-details
|
||||||
#
|
#
|
||||||
# Response: avatar-uri (Image download uri), id, username
|
# Response: avatar-uri (Image download uri), id, username
|
||||||
def self.user_details(id, backend = :w3dhub)
|
def self.user_details(id, backend = :w3dhub, &callback)
|
||||||
body = URI.encode_www_form("data": JSON.dump({ id: id }))
|
handler = lambda do |result|
|
||||||
user_details = post("/apis/w3dhub/1/get-user-details", FORM_ENCODED_HEADERS, body, backend)
|
if result.okay?
|
||||||
|
callback.call(JSON.parse(result.data, symbolize_names: true))
|
||||||
|
else
|
||||||
|
logger.error(LOG_TAG) { "Failed to fetch user details:" }
|
||||||
|
logger.error(LOG_TAG) { result.error }
|
||||||
|
|
||||||
if user_details.status == 200
|
callback.call(false)
|
||||||
JSON.parse(user_details.body, symbolize_names: true)
|
end
|
||||||
else
|
|
||||||
logger.error(LOG_TAG) { "Failed to fetch user details:" }
|
|
||||||
logger.error(LOG_TAG) { user_details }
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
body = URI.encode_www_form("data": JSON.dump({ id: id }))
|
||||||
|
post("/apis/w3dhub/1/get-user-details", FORM_ENCODED_HEADERS, body, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
# /apis/w3dhub/1/get-service-status
|
# /apis/w3dhub/1/get-service-status
|
||||||
# Service response:
|
# Service response:
|
||||||
# {"services":{"authentication":true,"packageDownload":true}}
|
# {"services":{"authentication":true,"packageDownload":true}}
|
||||||
def self.service_status(backend = :w3dhub)
|
def self.service_status(backend = :w3dhub, &callback)
|
||||||
response = post("/apis/w3dhub/1/get-service-status", DEFAULT_HEADERS, nil, backend)
|
handler = lambda do |result|
|
||||||
|
if result.okay?
|
||||||
|
callback.call(ServiceStatus.new(result.data))
|
||||||
|
else
|
||||||
|
logger.error(LOG_TAG) { "Failed to fetch service status:" }
|
||||||
|
logger.error(LOG_TAG) { result.error }
|
||||||
|
|
||||||
if response.status == 200
|
callback.call(false)
|
||||||
ServiceStatus.new(response.body)
|
end
|
||||||
else
|
|
||||||
logger.error(LOG_TAG) { "Failed to fetch service status:" }
|
|
||||||
logger.error(LOG_TAG) { response }
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
post("/apis/w3dhub/1/get-service-status", DEFAULT_HEADERS, nil, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
# /apis/launcher/1/get-applications
|
# /apis/launcher/1/get-applications
|
||||||
# Client sends an Authorization header bearer token which is received from logging in (Optional)
|
# Client sends an Authorization header bearer token which is received from logging in (Optional)
|
||||||
# Launcher sends an empty data request: data={}
|
# Launcher sends an empty data request: data={}
|
||||||
# Response is a list of applications/games
|
# Response is a list of applications/games
|
||||||
def self.applications(backend = :w3dhub)
|
def self.applications(backend = :w3dhub, &callback)
|
||||||
response = post("/apis/launcher/1/get-applications", DEFAULT_HEADERS, nil, backend)
|
handler = lambda do |result|
|
||||||
|
if result.okay?
|
||||||
|
callback.call(Applications.new(result.data, backend))
|
||||||
|
else
|
||||||
|
logger.error(LOG_TAG) { "Failed to fetch applications list:" }
|
||||||
|
logger.error(LOG_TAG) { result.error }
|
||||||
|
|
||||||
if response.status == 200
|
callback.call(false)
|
||||||
Applications.new(response.body, backend)
|
end
|
||||||
else
|
|
||||||
logger.error(LOG_TAG) { "Failed to fetch applications list:" }
|
|
||||||
logger.error(LOG_TAG) { response }
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
post("/apis/launcher/1/get-applications", DEFAULT_HEADERS, nil, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Populate applications list from primary and alternate backends
|
# Populate applications list from primary and alternate backends
|
||||||
@@ -301,61 +282,70 @@ class W3DHub
|
|||||||
# Client sends an Authorization header bearer token which is received from logging in (Optional)
|
# 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"} ("launcher-home" retrieves the weekly hub updates)
|
# Client requests news for a specific application/game e.g.: data={"category":"ia"} ("launcher-home" retrieves the weekly hub updates)
|
||||||
# Response is a JSON hash with a "highlighted" and "news" keys; the "news" one seems to be the desired one
|
# Response is a JSON hash with a "highlighted" and "news" keys; the "news" one seems to be the desired one
|
||||||
def self.news(category, backend = :w3dhub)
|
def self.news(category, backend = :w3dhub, &callback)
|
||||||
body = URI.encode_www_form("data": JSON.dump({category: category}))
|
handler = lambda do |result|
|
||||||
response = post("/apis/w3dhub/1/get-news", FORM_ENCODED_HEADERS, body, backend)
|
if result.okay?
|
||||||
|
callback.call(News.new(result.data))
|
||||||
|
else
|
||||||
|
logger.error(LOG_TAG) { "Failed to fetch news for:" }
|
||||||
|
logger.error(LOG_TAG) { category }
|
||||||
|
logger.error(LOG_TAG) { result.error }
|
||||||
|
|
||||||
if response.status == 200
|
callback.call(false)
|
||||||
News.new(response.body)
|
end
|
||||||
else
|
|
||||||
logger.error(LOG_TAG) { "Failed to fetch news for:" }
|
|
||||||
logger.error(LOG_TAG) { category }
|
|
||||||
logger.error(LOG_TAG) { response }
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
body = URI.encode_www_form("data": JSON.dump({ category: category }))
|
||||||
|
post("/apis/w3dhub/1/get-news", FORM_ENCODED_HEADERS, body, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Downloading games
|
# Downloading games
|
||||||
|
|
||||||
# /apis/launcher/1/get-package-details
|
# /apis/launcher/1/get-package-details
|
||||||
# client requests package details: data={"packages":[{"category":"games","name":"apb.ico","subcategory":"apb","version":""}]}
|
# client requests package details: data={"packages":[{"category":"games","name":"apb.ico","subcategory":"apb","version":""}]}
|
||||||
def self.package_details(packages, backend = :w3dhub)
|
def self.package_details(packages, backend = :w3dhub, &callback)
|
||||||
body = URI.encode_www_form("data": JSON.dump({ packages: packages }))
|
handler = lambda do |result|
|
||||||
response = post("/apis/launcher/1/get-package-details", FORM_ENCODED_HEADERS, body, backend)
|
if result.okay?
|
||||||
|
hash = JSON.parse(result.data, symbolize_names: true)
|
||||||
|
|
||||||
if response.status == 200
|
callback.call(hash[:packages].map { |pkg| Package.new(pkg) })
|
||||||
hash = JSON.parse(response.body, symbolize_names: true)
|
else
|
||||||
|
logger.error(LOG_TAG) { "Failed to fetch package details for:" }
|
||||||
|
logger.error(LOG_TAG) { packages }
|
||||||
|
logger.error(LOG_TAG) { result.error }
|
||||||
|
|
||||||
hash[:packages].map { |pkg| Package.new(pkg) }
|
callback.call(false)
|
||||||
else
|
end
|
||||||
logger.error(LOG_TAG) { "Failed to fetch package details for:" }
|
|
||||||
logger.error(LOG_TAG) { packages }
|
|
||||||
logger.error(LOG_TAG) { response }
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
body = URI.encode_www_form("data": JSON.dump({ packages: packages }))
|
||||||
|
post("/apis/launcher/1/get-package-details", FORM_ENCODED_HEADERS, body, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
# /apis/launcher/1/get-package
|
# /apis/launcher/1/get-package
|
||||||
# client requests package: data={"category":"games","name":"ECW_Asteroids.zip","subcategory":"ecw","version":"1.0.0.0"}
|
# client requests package: data={"category":"games","name":"ECW_Asteroids.zip","subcategory":"ecw","version":"1.0.0.0"}
|
||||||
#
|
#
|
||||||
# server responds with download bytes, probably supports chunked download and resume
|
# server responds with download bytes, probably supports chunked download and resume
|
||||||
def self.package(package, &block)
|
# FIXME: REFACTOR Cache.fetch_package to use HttpClient
|
||||||
Cache.fetch_package(package, block)
|
def self.package(package, &callback)
|
||||||
|
Cache.fetch_package(package, callback)
|
||||||
end
|
end
|
||||||
|
|
||||||
# /apis/w3dhub/1/get-events
|
# /apis/w3dhub/1/get-events
|
||||||
#
|
#
|
||||||
# clients requests events: data={"serverPath":"apb"}
|
# clients requests events: data={"serverPath":"apb"}
|
||||||
def self.events(app_id, backend = :w3dhub)
|
def self.events(app_id, backend = :w3dhub, &callback)
|
||||||
body = URI.encode_www_form("data": JSON.dump({ serverPath: app_id }))
|
handler = lambda do |result|
|
||||||
response = post("/apis/w3dhub/1/get-server-events", FORM_ENCODED_HEADERS, body, backend)
|
if result.okay?
|
||||||
|
array = JSON.parse(response.body, symbolize_names: true)
|
||||||
if response.status == 200
|
callback.call(array.map { |e| Event.new(e) })
|
||||||
array = JSON.parse(response.body, symbolize_names: true)
|
else
|
||||||
array.map { |e| Event.new(e) }
|
callback.call(false)
|
||||||
else
|
end
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
body = URI.encode_www_form("data": JSON.dump({ serverPath: app_id }))
|
||||||
|
post("/apis/w3dhub/1/get-server-events", FORM_ENCODED_HEADERS, body, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
#! === Server List API === !#
|
#! === Server List API === !#
|
||||||
@@ -381,15 +371,17 @@ class W3DHub
|
|||||||
# id, name, score, kills, deaths
|
# id, name, score, kills, deaths
|
||||||
# ...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, backend = :gsh)
|
def self.server_list(level = 1, backend = :gsh, &callback)
|
||||||
response = get("/listings/getAll/v2?statusLevel=#{level}", DEFAULT_HEADERS, nil, backend)
|
handler = lambda do |result|
|
||||||
|
if result.okay?
|
||||||
if response.status == 200
|
data = JSON.parse(result.data, symbolize_names: true)
|
||||||
data = JSON.parse(response.body, symbolize_names: true)
|
callback.call(data.map { |hash| ServerListServer.new(hash) })
|
||||||
return data.map { |hash| ServerListServer.new(hash) }
|
else
|
||||||
|
callback.call(false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
false
|
get("/listings/getAll/v2?statusLevel=#{level}", DEFAULT_HEADERS, nil, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
# /listings/getStatus/v2/:id?statusLevel=#{0-2}
|
# /listings/getStatus/v2/:id?statusLevel=#{0-2}
|
||||||
@@ -403,23 +395,24 @@ class W3DHub
|
|||||||
# id, name, score, kills, deaths
|
# id, name, score, kills, deaths
|
||||||
# ...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, backend = :gsh)
|
def self.server_details(id, level, backend = :gsh, &callback)
|
||||||
return false unless id && level
|
return false unless id && level
|
||||||
|
|
||||||
response = get("/listings/getStatus/v2/#{id}?statusLevel=#{level}", DEFAULT_HEADERS, nil, backend)
|
handler = lambda do |result|
|
||||||
|
if result.okay?
|
||||||
if response.status == 200
|
callback.call(JSON.parse(response.body, symbolize_names: true))
|
||||||
hash = JSON.parse(response.body, symbolize_names: true)
|
else
|
||||||
return hash
|
callback.call(false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
false
|
get("/listings/getStatus/v2/#{id}?statusLevel=#{level}", DEFAULT_HEADERS, nil, backend, &handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
# /listings/push/v2/negotiate?negotiateVersion=1
|
# /listings/push/v2/negotiate?negotiateVersion=1
|
||||||
##? /listings/push/v2/?id=#{websocket token?}
|
##? /listings/push/v2/?id=#{websocket token?}
|
||||||
## Websocket server list listener
|
## Websocket server list listener
|
||||||
def self.server_list_push(id)
|
def self.server_list_push(id, &callback)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class W3DHub
|
|||||||
@invocation_id = 0
|
@invocation_id = 0
|
||||||
|
|
||||||
logger.info(LOG_TAG) { "Starting emulated SignalR Server List Updater..." }
|
logger.info(LOG_TAG) { "Starting emulated SignalR Server List Updater..." }
|
||||||
run
|
# run
|
||||||
end
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
@@ -32,7 +32,8 @@ class W3DHub
|
|||||||
begin
|
begin
|
||||||
@auto_reconnect = true
|
@auto_reconnect = true
|
||||||
|
|
||||||
while W3DHub::BackgroundWorker.alive?
|
# FIXME
|
||||||
|
while true #W3DHub::BackgroundWorker.alive?
|
||||||
connect if @auto_reconnect
|
connect if @auto_reconnect
|
||||||
sleep @reconnection_delay
|
sleep @reconnection_delay
|
||||||
end
|
end
|
||||||
@@ -54,19 +55,31 @@ class W3DHub
|
|||||||
@auto_reconnect = false
|
@auto_reconnect = false
|
||||||
|
|
||||||
logger.debug(LOG_TAG) { "Requesting connection token..." }
|
logger.debug(LOG_TAG) { "Requesting connection token..." }
|
||||||
response = Api.post("/listings/push/v2/negotiate?negotiateVersion=1", Api::DEFAULT_HEADERS, "", :gsh)
|
|
||||||
|
|
||||||
if response.status != 200
|
result = nil
|
||||||
|
Api.post("/listings/push/v2/negotiate?negotiateVersion=1", Api::DEFAULT_HEADERS, "", :gsh) do |callback_result|
|
||||||
|
result = callback_result
|
||||||
|
end
|
||||||
|
|
||||||
|
# FIXME: we've introduced ourselves to callback hell, yay!
|
||||||
|
while result.nil?
|
||||||
|
sleep 0.1
|
||||||
|
end
|
||||||
|
|
||||||
|
if result.error?
|
||||||
@auto_reconnect = true
|
@auto_reconnect = true
|
||||||
@reconnection_delay = @reconnection_delay * 2
|
@reconnection_delay *= 2
|
||||||
@reconnection_delay = 60 if @reconnection_delay > 60
|
@reconnection_delay = 60 if @reconnection_delay > 60
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@reconnection_delay = 1
|
@reconnection_delay = 1
|
||||||
|
|
||||||
data = JSON.parse(response.body, symbolize_names: true)
|
connect_websocket(JSON.parse(result.data, symbolize_names: true))
|
||||||
|
end
|
||||||
|
|
||||||
|
def connect_websocket(data)
|
||||||
@invocation_id = 0 if @invocation_id > 9095
|
@invocation_id = 0 if @invocation_id > 9095
|
||||||
id = data[:connectionToken]
|
id = data[:connectionToken]
|
||||||
endpoint = "#{Api::SERVER_LIST_ENDPOINT}/listings/push/v2?id=#{id}"
|
endpoint = "#{Api::SERVER_LIST_ENDPOINT}/listings/push/v2?id=#{id}"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ class W3DHub
|
|||||||
Request = Struct.new(:context, :callback)
|
Request = Struct.new(:context, :callback)
|
||||||
Context = Data.define(
|
Context = Data.define(
|
||||||
:request_id,
|
:request_id,
|
||||||
|
:method,
|
||||||
:url,
|
:url,
|
||||||
:headers,
|
:headers,
|
||||||
:body,
|
:body,
|
||||||
@@ -12,52 +13,42 @@ class W3DHub
|
|||||||
)
|
)
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@requests = {}
|
@requests = []
|
||||||
|
@running = true
|
||||||
|
|
||||||
@ractor = Ractor.new do
|
Thread.new do
|
||||||
raise "Something has gone quite wrong!" if Ractor.main?
|
http_client = HttpClient.new
|
||||||
|
|
||||||
queue = []
|
Sync do
|
||||||
api_client = ApiClient.new
|
while @running
|
||||||
|
request = @requests.shift
|
||||||
|
|
||||||
# Ractor has no concept of non-blocking send/receive... :cry:
|
# goto sleep for an second if there is no work to be doing
|
||||||
Thread.new do
|
unless request
|
||||||
while (context = Ractor.receive) # blocking
|
sleep 1
|
||||||
# we cannot (easily) ensure we always are receive expected data
|
|
||||||
next unless context.is_a?(Context)
|
|
||||||
|
|
||||||
queue << context
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Async do
|
|
||||||
loop do
|
|
||||||
context = queue.shift
|
|
||||||
|
|
||||||
# goto sleep for an instant if there is no work to be doing
|
|
||||||
unless context
|
|
||||||
sleep 0.1
|
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
Sync do
|
Async do |task|
|
||||||
result = api_client.handle(context)
|
assigned_request = request
|
||||||
|
result = http_client.handle(task, assigned_request)
|
||||||
|
|
||||||
Ractor.yield(NetworkEvent.new(context, result))
|
pp [assigned_request, result]
|
||||||
|
|
||||||
|
Store.main_thread_queue << -> { assigned_request.callback.call(result) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
monitor
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_request(url, headers, body, bearer_token, &block)
|
def request(method, url, headers, body, bearer_token, &block)
|
||||||
request_id = SecureRandom.hex
|
request_id = SecureRandom.hex
|
||||||
|
|
||||||
@requests << Request.new(
|
request = Request.new(
|
||||||
Context.new(
|
Context.new(
|
||||||
request_id,
|
request_id,
|
||||||
|
method,
|
||||||
url,
|
url,
|
||||||
headers,
|
headers,
|
||||||
body,
|
body,
|
||||||
@@ -66,31 +57,9 @@ class W3DHub
|
|||||||
block
|
block
|
||||||
)
|
)
|
||||||
|
|
||||||
@ractor.send(context)
|
@requests << request
|
||||||
|
|
||||||
request_id
|
request_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def monitor
|
|
||||||
raise "Something has gone quite wrong!!!" unless Ractor.main?
|
|
||||||
|
|
||||||
# Thread that spends its days sleeping **yawn**
|
|
||||||
Thread.new do
|
|
||||||
while (event = @ractor.take)
|
|
||||||
pp event
|
|
||||||
|
|
||||||
next unless event.is_a?(NetworkEvent)
|
|
||||||
|
|
||||||
request = @request.find { |r| r.context.request_id == event.context.request_id }
|
|
||||||
|
|
||||||
next if request
|
|
||||||
|
|
||||||
@requests.delete(request)
|
|
||||||
result = event.result
|
|
||||||
|
|
||||||
Store.main_thread_queue << ->(result) { request.callback(result) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
class W3DHub
|
|
||||||
class NetworkManager
|
|
||||||
# Api reimplemented in a Ractor friendly manner
|
|
||||||
class ApiClient
|
|
||||||
def initialize
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
61
lib/network_manager/http_client.rb
Normal file
61
lib/network_manager/http_client.rb
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
class W3DHub
|
||||||
|
class NetworkManager
|
||||||
|
# non-blocking, http requests.
|
||||||
|
class HttpClient
|
||||||
|
def initialize
|
||||||
|
@http_clients = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle(task, request)
|
||||||
|
result = CyberarmEngine::Result.new
|
||||||
|
context = request.context
|
||||||
|
|
||||||
|
task.with_timeout(30) do
|
||||||
|
uri = URI(context.url)
|
||||||
|
|
||||||
|
pp uri
|
||||||
|
|
||||||
|
response = provision_http_client(uri.origin).send(
|
||||||
|
context.method,
|
||||||
|
uri.path,
|
||||||
|
context.headers,
|
||||||
|
context.body
|
||||||
|
)
|
||||||
|
|
||||||
|
pp response
|
||||||
|
|
||||||
|
if response.success?
|
||||||
|
result.data = response.body.read
|
||||||
|
else
|
||||||
|
result.error = response
|
||||||
|
end
|
||||||
|
rescue Async::TimeoutError => e
|
||||||
|
result.error = e
|
||||||
|
rescue StandardError => e
|
||||||
|
result.error = e
|
||||||
|
ensure
|
||||||
|
response&.close
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def provision_http_client(hostname)
|
||||||
|
return @http_clients[hostname.downcase] if @http_clients[hostname.downcase]
|
||||||
|
|
||||||
|
ssl_context = W3DHub.ca_bundle_path ? OpenSSL::SSL::SSLContext.new : nil
|
||||||
|
ssl_context&.set_params(
|
||||||
|
ca_file: W3DHub.ca_bundle_path,
|
||||||
|
verify_mode: OpenSSL::SSL::VERIFY_PEER
|
||||||
|
)
|
||||||
|
|
||||||
|
endpoint = Async::HTTP::Endpoint.parse(hostname, ssl_context: ssl_context)
|
||||||
|
@http_clients[hostname.downcase] = Async::HTTP::Client.new(endpoint)
|
||||||
|
end
|
||||||
|
|
||||||
|
def wrapped_error(error)
|
||||||
|
WrappedError.new(error.class, error.message.to_s, error.backtrace)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -175,7 +175,11 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
|
|
||||||
def service_status
|
def service_status
|
||||||
|
@status_label.value = "Checking service status..." #I18n.t(:"server_browser.fetching_server_list")
|
||||||
|
|
||||||
Api.on_thread(:service_status) do |service_status|
|
Api.on_thread(:service_status) do |service_status|
|
||||||
|
pp service_status
|
||||||
|
|
||||||
@service_status = service_status
|
@service_status = service_status
|
||||||
|
|
||||||
if @service_status
|
if @service_status
|
||||||
@@ -227,14 +231,14 @@ class W3DHub
|
|||||||
def applications
|
def applications
|
||||||
@status_label.value = I18n.t(:"boot.checking_for_updates")
|
@status_label.value = I18n.t(:"boot.checking_for_updates")
|
||||||
|
|
||||||
Api.on_thread(:_applications) do |applications|
|
# Api.on_thread(:_applications) do |applications|
|
||||||
|
Api.on_thread(:applications, :alt_w3dhub) do |applications|
|
||||||
if applications
|
if applications
|
||||||
Store.applications = applications
|
Store.applications = applications
|
||||||
Store.settings.save_application_cache(applications.data.to_json)
|
Store.settings.save_application_cache(applications.data.to_json)
|
||||||
@tasks[:applications][:complete] = true
|
@tasks[:applications][:complete] = true
|
||||||
else
|
else
|
||||||
# FIXME: Failed to retreive!
|
@status_label.value = "FAILED TO RETREIVE APPS LIST"
|
||||||
BackgroundWorker.foreground_job(-> {}, ->(_) { @status_label.value = "FAILED TO RETREIVE APPS LIST" })
|
|
||||||
|
|
||||||
@offline_mode = true
|
@offline_mode = true
|
||||||
Store.offline_mode = true
|
Store.offline_mode = true
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ require_relative "lib/hardware_survey"
|
|||||||
require_relative "lib/game_settings"
|
require_relative "lib/game_settings"
|
||||||
require_relative "lib/websocket_client"
|
require_relative "lib/websocket_client"
|
||||||
require_relative "lib/network_manager"
|
require_relative "lib/network_manager"
|
||||||
require_relative "lib/network_manager/api_client"
|
require_relative "lib/network_manager/http_client"
|
||||||
require_relative "lib/application_manager"
|
require_relative "lib/application_manager"
|
||||||
require_relative "lib/application_manager/manifest"
|
require_relative "lib/application_manager/manifest"
|
||||||
require_relative "lib/application_manager/status"
|
require_relative "lib/application_manager/status"
|
||||||
|
|||||||
Reference in New Issue
Block a user