# encoding: utf-8 module Hatetepe class Client USER_AGENT = 'User-Agent'.freeze USER_AGENT_VALUE = "hatetepe/#{Hatetepe::VERSION}".freeze HOST = 'Host'.freeze HOST_VALUE = '%s:%d'.freeze include Support::Handlers include Connection::Status attr_reader :config def initialize(config) @config = config @requests = [] setup_connection setup_handlers notify_handlers(:setup, @config, self, @connection) end def request(*args) request = Request.new(*args) perform(request).sync end def perform(request) served = Promise.new @requests << [request, served] add_extra_headers(request) Fiber.new { perform!(request) }.resume served end def receive(response) request, served = correlate served.fulfill(response) notify_handlers(:receive, request, response) response.closed { finish(request) } end def finish(request) @requests.delete_if { |(req)| req == request } notify_handlers(:finish, request) end def close @connection.close end def teardown(reason) @requests.each do |_, served| served.reject(reason) if (response = served.value) response.reject_closed(reason) end end end private def add_extra_headers(request) host = sprintf(HOST_VALUE, config[:address], config[:port]) request.add_extra_headers(USER_AGENT => USER_AGENT_VALUE, HOST => host) end def perform!(request) notify_handlers(:perform, request) @connection.serialize(request) end def correlate tuple = @requests.detect { |_, served| served.pending? } fail ClientError, 'Unable to correlate with request' unless tuple tuple end def setup_connection @connection = EM.connect(@config[:address], @config[:port], Connection::EventMachine) @connection.parse(method(:receive)) @connection.closed.then(method(:teardown)) end end end