Added Logger, added TACNET test server, networking now seems to work(heartbeats are sent and received)

This commit is contained in:
2020-06-07 21:23:16 -05:00
parent c694d29050
commit 95209ded73
10 changed files with 128 additions and 40 deletions

23
lib/logger.rb Normal file
View File

@@ -0,0 +1,23 @@
module TAC
class Logger
def printer(message)
puts "#{Time.now.strftime("%Y-%m-%d %H:%M:%S %Z")} #{message}"
end
def i(tag, message)
printer("INFO #{tag}: #{message}")
end
def d(tag, message)
printer("DEBUG #{tag}: #{message}")
end
def e(tag, message)
printer("ERROR #{tag}: #{message}")
end
end
end
def log
@logger ||= TAC::Logger.new
end

View File

@@ -34,7 +34,7 @@ module TAC
stack width: 0.499 do
@tacnet_status = label "Connection Error", background: TAC::Palette::TACNET_CONNECTION_ERROR, text_size: 18, padding: 5, margin_top: 2
@tacnet_connection_button = button "Connect", text_size: 18 do
window.backend.tacnet.connect
window.backend.tacnet.connect("localhost")
end
end
end

View File

@@ -12,10 +12,9 @@ module TAC
end
def connect(hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT, error_callback = proc {})
return if @connection && @connect.connected?
return if @connection && @connection.connected?
@connection = Connection.new(hostname, port)
puts "Connecting..."
@connection.connect(error_callback)
end
end

View File

@@ -1,6 +1,7 @@
module TAC
class TACNET
class Client
TAG = "TACNET|Client"
CHUNK_SIZE = 4096
attr_reader :uuid, :read_queue, :write_queue, :socket,
@@ -32,6 +33,8 @@ module TAC
if message_in.empty?
break
else
log.i(TAG, "Read: " + message_in)
@read_queue << message_in
@packets_received += 1
@@ -39,12 +42,19 @@ module TAC
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.length
@data_sent += message_out.to_s.length
log.i(TAG, "Write: " + message_out.to_s)
end
sleep @sync_interval / 1000.0
@@ -52,7 +62,7 @@ module TAC
end
end
def sync(&block)
def sync(block)
block.call
end
@@ -62,6 +72,8 @@ module TAC
while message
puts(message)
log.i(TAG, "Writing to Queue: " + message)
message = gets
end
end
@@ -79,7 +91,12 @@ module TAC
end
def write(message)
@socket.puts("#{message}\r\n\n")
begin
@socket.puts("#{message}\r\n\n")
rescue Errno::EPIPE, IOError => error
log.e(TAG, error.message)
close
end
end
def read
@@ -87,10 +104,14 @@ module TAC
begin
data = @socket.readpartial(CHUNK_SIZE)
message += message
message += data
rescue Errno::EPIPE, EOFError
message = ""
break
end until message.end_with?("\r\n\n")
return message
return message.strip
end
def puts(message)

View File

@@ -1,6 +1,7 @@
module TAC
class TACNET
class Connection
TAG = "TACNET|Connection"
def initialize(hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT)
@hostname = hostname
@port = port
@@ -14,6 +15,8 @@ module TAC
@connection_handler = proc do
handle_connection
end
@packet_handler = PacketHandler.new
end
def connect(error_callback)
@@ -24,6 +27,7 @@ module TAC
Thread.new do
begin
@client.socket = Socket.tcp(@hostname, @port, connect_timeout: 5)
log.i(TAG, "Connected to: #{@hostname}:#{@port}")
while @client && @client.connected?
if Gosu.milliseconds > @last_sync_time + @sync_interval
@@ -44,15 +48,23 @@ module TAC
if @client && @client.connected?
message = @client.gets
PacketHandler.handle(message) if message
@packet_handler.handle(message) if message
if Gosu.milliseconds > @last_heartbeat_sent + @heartbeat_interval
last_heartbeat_sent = Gosu.milliseconds
@last_heartbeat_sent = Gosu.milliseconds
client.puts(PacketHandler.packet_heartbeat)
@client.puts(PacketHandler.packet_heartbeat)
end
end
end
def connected?
!closed?
end
def closed?
@client.closed? if @client
end
end
end
end

