diff --git a/lib/asterisk/irc_client.rb b/lib/asterisk/irc_client.rb index 4aa8cfc..5f2dafd 100644 --- a/lib/asterisk/irc_client.rb +++ b/lib/asterisk/irc_client.rb @@ -7,6 +7,8 @@ require_relative "irc_profile" class W3DHub class Asterisk class IRCClient + TAG = "IRCClient" + class SSL def self.default_context verify_peer_and_hostname @@ -38,24 +40,32 @@ class W3DHub attr_reader :status - def initialize(irc_profile = nil) + def initialize(irc_profile) @irc_profile = irc_profile + ssl_context = false + + if irc_profile.server_ssl + ssl_context = irc_profile.server_verify_ssl ? SSL.default_context : SSL.no_verify + end + socket = dial( @irc_profile.server_hostname, @irc_profile.server_port, - ssl_context: irc_profile.server_ssl ? irc_profile.server_verify_ssl ? SSL.default_context : SSL.no_verify : false + ssl_context: ssl_context ) authenticate_with_brenbot!(socket) ensure - socket&.close + close_socket(socket) end def dial(hostname, port = 6697, local_host: nil, local_port: nil, ssl_context: SSL.default_context) Socket.tcp(hostname, port, local_host, local_port).then do |socket| if ssl_context - ssl_context = SSL.send(ssl_context) if ssl_context.is_a? Symbol + @ssl_socket = true + + ssl_context = SSL.send(ssl_context) if ssl_context.is_a?(Symbol) OpenSSL::SSL::SSLSocket.new(socket, ssl_context).tap do |ssl_socket| ssl_socket.hostname = hostname @@ -65,21 +75,22 @@ class W3DHub socket end end + rescue StandardError => e + logger.error(TAG) { e } + logger.error(TAG) { e.backtrace } end def authenticate_with_brenbot!(socket) - pp @irc_profile, "#{@irc_profile.nickname}!#{@irc_profile.username.split("/").first}" - # exit + username = @irc_profile.username.empty? ? @irc_profile.nickname : @irc_profile.username - pass = IRCParser::Message.new(command: "PASS", parameters: [@irc_profile.password]) - user = IRCParser::Message.new(command: "USER", parameters: [@irc_profile.username, "0", "*", ":#{@irc_profile.nickname}"]) + pass = IRCParser::Message.new(command: "PASS", parameters: [Base64.strict_decode64(@irc_profile.password)]) unless @irc_profile.password.empty? + user = IRCParser::Message.new(command: "USER", parameters: [username, "0", "*", ":#{@irc_profile.nickname}"]) nick = IRCParser::Message.new(command: "NICK", parameters: [@irc_profile.nickname]) socket.puts(pass) socket.puts(user) socket.puts(nick) - pp socket socket.flush until socket.closed? @@ -93,19 +104,31 @@ class W3DHub socket.puts("#{pong}") socket.flush elsif msg.command == "001" && msg.parameters.join.include?("#{@irc_profile.nickname}!#{@irc_profile.username.split("/").first}") - pm = IRCParser::Message.new(command: "PRIVMSG", parameters: [@irc_profile.server_bot, "!auth #{@irc_profile.bot_auth_username} password"]) + pm = IRCParser::Message.new(command: "PRIVMSG", parameters: [@irc_profile.bot_username, "!auth #{@irc_profile.bot_auth_username} #{Base64.strict_decode64(@irc_profile.bot_auth_password)}"]) socket.puts(pm) quit = IRCParser::Message.new(command: "QUIT", parameters: ["Quiting from an Asterisk"]) socket.puts(quit) socket.flush - socket.close + sleep 15 + close_socket(socket) + elsif msg.command == "ERROR" + close_socket(socket) end end end + + def close_socket(socket) + return unless socket + + if @ssl_socket + socket.sync_close = true + socket.sysclose + else + socket.close + end + end end end end - -W3DHub::Asterisk::IRCClient.new diff --git a/lib/asterisk/server_profile.rb b/lib/asterisk/server_profile.rb index b3c5f3a..49ff262 100644 --- a/lib/asterisk/server_profile.rb +++ b/lib/asterisk/server_profile.rb @@ -2,7 +2,7 @@ class W3DHub class Asterisk class ServerProfile attr_accessor :name, :nickname, :password, - :game, :launch_arguments, + :game_title, :launch_arguments, :server_profile, :server_hostname, :server_port, :irc_profile @@ -15,7 +15,7 @@ class W3DHub @server_profile = hash[:server_profile] @server_hostname = hash[:server_hostname] @server_port = hash[:server_port] - @game = hash[:game] + @game_title = hash[:game_title] @launch_arguments = hash[:launch_arguments] @irc_profile = hash[:irc_profile] end diff --git a/lib/asterisk/states/irc_profile_form.rb b/lib/asterisk/states/irc_profile_form.rb index 7122074..f79ea99 100644 --- a/lib/asterisk/states/irc_profile_form.rb +++ b/lib/asterisk/states/irc_profile_form.rb @@ -70,7 +70,7 @@ class W3DHub stack(width: 0.5, height: 66) do para "Brenbot Auth Password:" - @bot_auth_password = edit_line @profile ? Base64.strict_decode64(@profile.bot_auth_password) : "", width: 1.0, fill: true, type: :password + @bot_auth_password = edit_line @profile && @profile.bot_auth_password ? Base64.strict_decode64(@profile.bot_auth_password) : "", width: 1.0, fill: true, type: :password end end diff --git a/lib/states/direct_connect_dialog.rb b/lib/states/direct_connect_dialog.rb index a3dc46f..dfa28d2 100644 --- a/lib/states/direct_connect_dialog.rb +++ b/lib/states/direct_connect_dialog.rb @@ -115,7 +115,8 @@ class W3DHub end @game_delete_button = button get_image("#{GAME_ROOT_PATH}/media/ui_icons/minus.png"), image_height: 1.0, tip: "Remove selected game" do - push_state(ConfirmDialog, message: "Remove game?") + push_state(ConfirmDialog, title: "Are you sure?", message: "Remove game: #{@games_list.value}?", accept_callback: -> { delete_game(game_from_title(@games_list.value)) }) + end @game_edit_button = button get_image("#{GAME_ROOT_PATH}/media/ui_icons/gear.png"), image_height: 1.0, tip: "Edit selected game" do @@ -135,7 +136,7 @@ class W3DHub end stack(width: 1.0, height: 66) do - para "IRC Profile:" + para "IRC Profile (Optional):" flow(width: 1.0, fill: true) do @irc_profiles_list = list_box items: W3DHub::Store[:asterisk_config].irc_profiles.map {| pf| pf.name }.insert(0, "None"), fill: true, height: 1.0 @@ -150,11 +151,11 @@ class W3DHub end @irc_delete_button = button get_image("#{GAME_ROOT_PATH}/media/ui_icons/minus.png"), image_height: 1.0, tip: "Remove selected IRC profile" do - push_state(ConfirmDialog, message: "") + push_state(ConfirmDialog, title: "Are you sure?", message: "Delete IRC Profile: #{@irc_profiles_list.value}?", accept_callback: -> { delete_irc_profile(irc_profile_from_name(@irc_profiles_list.value)) }) end @irc_edit_button = button get_image("#{GAME_ROOT_PATH}/media/ui_icons/gear.png"), image_height: 1.0, tip: "Edit selected IRC profile" do - push_state(Asterisk::States::IRCProfileForm, editing: W3DHub::Store[:asterisk_config].irc_profiles.find { |pf| pf.name == @irc_profiles_list.value }, save_callback: method(:save_irc_profile)) + push_state(Asterisk::States::IRCProfileForm, editing: irc_profile_from_name(@irc_profiles_list.value), save_callback: method(:save_irc_profile)) end end end @@ -164,14 +165,16 @@ class W3DHub flow(width: 1.0, height: 40, padding: 8) do button "Cancel", width: 0.25 do pop_state - @options[:cancel_callback]&.call end stack(fill: true) - button "Connect", width: 0.25 do + @connect_button = button "Connect", width: 0.25 do pop_state - @options[:accept_callback]&.call + + join_server(game_from_title(@games_list.value).path, @server_nickname.value, @server_hostname.value, @server_port.value, @server_password.value, @launch_arguments.value) + + handle_irc end end end @@ -203,6 +206,12 @@ class W3DHub @irc_delete_button.enabled = true @irc_edit_button.enabled = true end + + if @games_list.value.empty? || @server_nickname.value.empty? || @server_hostname.value.empty? || @server_port.value.empty? + @connect_button.enabled = false + else + @connect_button.enabled = true + end end def draw @@ -219,7 +228,7 @@ class W3DHub @server_hostname.value = profile.server_hostname @server_port.value = profile.server_port - @games_list.choose = profile.game if @games_list.items.find { |game| game == profile.game } + @games_list.choose = profile.game_title if @games_list.items.find { |game| game == profile.game_title } @launch_arguments.value = profile.launch_arguments @irc_profiles_list.choose = profile.irc_profile if @irc_profiles_list.items.find { |irc| irc == profile.irc_profile } @@ -244,7 +253,7 @@ class W3DHub updated.server_profile = @server_profiles_list.value updated.server_hostname = @server_hostname.value updated.server_port = @server_port.value - updated.game = @games_list.value + updated.game_title = @games_list.value updated.launch_arguments = @launch_arguments.value updated.irc_profile = @irc_profiles_list.value else @@ -274,6 +283,10 @@ class W3DHub @changes_made = false end + def game_from_title(title) + W3DHub::Store[:asterisk_config].games.find { |g| title == g.title } + end + def save_game(updated, path, title) if updated updated.path = path @@ -293,6 +306,21 @@ class W3DHub @games_list.choose = title end + def delete_game(game) + index = W3DHub::Store[:asterisk_config].games.index(game) || 0 + + W3DHub::Store[:asterisk_config].games.delete(game) + + W3DHub::Store[:asterisk_config].save_config + + @games_list.items = W3DHub::Store[:asterisk_config].games.map {|g| g.title } + @games_list.choose = W3DHub::Store[:asterisk_config].games[index - 1 > 0 ? index - 1 : 0].title + end + + def irc_profile_from_name(name) + W3DHub::Store[:asterisk_config].irc_profiles.find { |pf| name == pf.name } + end + def save_irc_profile( updated, nickname, username, password, server_hostname, server_port, server_ssl, server_verify_ssl, @@ -310,8 +338,8 @@ class W3DHub updated.nickname = nickname updated.username = username updated.password = Base64.strict_encode64(password) - updated.server_hostname = hserver_hostname - updated.server_port = hserver_port + updated.server_hostname = server_hostname + updated.server_port = server_port updated.server_ssl = server_ssl updated.server_verify_ssl = server_verify_ssl updated.bot_username = bot_username @@ -340,6 +368,75 @@ class W3DHub @irc_profiles_list.items = W3DHub::Store[:asterisk_config].irc_profiles.map {| pf| pf.name }.insert(0, "None") @irc_profiles_list.choose = generated_name end + + def delete_irc_profile(profile) + index = W3DHub::Store[:asterisk_config].irc_profiles.index(profile) || 0 + + W3DHub::Store[:asterisk_config].irc_profiles.delete(profile) + + W3DHub::Store[:asterisk_config].save_config + + @irc_profiles_list.items = W3DHub::Store[:asterisk_config].irc_profiles.map {| pf| pf.name }.insert(0, "None") + @irc_profiles_list.choose = W3DHub::Store[:asterisk_config].irc_profiles[index - 1 > 0 ? index - 1 : 0].name + end + + def wine_command + return "" if W3DHub.windows? + + "#{Store.settings[:wine_command]} " + end + + # TODO + def mangohud_command + return "" if W3DHub.windows? + + # TODO: Add game specific options + # OPENGL? + if false && system("which mangohud") + "MANGOHUD=1 MANGOHUD_DLSYM=1 DXVK_HUD=1 mangohud " + else + "" + end + end + + # TODO + def dxvk_command + return "" if W3DHub.windows? + + # Vulkan + # SETTING && WINE WILL USE DXVK? + if false && true#system() + _setting = "full" + "DXVK_HUD=#{_setting} " + else + "" + end + end + + def run(game_path, *args) + pid = Process.spawn("#{dxvk_command}#{mangohud_command}#{wine_command}\"#{game_path}\" #{args.join(' ')}") + Process.detach(pid) + end + + def join_server(game_path, nickname, server_address, server_port, server_password, launch_arguments) + server_password = nil if server_password.empty? + launch_arguments = nil if launch_arguments.empty? + + run( + game_path, + "-launcher +connect #{server_address}:#{server_port} +netplayername #{nickname}#{server_password ? " +password \"#{server_password}\"" : ""}#{launch_arguments ? " #{launch_arguments}" : ''}" + ) + end + + def handle_irc + return unless (profile = irc_profile_from_name(@irc_profiles_list.value)) + + Thread.new do + sleep 15 + + W3DHub::Asterisk::IRCClient.new(profile) + end + end end end end diff --git a/w3d_hub_linux_launcher.rb b/w3d_hub_linux_launcher.rb index e9d281f..84d537f 100644 --- a/w3d_hub_linux_launcher.rb +++ b/w3d_hub_linux_launcher.rb @@ -6,6 +6,7 @@ require "digest" require "rexml" require "logger" require "time" +require "base64" class W3DHub W3DHUB_DEBUG = ARGV.join.include?("--debug") @@ -127,6 +128,7 @@ require_relative "lib/pages/login" require_relative "lib/pages/settings" require_relative "lib/pages/download_manager" +require_relative "lib/asterisk/irc_client" require_relative "lib/asterisk/config" require_relative "lib/asterisk/game" require_relative "lib/asterisk/irc_profile"