class Object

Public Instance Methods

address_of(socket) click to toggle source

Send Format: =======

One line strings: “#{command} #{arg1} #{arg2} #{etc}” The last argument, depending on the command, may contain spaces (but usually does not need to)

Receive Format: =====

Usually one string, like “yes”, or “no”. Returns “denied” if an unauthorized command was attempted. Returns “invalid” if an invalid command was attempted. Returns “sorry” if an error was raised while processing the command. Can be a json argument, often following “yes ”.

# File lib/softwear/library/tcp_server.rb, line 32
def address_of(socket)
  _family, port, name, host = socket.addr
  if host == name
    "#{host}:#{port}"
  else
    "#{name}(#{host}):#{port}"
  end
end
dev_log(*a) click to toggle source
# File lib/softwear/library/tcp_server.rb, line 11
def dev_log(*a)
  $stdout.puts(*a) if Rails.env.development?
end
log(*a) click to toggle source
# File lib/softwear/library/tcp_server.rb, line 15
def log(*a)
  $stdout.puts(*a) unless Rails.env.test?
end
puts(s) click to toggle source
Calls superclass method
# File lib/softwear/library/tcp_server.rb, line 63
def puts(s)
  $stdout.puts "==> #{s}"
  super
end
report_error(client, whole_command, error) click to toggle source
# File lib/softwear/library/tcp_server.rb, line 5
def report_error(client, whole_command, error)
  $stderr.puts "=== ERROR WHILE PROCESSING THE COMMAND \"#{whole_command}\" ===\n"\
    "#{error.class.name}: #{error.message}\n#{error.backtrace.join("\n")}"
  client.puts "sorry"
end
split(string, limit = nil) click to toggle source
# File lib/softwear/library/tcp_server.rb, line 1
def split(string, limit = nil)
  string.split(/\s+/, limit)
end
start_server!(*args) click to toggle source
# File lib/softwear/library/tcp_server.rb, line 41
def start_server!(*args)
  log "Connecting...!"
  
  if args.size > 1
    port = args.first
  else
    port = ENV['port'] || ENV['PORT'] || 2900
  end

  server = TCPServer.new port
  log "Ready! Using \"#{ActiveRecord::Base.connection.current_database}\" database"

  client_count = 0
  commands = args.last

  loop do
    Thread.start(server.accept) do |client|
      client_count += 1
      dev_log "New client! ##{client_count} #{address_of client}"

      if Rails.env.development?
        response_logger = Module.new do
          def puts(s)
            $stdout.puts "==> #{s}"
            super
          end
        end
        client.singleton_class.send :include, response_logger
      end

      while line_in = client.gets.chomp
        log "Processing \"#{line_in}\"" if Rails.env.test?

        command, rest_of_command = split(line_in, 2)

        before = Time.now
        begin
          command = commands[command.downcase.to_sym]

          if command.nil?
            log "SOMEONE attempted invalid command: \"#{line_in}\""
          else
            dev_log "<== #{line_in}"
            ActiveRecord::Base.connection_pool.with_connection do
              command.call(client, rest_of_command)
            end
          end

        rescue StandardError => e
          report_error(client, line_in, e)
        rescue Exception => e
          report_error(client, line_in, e)
          break
        end
        after = Time.now

        ms = (after - before) * 1000
        dev_log %((#{'%.2f' % ms}ms) from #{address_of(client)})
        dev_log ""
      end

      client_count -= 1
      client.close rescue nil
      dev_log "Client disconnected. #{address_of client}"
    end
  end
end