Class: Sc2::Connection
- Inherits:
-
Object
- Object
- Sc2::Connection
- Includes:
- Requests
- Defined in:
- lib/sc2ai/connection.rb,
lib/sc2ai/connection/requests.rb,
lib/sc2ai/connection/status_listener.rb,
lib/sc2ai/connection/connection_listener.rb
Overview
Manages client connection to the Api
Defined Under Namespace
Modules: ConnectionListener, Requests, StatusListener
Instance Attribute Summary collapse
-
#external_time ⇒ Float
Total milliseconds spent waiting on SC2 responses.
-
#host ⇒ Object
Returns the value of attribute host.
-
#listeners ⇒ Object
readonly
Returns the value of attribute listeners.
-
#port ⇒ Object
Returns the value of attribute port.
-
#status ⇒ Object
readonly
Last known game status, i.e.
-
#websocket ⇒ Object
Returns the value of attribute websocket.
Instance Method Summary collapse
-
#add_listener(listener, klass:) ⇒ void
Add a listener of specific callback type.
-
#close ⇒ void
Closes Connection to client.
-
#connect ⇒ void
Attempts to connect for a period of time, ignoring errors nad performing on_* callbacks.
-
#initialize(host:, port:) ⇒ Connection
constructor
#param [Sc2::CallbackListener] listener.
-
#remove_listener(listener, klass:) ⇒ Object
Removes a listener of specific callback type.
-
#send_request(request) ⇒ Api::Response
——————————————————— Sends a request synchronously and returns Api::Response type.
-
#send_request_and_ignore(request) ⇒ void
Sends and ignores response.
Methods included from Requests
#action, #available_maps, #create_game, #data, #debug, #game_info, #join_game, #leave_game, #observation, #observer_action, #observer_action_camera_move, #ping, #query, #query_abilities, #query_abilities_for_unit_tags, #query_ability_ids_for_unit, #query_pathings, #query_placements, #quit, #replay_info, #request_quick_load, #request_quick_save, #restart_game, #save_map, #save_replay, #send_request_for, #start_replay, #step
Constructor Details
#initialize(host:, port:) ⇒ Connection
#param [Sc2::CallbackListener] listener
39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/sc2ai/connection.rb', line 39 def initialize(host:, port:) @host = host @port = port @listeners = {} @websocket = nil @status = :unknown @external_time = 0.0 # Only allow one request at a time. # TODO: Since it turns out the client websocket can only handle 1 request at a time, we don't stricly need Async @scheduler = Async::Semaphore.new(1) end |
Instance Attribute Details
#external_time ⇒ Float
Total milliseconds spent waiting on SC2 responses
17 18 19 |
# File 'lib/sc2ai/connection.rb', line 17 def external_time @external_time end |
#host ⇒ Object
Returns the value of attribute host.
19 20 21 |
# File 'lib/sc2ai/connection.rb', line 19 def host @host end |
#listeners ⇒ Object
Returns the value of attribute listeners.
34 35 36 |
# File 'lib/sc2ai/connection.rb', line 34 def listeners @listeners end |
#port ⇒ Object
Returns the value of attribute port.
19 20 21 |
# File 'lib/sc2ai/connection.rb', line 19 def port @port end |
#status ⇒ Object
Last known game status, i.e. :launched, :ended, :unknown
:launched // Game has been launch and is not yet doing anything.
:init_game // Create game has been called, and the host is awaiting players.
:in_game // In a single or multiplayer game.
:in_replay // In a replay.
:ended // Game has ended, can still request game info, but ready for a new game.
:quit // Application is shutting down.
:unknown // Should not happen, but indicates an error if it occurs.
@return [Symbol] game status
30 31 32 |
# File 'lib/sc2ai/connection.rb', line 30 def status @status end |
#websocket ⇒ Object
Returns the value of attribute websocket.
19 20 21 |
# File 'lib/sc2ai/connection.rb', line 19 def websocket @websocket end |
Instance Method Details
#add_listener(listener, klass:) ⇒ void
This method returns an undefined value.
Add a listener of specific callback type
86 87 88 89 |
# File 'lib/sc2ai/connection.rb', line 86 def add_listener(listener, klass:) @listeners[klass.to_s] ||= [] @listeners[klass.to_s].push(listener) end |
#close ⇒ void
This method returns an undefined value.
Closes Connection to client
77 78 79 80 |
# File 'lib/sc2ai/connection.rb', line 77 def close @websocket&.close @listeners[ConnectionListener.name]&.each { _1.on_disconnect(self) } end |
#connect ⇒ void
This method returns an undefined value.
Attempts to connect for a period of time, ignoring errors nad performing on_* callbacks
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/sc2ai/connection.rb', line 53 def connect attempt = 1 Sc2.logger.debug { "Waiting for client..." } if (attempt % 5).zero? begin @websocket = Async::WebSocket::Client.connect(endpoint) # , handler: Sc2::Connection::Connection) @listeners[ConnectionListener.name]&.each { _1.on_connected(self) } # do initial ping to ensure status is set and connection is working response_ping = ping Sc2.logger.debug { "Game version: #{response_ping.game_version}" } rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EADDRNOTAVAIL raise Error, "Connection timeout. Max retry exceeded." unless (attempt += 1) < 30 # 30s attempts @listeners[ConnectionListener.name]&.each { _1.on_connection_waiting(self) } sleep(1) retry rescue Error => e Sc2.logger.error "#{e.class}: #{e.message}" @listeners[ConnectionListener.name]&.each { _1.on_disconnect(self) } end nil end |
#remove_listener(listener, klass:) ⇒ Object
Removes a listener of specific callback type
94 95 96 |
# File 'lib/sc2ai/connection.rb', line 94 def remove_listener(listener, klass:) @listeners[klass.to_s].delete(listener) end |
#send_request(request) ⇒ Api::Response
Sends a request synchronously and returns Api::Response type
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/sc2ai/connection.rb', line 101 def send_request(request) @scheduler.async do |_task| request = request.to_proto unless request.is_a?(String) time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) @websocket.send_binary(request) response = @websocket.read.to_str @external_time += Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - time response = Api::Response.decode(response) if @status != response.status @status = response.status @listeners[StatusListener.name]&.each { _1.on_status_change(@status) } end response end.wait rescue EOFError => e Sc2.logger.error e close end |
#send_request_and_ignore(request) ⇒ void
This method returns an undefined value.
Sends and ignores response. Meant to be used as optimization for RequestStep. No other command sends and ignores. Expects request to be to_proto’d already
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/sc2ai/connection.rb', line 129 def send_request_and_ignore(request) @scheduler.async do |_task| time = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) @websocket.send_binary(request) while @websocket.read_frame if @websocket.frames.last&.finished? @websocket.frames = [] break end end @external_time += Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_millisecond) - time end.wait nil end |