View File

@@ -1,7 +1,7 @@
module TAC
class TACNET
class Packet
PROTOCOL_VERSION = "0"
PROTOCOL_VERSION = 0
PROTOCOL_HEADER_SEPERATOR = "|"
PROTOCOL_HEARTBEAT = "heartbeat"
@@ -27,12 +27,12 @@ module TAC
slice = message.split("|", 4)
if slice.size < 4
warn "Failed to split packet along first 4 " + PROTOCOL_HEADER_SEPERATOR + ". Raw return: " + Arrays.toString(slice)
warn "Failed to split packet along first 4 " + PROTOCOL_HEADER_SEPERATOR + ". Raw return: " + slice.to_s
return nil
end
if slice.first != PROTOCOL_VERSION
warn "Incompatible protocol version received, expected: " + PROTOCOL_VERSION + " got: " + slice.first
if slice.first != PROTOCOL_VERSION.to_s
warn "Incompatible protocol version received, expected: " + PROTOCOL_VERSION.to_s + " got: " + slice.first
return nil
end
@@ -41,25 +41,27 @@ module TAC
return nil
end
version = slice[0]
protocol_version = Integer(slice[0])
type = PACKET_TYPES.key(Integer(slice[1]))
content_length = Integer(slice[2])
content = slice[3]
body = slice[3]
return Packet.new(version, type, content_length, body)
raise "Type is #{type.inspect} [#{type.class}]" unless type.is_a?(Symbol)
return Packet.new(protocol_version, type, content_length, body)
end
def self.create(packet_type, body)
Packet.new(PROTOCOL_VERSION, packet_type, body.length, body)
Packet.new(PROTOCOL_VERSION, PACKET_TYPES.key(packet_type), body.length, body)
end
def self.valid_packet_type?(packet_type)
PACKET_TYPES.values.find { |t| t == packet_type }
end
attr_reader :version, :type, :content_length, :body
def initialize(version, type, content_length, body)
@version = version
attr_reader :protocol_version, :type, :content_length, :body
def initialize(protocol_version, type, content_length, body)
@protocol_version = protocol_version
@type = type
@content_length = content_length
@body = body
@@ -67,11 +69,11 @@ module TAC
def encode_header
string = ""
string += PROTOCOL_VERSION
string += protocol_version.to_s
string += PROTOCOL_HEADER_SEPERATOR
string += packet_type
string += PACKET_TYPES[type].to_s
string += PROTOCOL_HEADER_SEPERATOR
string += content_length
string += content_length.to_s
string += PROTOCOL_HEADER_SEPERATOR
return string

View File

@@ -1,6 +1,7 @@
module TAC
class TACNET
class PacketHandler
TAG = "TACNET|PacketHandler"
def initialize(host_is_a_connection: false)
@host_is_a_connection = host_is_a_connection
end
@@ -11,7 +12,7 @@ module TAC
if packet
hand_off(packet)
else
warn "Rejected raw packet: #{message}"
log.d(TAG, "Rejected raw packet: #{message}")
end
end
@@ -24,13 +25,17 @@ module TAC
when :dump_config
handle_dump_config(packet)
else
warn "No hand off available for packet type: #{packet.type}"
log.d(TAG, "No hand off available for packet type: #{packet.type}")
end
end
def handle_handshake(packet)
if @host_is_a_connection
# TODO: Set Connection client id to received uuid
end
end
# TODO: Reset socket timeout
def handle_heartbeat(packet)
end
@@ -52,7 +57,7 @@ module TAC
end
def self.packet_heartbeat
Packet.create(Packet::PACKET_TYPES[:heartbeat], Packet::PROTOCOL_VERSION)
Packet.create(Packet::PACKET_TYPES[:heartbeat], Packet::PROTOCOL_HEARTBEAT)
end
def self.packet_dump_config(string)

