require "securerandom" module TAC class PracticeGameClock class ClockNet class Client TAG = "ClockNet|Client" CHUNK_SIZE = 4096 PACKET_TAIL = "\r\n\n" attr_reader :uuid, :read_queue, :write_queue, :socket, :packets_sent, :packets_received, :data_sent, :data_received attr_accessor :sync_interval, :last_socket_error, :socket_error def initialize @uuid = SecureRandom.uuid @read_queue = [] @write_queue = [] @sync_interval = 100 @last_socket_error = nil @socket_error = false @bound = false @packets_sent, @packets_received = 0, 0 @data_sent, @data_received = 0, 0 end def uuid=(id) @uuid = id end def socket=(socket) @socket = socket @bound = true listen end def listen Thread.new do while connected? # Read from socket while message_in = read if message_in.empty? break else log.i(TAG, "Read: " + message_in) @read_queue << message_in @packets_received += 1 @data_received += message_in.length end end sleep @sync_interval / 1000.0 end end Thread.new do while connected? # Write to socket while message_out = @write_queue.shift write(message_out) @packets_sent += 1 @data_sent += message_out.to_s.length log.i(TAG, "Write: " + message_out.to_s) end sleep @sync_interval / 1000.0 end end end def sync(block) block.call end def handle_read_queue message = gets while message puts(message) log.i(TAG, "Writing to Queue: " + message) message = gets end end def socket_error? @socket_error end def connected? if closed? == true || closed? == nil false else true end end def closed? @socket.closed? if @socket end def write(message) begin @socket.puts("#{message}#{PACKET_TAIL}") rescue => error @last_socket_error = error @socket_error = true log.e(TAG, error.message) close end end def read begin message = @socket.gets rescue => error @last_socket_error = error @socket_error = true message = "" end return message.to_s.strip end def puts(message) @write_queue << message end def gets @read_queue.shift end def encode(message) return message end def decode(blob) return blob end def flush @socket.flush if socket end def close(reason = nil) write(reason) if reason @socket.close if @socket end end end end end