Skip to content
Permalink
Browse files

net-http-persistent

  • Loading branch information
sorah committed Oct 31, 2015
1 parent 603f411 commit ac397bf002e288d43f6b7962a7bb0eab7e954dfb
Showing with 132 additions and 16 deletions.
  1. +3 −0 5f/webapp/ruby/Gemfile
  2. +4 −0 5f/webapp/ruby/Gemfile.lock
  3. +125 −16 5f/webapp/ruby/app.rb
@@ -14,3 +14,6 @@ gem 'oj'
gem 'oj_mimic_json'
gem 'hiredis'
gem 'msgpack'

gem 'http-2'
gem 'net-http-persistent'
@@ -12,10 +12,12 @@ GEM
concurrent-ruby-ext (= 0.8.0)
retryable (> 1.0)
hiredis (0.6.0)
http-2 (0.7.0)
httpclient (2.6.0.1)
kgio (2.10.0)
msgpack (0.7.0)
multi_json (1.11.2)
net-http-persistent (2.9.4)
oj (2.13.0)
oj_mimic_json (1.0.1)
pg (0.18.3)
@@ -53,8 +55,10 @@ DEPENDENCIES
erubis
expeditor
hiredis
http-2
httpclient
msgpack
net-http-persistent
oj
oj_mimic_json
pg
@@ -1,8 +1,10 @@
require 'thread'
require 'sinatra/base'
require 'sinatra/contrib'
require 'pg'
require 'tilt/erubis'
require 'erubis'
require 'net/http/persistent'
require 'httpclient'
require 'openssl'
require 'expeditor'
@@ -25,15 +27,60 @@ def to_s
::Time.prepend TimeWithoutZone
end

# module Isucon5f
# class ConnectionPool
# LIST = {}
# SIZE = 12
#
# def self.for(hostport)
# host, port = hostport.split(?:, 2)
# LIST[hostport] ||= self.new(host, port.to_i)
# end
#
# def initialize(host, port)
# @host, @port = host, port
# @count = 0
# @lock = Mutex.new
# @queue = Queue.new
# end
#
# def take
# if @pool.pop
# end
# end
#
# def back(conn)
# @queue.push
# end
#
# def create
# @lock.synchronize do
# return nil if @count >= SIZE
# @count += 1
#
# Net::HTTP::e
#
# end
# end
#
# def use
# conn = take()
# yield conn
# ensure
# add conn if conn
# end
# end
# end

class Isucon5f::Endpoint
LIST = {}

def self.get(name)
LIST[name]
end

def initialize(name, method, token_type, token_key, uri)
@name, @method, @token_type, @token_key, @uri = name, method, token_type, token_key, uri
def initialize(name, method, token_type, token_key, uri, mode = :http)
@name, @method, @token_type, @token_key, @uri, @mode = name, method, token_type, token_key, uri, mode
@ssl = uri.start_with?('https://')

LIST[@name] = self
@@ -49,19 +96,81 @@ def fetch(conf)
end
call_uri = sprintf(uri, *conf['keys'])

client = HTTPClient.new
if @ssl
client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE

case @mode
when :http
fetch_http headers, params, call_uri, conf
when :http2
fetch_http2 headers, params, call_uri, conf
end
fetcher = case method
when 'GET' then client.method(:get_content)
when 'POST' then client.method(:post_content)
else
raise "unknown method #{method}"
end

def fetch_http2(headers, params, call_uri, conf)
@h2 ||= HTTP2::Client.new
@conn ||= begin
conn_stop_r, @conn_stop = IO.pipe
tcp = TCPSocket.new(uri.host, uri.port)
ctx = OpenSSL::SSL::SSLContext.new
ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE

ctx.npn_protocols = %w(h2)
ctx.npn_select_cb = lambda do |protocols|
'h2'.freeze
end

sock = OpenSSL::SSL::SSLSocket.new(tcp, ctx)
sock.sync_close = true
sock.hostname = uri.hostname
sock.connect

Thread.new do
loop do
rs, _, _ = IO.select([conn_stop_r, sock])
break if sock.closed? || sock.eof?
if rs.include?(sock)
data = sock.read_nonblock(1024)
# puts "Received bytes: #{data.unpack("H*").first}"

begin
@h2 << data
rescue => e
warn "Exception: #{e}, #{e.message} - closing socket."
sock.close
end
end

break if sock.closed? || sock.eof?
break if rs.include?(conn_stop_r)
end
end.abort_on_exception = true

sock
end
res = fetcher.call(call_uri, params, headers)
end

JSON.parse(res)
def fetch_http(headers, params, call_uri, conf)
@client ||= Net::HTTP::Persistent.new(self.__id__.to_s).tap do |cl|
cl.verify_mode = OpenSSL::SSL::VERIFY_NONE
end

call_uri = URI(call_uri)
call_uri.query = URI.encode_www_form(params)

req = case method
when 'GET'
Net::HTTP::Get.new(call_uri.request_uri, headers)
when 'POST'
Net::HTTP::Post.new(call_uri.request_uri, headers)
else
raise "unknown method #{method}"
end

s = Time.now
res = @client.request(call_uri, req)
res.value
e = Time.now
$stderr.puts "[API CALL][HTTP] #{method} #{call_uri} (#{"%.2f" % (e-s)}s)"
JSON.parse(res.body)
end
end

@@ -273,14 +382,14 @@ def fetch_api(method, uri, headers, params)
arg = get_subscription(user[:id])

data = arg.map do |service, conf|
#Expeditor::Command.new do
Expeditor::Command.new do
endpoint = Isucon5f::Endpoint.get(service)
{"service" => service, "data" => endpoint.fetch(conf)}
#end
end
end

#data.each(&:start)
json data#.map(&:get)
data.each(&:start)
json data.map(&:get)
end

get '/spoof' do

0 comments on commit ac397bf

Please sign in to comment.
You can’t perform that action at this time.