mirror of
https://github.com/cyberarm/w3d_hub_linux_launcher.git
synced 2026-09-19 14:53:49 +00:00
Initial functioning work to get IPC working via UNIX sockets since ractors are still not a viable option :sad:
This commit is contained in:
@@ -7,5 +7,6 @@ module W3DHubLauncher
|
|||||||
DEFAULT_PACKAGE_CACHE_PATH = "#{CACHE_PATH}/packages".freeze
|
DEFAULT_PACKAGE_CACHE_PATH = "#{CACHE_PATH}/packages".freeze
|
||||||
DEFAULT_APPLICATIONS_PATH = "#{Dir.home}/.local/share/#{DIRECTORY_NAME}/applications".freeze
|
DEFAULT_APPLICATIONS_PATH = "#{Dir.home}/.local/share/#{DIRECTORY_NAME}/applications".freeze
|
||||||
|
|
||||||
|
IPC_PATH = "/tmp/w3dhub_linux_launcher.sock"
|
||||||
USER_AGENT = "#{NAME} v#{VERSION}".freeze
|
USER_AGENT = "#{NAME} v#{VERSION}".freeze
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ module W3DHubLauncher
|
|||||||
WHITE_IMAGE = Gosu.render(64, 64, retro: true) { Gosu.draw_rect(0, 0, 32, 32, Gosu::Color::WHITE) }
|
WHITE_IMAGE = Gosu.render(64, 64, retro: true) { Gosu.draw_rect(0, 0, 32, 32, Gosu::Color::WHITE) }
|
||||||
|
|
||||||
def safe_get_image(path, retro: false)
|
def safe_get_image(path, retro: false)
|
||||||
|
raise RuntimeError, "Images may only be loaded from the main thread!" unless Thread.current == Thread.main
|
||||||
|
|
||||||
return get_image(path, retro: retro) if File.exist?(path)
|
return get_image(path, retro: retro) if File.exist?(path)
|
||||||
|
|
||||||
path = "#{ROOT_PATH}/media/default.png"
|
path = "#{ROOT_PATH}/media/default.png"
|
||||||
@@ -21,5 +23,9 @@ module W3DHubLauncher
|
|||||||
circle.draw(0, 0, 1, 1, 1, 0xff_ffffff, :multiply)
|
circle.draw(0, 0, 1, 1, 1, 0xff_ffffff, :multiply)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def on_main_thread(block)
|
||||||
|
window.add_to_queue(block)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ module W3DHubLauncher
|
|||||||
|
|
||||||
Worker::Api.update_settings({}) do |result|
|
Worker::Api.update_settings({}) do |result|
|
||||||
if result.okay?
|
if result.okay?
|
||||||
page(Page::Boot::StartUp)
|
on_main_thread(proc { page(Page::Boot::StartUp) })
|
||||||
else
|
else
|
||||||
btn.enabled = true
|
btn.enabled = true
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ module W3DHubLauncher
|
|||||||
# game info container
|
# game info container
|
||||||
stack(width: 340, height: 1.0) do
|
stack(width: 340, height: 1.0) do
|
||||||
# logo
|
# logo
|
||||||
image safe_get_image("/run/media/cyberarm/Storage/W3DHub/Launcher/package-cache/games/apb/logo.png.package"), width: 1.0, max_height: 124
|
image safe_get_image("#{ROOT_PATH}/media/default.png"), width: 1.0, max_height: 124
|
||||||
|
|
||||||
# web links
|
# web links
|
||||||
stack(width: 1.0, fill: true, padding: 0, padding_top: LARGE_PADDING) do
|
stack(width: 1.0, fill: true, padding: 0, padding_top: LARGE_PADDING) do
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ module W3DHubLauncher
|
|||||||
super
|
super
|
||||||
|
|
||||||
# root container - background image
|
# root container - background image
|
||||||
stack(width: 1.0, height: 1.0, background_image: safe_get_image("/run/media/cyberarm/Storage/W3DHub/Launcher/package-cache/games/apb/background.png.package"), background_image_mode: :fill) do
|
stack(width: 1.0, height: 1.0, background_image: safe_get_image("#{ROOT_PATH}/media/background.png"), background_image_mode: :fill) do
|
||||||
# root container - background image tint
|
# root container - background image tint
|
||||||
flow(width: 1.0, height: 1.0, background: 0xaa_000000) do
|
flow(width: 1.0, height: 1.0, background: 0xaa_000000) do
|
||||||
# content container
|
# content container
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ module W3DHubLauncher
|
|||||||
super
|
super
|
||||||
|
|
||||||
# root container - background image
|
# root container - background image
|
||||||
stack(width: 1.0, height: 1.0, background_image: safe_get_image("/run/media/cyberarm/Storage/W3DHub/Launcher/package-cache/games/apb/background.png.package"), background_image_mode: :fill) do
|
stack(width: 1.0, height: 1.0, background_image: safe_get_image("#{ROOT_PATH}/media/background.png"), background_image_mode: :fill) do
|
||||||
# root container - background image tint
|
# root container - background image tint
|
||||||
stack(width: 1.0, height: 1.0, background: ALPHA_BLACK) do
|
stack(width: 1.0, height: 1.0, background: ALPHA_BLACK) do
|
||||||
# content container
|
# content container
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ module W3DHubLauncher
|
|||||||
self.show_cursor = true
|
self.show_cursor = true
|
||||||
self.caption = format("%s | v%s (%s)", NAME, VERSION, VERSION_NAME) # "Cyberarm's W3D Hub Linux Launcher | v2.0.0 alpha"
|
self.caption = format("%s | v%s (%s)", NAME, VERSION, VERSION_NAME) # "Cyberarm's W3D Hub Linux Launcher | v2.0.0 alpha"
|
||||||
|
|
||||||
|
@main_thread_queue = []
|
||||||
|
|
||||||
push_state(States::Boot)
|
push_state(States::Boot)
|
||||||
# push_state(States::Interface)
|
# push_state(States::Interface)
|
||||||
end
|
end
|
||||||
@@ -13,9 +15,19 @@ module W3DHubLauncher
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
while(block = @main_thread_queue.shift)
|
||||||
|
block.call
|
||||||
|
end
|
||||||
|
|
||||||
|
WORKER.service
|
||||||
|
|
||||||
super
|
super
|
||||||
|
|
||||||
sleep 0.001
|
sleep 0.001
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_to_queue(block)
|
||||||
|
@main_thread_queue << block
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,16 +3,28 @@ module W3DHubLauncher
|
|||||||
Response = Data.define(:status, :request_id, :data)
|
Response = Data.define(:status, :request_id, :data)
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
def connect
|
||||||
|
puts :connect
|
||||||
|
|
||||||
|
@socket = UNIXSocket.new(IPC_PATH)
|
||||||
|
end
|
||||||
|
|
||||||
|
def connected?
|
||||||
|
@socket && !@socket.closed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def listen
|
||||||
|
init_server
|
||||||
|
end
|
||||||
|
|
||||||
|
def init_server
|
||||||
@threads = []
|
@threads = []
|
||||||
@requests = []
|
@requests = []
|
||||||
|
|
||||||
@settings = # Settings.new
|
@settings = 0# Settings.new
|
||||||
|
|
||||||
# next available request_id to assign incoming requests
|
|
||||||
@request_id = 0
|
|
||||||
|
|
||||||
# listen for requests from frontend
|
|
||||||
listener = Thread.new { listen }
|
|
||||||
# connect to and monitor GSH web service
|
# connect to and monitor GSH web service
|
||||||
@threads << Thread.new { game_server_hub_websocket }
|
@threads << Thread.new { game_server_hub_websocket }
|
||||||
# connect to and monitor Backend web service
|
# connect to and monitor Backend web service
|
||||||
@@ -20,20 +32,26 @@ module W3DHubLauncher
|
|||||||
|
|
||||||
@w3dhub_api = W3DHubLauncher::W3DHubApi.new
|
@w3dhub_api = W3DHubLauncher::W3DHubApi.new
|
||||||
|
|
||||||
listener.join
|
Async do |task|
|
||||||
end
|
UNIXServer.open(IPC_PATH) do |server|
|
||||||
|
while(socket = server.accept)
|
||||||
|
task.async do
|
||||||
|
data = socket.gets
|
||||||
|
json = JSON.parse(data)
|
||||||
|
query = Request::Query.new(type: json["type"].to_sym, request_id: json["request_id"], data: json["data"])
|
||||||
|
|
||||||
def listen
|
pp [:server_incoming, data, query]
|
||||||
loop do
|
|
||||||
query = Ractor.receive
|
|
||||||
pp query
|
|
||||||
|
|
||||||
if respond_to?(query.type)
|
if respond_to?(query.type)
|
||||||
Async do
|
response = send(query.type, query)
|
||||||
send(query.type, query)
|
pp [:server_to_client, response]
|
||||||
|
payload = { status: response.status, request_id: response.request_id, data: response.data.data }.to_json
|
||||||
|
socket.puts(payload)
|
||||||
end
|
end
|
||||||
else
|
end
|
||||||
raise "UNKNOWN REQUEST: #{query}"
|
end
|
||||||
|
ensure # manually delete "socket"
|
||||||
|
File.delete(IPC_PATH)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -44,6 +62,45 @@ module W3DHubLauncher
|
|||||||
def backend_websocket
|
def backend_websocket
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Send request to server
|
||||||
|
def request(query)
|
||||||
|
pp [:client_request, query]
|
||||||
|
payload = { type: query.type, request_id: query.request_id, data: query.data }.to_json
|
||||||
|
|
||||||
|
if respond_to?(query.type)
|
||||||
|
@socket.puts(payload)
|
||||||
|
else
|
||||||
|
raise "UNKNOWN REQUEST: #{query}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def service
|
||||||
|
data = @socket.read_nonblock(1_048_576) # 1 MB
|
||||||
|
pp [:CLIENT, data]
|
||||||
|
json = JSON.parse(data)
|
||||||
|
response = Response.new(status: json["status"], request_id: json["request_id"], data: json["data"])
|
||||||
|
request = W3DHubLauncher::Worker::Request.requests.find { |r| r.request_id == response.request_id }
|
||||||
|
|
||||||
|
pp [json, response, request]
|
||||||
|
return unless request
|
||||||
|
|
||||||
|
CyberarmEngine::Window.instance&.add_to_queue(proc {
|
||||||
|
request.handle_event(
|
||||||
|
response.status,
|
||||||
|
CyberarmEngine::Result.new(data: response.data, error: response.status.negative? ? true : nil)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
rescue Errno::EWOULDBLOCK
|
||||||
|
end
|
||||||
|
|
||||||
|
def deliver_response(result, query)
|
||||||
|
response = Response.new(result.okay? ? Request::STATUS_COMPLETE : Request::STATUS_ERROR, query.request_id, result)
|
||||||
|
pp response
|
||||||
|
|
||||||
|
response
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# ------------ query / request handlers ------------
|
# ------------ query / request handlers ------------
|
||||||
#
|
#
|
||||||
@@ -54,11 +111,9 @@ module W3DHubLauncher
|
|||||||
end
|
end
|
||||||
|
|
||||||
def w3dhub_api_call(query)
|
def w3dhub_api_call(query)
|
||||||
result = @w3dhub_api.send(query.data[:call], *(query.data[:arguments] || []))
|
result = @w3dhub_api.send(query.data["call"], *(query.data["arguments"] || []))
|
||||||
pp result
|
|
||||||
response = Response.new(result.okay? ? Request::STATUS_COMPLETE : Request::STATUS_ERROR, query.request_id, result)
|
|
||||||
|
|
||||||
Ractor.main.send(response)
|
deliver_response(result, query)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_settings(query)
|
def update_settings(query)
|
||||||
@@ -67,9 +122,7 @@ module W3DHubLauncher
|
|||||||
FileUtils.mkdir_p(W3DHubLauncher::CONFIG_PATH) # FIXME: FAILABLE!
|
FileUtils.mkdir_p(W3DHubLauncher::CONFIG_PATH) # FIXME: FAILABLE!
|
||||||
File.write("#{W3DHubLauncher::CONFIG_PATH}/settings.json", query.data) # FIXME: FAILABLE!
|
File.write("#{W3DHubLauncher::CONFIG_PATH}/settings.json", query.data) # FIXME: FAILABLE!
|
||||||
result.data = query.data
|
result.data = query.data
|
||||||
response = Response.new(result.okay? ? Request::STATUS_COMPLETE : Request::STATUS_ERROR, query.request_id, result)
|
deliver_response(result, query)
|
||||||
|
|
||||||
Ractor.main.send(response)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def install_application(query)
|
def install_application(query)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Helper for launcher frontend to safely communicate with ractor (prevent deadlocks and concurrent access errors)
|
# Helper for launcher frontend to safely communicate with launcher backend
|
||||||
|
|
||||||
module W3DHubLauncher
|
module W3DHubLauncher
|
||||||
class Worker
|
class Worker
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ module W3DHubLauncher
|
|||||||
|
|
||||||
def enqueue(type, id, data)
|
def enqueue(type, id, data)
|
||||||
Request.requests << self
|
Request.requests << self
|
||||||
W3DHubLauncher::WORKER.send(Query.new(type, id, data))
|
W3DHubLauncher::WORKER.request(Query.new(type, id, data))
|
||||||
end
|
end
|
||||||
|
|
||||||
# event from Worker received
|
# event from Worker received
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ module W3DHubLauncher
|
|||||||
array << ["content-type", "application/x-www-form-urlencoded"] if form_encoded
|
array << ["content-type", "application/x-www-form-urlencoded"] if form_encoded
|
||||||
array << ["authorization", "Bearer #{@access_token}"] if @access_token
|
array << ["authorization", "Bearer #{@access_token}"] if @access_token
|
||||||
|
|
||||||
pp array
|
# pp array
|
||||||
|
|
||||||
array
|
array
|
||||||
end
|
end
|
||||||
@@ -36,6 +36,7 @@ module W3DHubLauncher
|
|||||||
if response.success?
|
if response.success?
|
||||||
result.data = response.read
|
result.data = response.read
|
||||||
else
|
else
|
||||||
|
pp response
|
||||||
result.error = true
|
result.error = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -99,9 +100,24 @@ module W3DHubLauncher
|
|||||||
|
|
||||||
def fetch_applications
|
def fetch_applications
|
||||||
result = CyberarmEngine::Result.new
|
result = CyberarmEngine::Result.new
|
||||||
primary_result = fetch("#{PRIMARY_W3DHUB_API_ENDPOINT}/apis/launcher/1/get-applications")
|
# If we're not signed in, then the primary backend will try to redirect us to the alternate backend. So skip it if we're not signed in.
|
||||||
|
primary_result = @access_token ? fetch("#{PRIMARY_W3DHUB_API_ENDPOINT}/apis/launcher/1/get-applications") : CyberarmEngine::Result.new(error: true)
|
||||||
alternate_result = fetch("#{ALTERNATIVE_W3DHUB_API_ENDPOINT}/apis/launcher/1/get-applications")
|
alternate_result = fetch("#{ALTERNATIVE_W3DHUB_API_ENDPOINT}/apis/launcher/1/get-applications")
|
||||||
|
|
||||||
|
# We've failed to retrieve data
|
||||||
|
if primary_result.error? && alternate_result.error?
|
||||||
|
return result
|
||||||
|
# We've only gotten data back from the primary backend
|
||||||
|
elsif primary_result.okay? && alternate_result.error?
|
||||||
|
result.data = primary_result.data
|
||||||
|
return result
|
||||||
|
# We've only gotten data back from the alternate backend
|
||||||
|
elsif primary_result.error? && alternate_result.okay?
|
||||||
|
result.data = alternate_result.data
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
# We've gotten data back from both backends, merge them.
|
||||||
pp [primary_result, alternate_result]
|
pp [primary_result, alternate_result]
|
||||||
|
|
||||||
# FIXME: Merge primary and alternate results
|
# FIXME: Merge primary and alternate results
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ rescue LoadError
|
|||||||
require "cyberarm_engine"
|
require "cyberarm_engine"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
require "socket"
|
||||||
require "rexml"
|
require "rexml"
|
||||||
require "base64"
|
require "base64"
|
||||||
require "logger"
|
require "logger"
|
||||||
@@ -44,30 +45,20 @@ require_relative "lib/worker/tasks/repair_application"
|
|||||||
require_relative "lib/worker/tasks/update_application"
|
require_relative "lib/worker/tasks/update_application"
|
||||||
|
|
||||||
module W3DHubLauncher
|
module W3DHubLauncher
|
||||||
WORKER = Ractor.new(name: "Parallel Worker") { W3DHubLauncher::Worker.new }
|
# UNIXServer
|
||||||
end
|
Thread.new do
|
||||||
|
W3DHubLauncher::Worker.new.listen
|
||||||
# Hello, I exist because there presently exists no way to ask if there are pending
|
|
||||||
# messages in our ractors mailbox without making a blocking call which is a big no no
|
|
||||||
# for a GUI application. :|
|
|
||||||
#
|
|
||||||
# Keep an eye on: https://bugs.ruby-lang.org/issues/21930: "Add Ractor#empty? method to check for pending messages without blocking"
|
|
||||||
#
|
|
||||||
# NOTE: May need to mangle Window#update to do ruby-land sleep so thread gets time to process :(
|
|
||||||
Thread.new do
|
|
||||||
loop do
|
|
||||||
response = Ractor.receive
|
|
||||||
pp response
|
|
||||||
|
|
||||||
request = W3DHubLauncher::Worker::Request.requests.find { |r| r.request_id == response.request_id }
|
|
||||||
request&.handle_event(response.status, response.data)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# UNIXSocket / client
|
||||||
|
WORKER = W3DHubLauncher::Worker.new
|
||||||
|
WORKER.connect
|
||||||
end
|
end
|
||||||
|
|
||||||
# 10.times do
|
# 10.times do
|
||||||
W3DHubLauncher::Worker::Request.new(:w3dhub_api_call, { call: :fetch_applications }) do |result|
|
# W3DHubLauncher::Worker::Request.new(:w3dhub_api_call, { call: :fetch_applications }) do |result|
|
||||||
pp result
|
# pp [:CALLBACK, result]
|
||||||
end
|
# end
|
||||||
# end
|
# end
|
||||||
|
|
||||||
window = W3DHubLauncher::Window.new(width: 1280, height: 800, resizable: true)
|
window = W3DHubLauncher::Window.new(width: 1280, height: 800, resizable: true)
|
||||||
|
|||||||
Reference in New Issue
Block a user