View File

@@ -1,6 +1,7 @@
module TAC
class TACNET
class Server
TAG = "TACNET|Server"
attr_reader :active_client,
:packets_sent, :packets_received, :data_sent, :data_received,
:client_last_packets_sent, :client_last_packets_received, :client_last_data_sent, :client_last_data_received
@@ -28,28 +29,31 @@ module TAC
@packet_handler = PacketHandler.new
end
def start
Thread.new do
while !@socket && @connection_attempts < @max_connection_attempts
def start(run_on_main_thread: false)
thread = Thread.new do
while (!@socket && @connection_attempts < @max_connection_attempts)
begin
log.i(TAG, "Starting server...")
@socket = TCPServer.new(@port)
rescue => error
p error
log.e(TAG, error)
@connection_attempts += 1
retry
retry if @connection_attempts < @max_connection_attempts
end
end
while !@socket.closed?
while @socket && !@socket.closed?
begin
run_server
rescue => error
p error
@socket.close
@socket.close if @socket
end
end
end
thread.join if run_on_main_thread
end
def run_server
@@ -58,9 +62,10 @@ module TAC
client.sync_interval = @sync_interval
client.socket = @socket.accept
unless @active_client && @active_client.closed?
warn "Too many clients, already have one connected!"
if @active_client && @active_client.connected?
log.i(TAG, "Too many clients, already have one connected!")
client.close("Too many clients!")
pp @active_client.connected?
else
@active_client = client
# TODO: Backup local config
@@ -70,6 +75,8 @@ module TAC
@active_client.puts(PacketHandler.packet_handshake(@active_client.uuid))
@active_client.puts(PacketHandler.packet_dump_config(config))
log.i(TAG, "Client connected!")
Thread.new do
while @active_client && @active_client.connected?
if Gosu.milliseconds > @last_sync_time + @sync_interval
@@ -96,14 +103,14 @@ module TAC
if @active_client && @active_client.connected?
message = @active_client.gets
unless message.empty?
if message && !message.empty?
@packet_handler.handle(message)
end
if Gosu.milliseconds > @last_heartbeat_sent + @heartbeat_interval
@last_heartbeat_sent = Gosu.milliseconds
@active_client.puts(PacketHandler.packet_heartbeart)
@active_client.puts(PacketHandler.packet_heartbeat)
end
end
end

17
tacnet_test_server.rb Normal file
View File

@@ -0,0 +1,17 @@
require "gosu"
require "socket"
require "securerandom"
require_relative "lib/tac"
require_relative "lib/logger"
require_relative "lib/tacnet"
require_relative "lib/tacnet/packet"
require_relative "lib/tacnet/packet_handler"
require_relative "lib/tacnet/client"
require_relative "lib/tacnet/server"
Thread.report_on_exception = true
server = TAC::TACNET::Server.new
server.start(run_on_main_thread: true)

View File

@@ -1,5 +1,6 @@
require_relative "../cyberarm_engine/lib/cyberarm_engine"
require "socket"
require "securerandom"
require "json"
require "faker"
@@ -12,6 +13,7 @@ require_relative "lib/storage"
require_relative "lib/backend"
require_relative "lib/states/editor"
require_relative "lib/theme"
require_relative "lib/logger"
require_relative "lib/dialog"
require_relative "lib/dialogs/name_prompt_dialog"
require_relative "lib/tacnet"
@@ -21,6 +23,6 @@ require_relative "lib/tacnet/client"
require_relative "lib/tacnet/connection"
require_relative "lib/tacnet/server"
Thread.abort_on_exception = true
# Thread.abort_on_exception = true
TAC::Window.new(width: (Gosu.screen_width * 0.8).round, height: (Gosu.screen_height * 0.8).round, resizable: true).show