Skip to content

Commit

Permalink
middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
godfat committed Jan 29, 2016
1 parent 6d2fe93 commit 29247c8
Show file tree
Hide file tree
Showing 25 changed files with 535 additions and 490 deletions.
2 changes: 1 addition & 1 deletion lib/rest-core/builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Builder
singleton_class.module_eval do
attr_writer :default_engine
def default_engine
@default_engine ||= RestCore::HttpClient
@default_engine ||= HttpClient
end

def client *attrs, &block
Expand Down
2 changes: 1 addition & 1 deletion lib/rest-core/client/simple.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
require 'rest-core/builder'

module RestCore
Simple = RestCore::Builder.client
Simple = Builder.client
end
40 changes: 21 additions & 19 deletions lib/rest-core/middleware/auth_basic.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@

require 'rest-core/middleware'

class RestCore::AuthBasic
def self.members; [:username, :password]; end
include RestCore::Middleware
module RestCore
class AuthBasic
def self.members; [:username, :password]; end
include Middleware

def call env, &k
if username(env)
if password(env)
app.call(env.merge(REQUEST_HEADERS =>
auth_basic_header(env).merge(env[REQUEST_HEADERS])), &k)
def call env, &k
if username(env)
if password(env)
app.call(env.merge(REQUEST_HEADERS =>
auth_basic_header(env).merge(env[REQUEST_HEADERS])), &k)
else
app.call(log(env, "AuthBasic: username provided: #{username(env)},"\
" but password is missing."), &k)
end
elsif password(env)
app.call(log(env, "AuthBasic: password provided: #{password(env)}," \
" but username is missing."), &k)
else
app.call(log(env, "AuthBasic: username provided: #{username(env)}," \
" but password is missing."), &k)
app.call(env, &k)
end
elsif password(env)
app.call(log(env, "AuthBasic: password provided: #{password(env)}," \
" but username is missing."), &k)
else
app.call(env, &k)
end
end

def auth_basic_header env
{'Authorization' =>
"Basic #{["#{username(env)}:#{password(env)}"].pack('m0')}"}
def auth_basic_header env
{'Authorization' =>
"Basic #{["#{username(env)}:#{password(env)}"].pack('m0')}"}
end
end
end
16 changes: 8 additions & 8 deletions lib/rest-core/middleware/bypass.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

module RestCore; end

# the simplest middleware
class RestCore::Bypass
def initialize app
@app = app
end
module RestCore
class Bypass
def initialize app
@app = app
end

def call env, &k
@app.call(env, &k)
def call env, &k
@app.call(env, &k)
end
end
end
184 changes: 93 additions & 91 deletions lib/rest-core/middleware/cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,118 +5,120 @@

require 'digest/md5'

class RestCore::Cache
def self.members; [:cache, :expires_in]; end
include RestCore::Middleware

def initialize app, cache, expires_in, &block
super(&block)
@app, @cache, @expires_in = app, cache, expires_in
end
module RestCore
class Cache
def self.members; [:cache, :expires_in]; end
include Middleware

def initialize app, cache, expires_in, &block
super(&block)
@app, @cache, @expires_in = app, cache, expires_in
end

def call env, &k
e = if env['cache.update']
cache_clear(env)
else
env
end

cache_get(e){ |cached|
e[TIMER].cancel if e[TIMER]
k.call(cached)
} || app_call(e, &k)
end
def call env, &k
e = if env['cache.update']
cache_clear(env)
else
env
end

cache_get(e){ |cached|
e[TIMER].cancel if e[TIMER]
k.call(cached)
} || app_call(e, &k)
end

def app_call env
app.call(env) do |res|
yield(if (res[FAIL] || []).empty?
cache_for(res)
else
res
end)
def app_call env
app.call(env) do |res|
yield(if (res[FAIL] || []).empty?
cache_for(res)
else
res
end)
end
end
end

def cache_key env
"rest-core:cache:#{Digest::MD5.hexdigest(env['cache.key'] ||
cache_key_raw(env))}"
end
def cache_key env
"rest-core:cache:#{Digest::MD5.hexdigest(env['cache.key'] ||
cache_key_raw(env))}"
end

def cache_get env, &k
return unless cache(env)
return unless cache_for?(env)
def cache_get env, &k
return unless cache(env)
return unless cache_for?(env)

uri = request_uri(env)
start_time = Time.now
return unless data = cache(env)[cache_key(env)]
res = log(env.merge(REQUEST_URI => uri),
Event::CacheHit.new(Time.now - start_time, uri))
data_extract(data, res, k)
end
uri = request_uri(env)
start_time = Time.now
return unless data = cache(env)[cache_key(env)]
res = log(env.merge(REQUEST_URI => uri),
Event::CacheHit.new(Time.now - start_time, uri))
data_extract(data, res, k)
end

private
def cache_key_raw env
"#{env[REQUEST_METHOD]}:#{request_uri(env)}:#{header_cache_key(env)}"
end
private
def cache_key_raw env
"#{env[REQUEST_METHOD]}:#{request_uri(env)}:#{header_cache_key(env)}"
end

def cache_clear env
return env unless cache(env)
return env unless cache_for?(env)
def cache_clear env
return env unless cache(env)
return env unless cache_for?(env)

cache_store(env, :[]=, nil)
end
cache_store(env, :[]=, nil)
end

def cache_for res
return res unless cache(res)
return res unless cache_for?(res)
def cache_for res
return res unless cache(res)
return res unless cache_for?(res)

if expires_in(res).kind_of?(Fixnum) &&
cache(res).respond_to?(:store) &&
cache(res).method(:store).arity == -3
if expires_in(res).kind_of?(Fixnum) &&
cache(res).respond_to?(:store) &&
cache(res).method(:store).arity == -3

cache_store(res, :store, data_construct(res),
:expires_in => expires_in(res))
else
cache_store(res, :[]= , data_construct(res))
cache_store(res, :store, data_construct(res),
:expires_in => expires_in(res))
else
cache_store(res, :[]= , data_construct(res))
end
end
end

def cache_store res, msg, value, *args
start_time = Time.now
cache(res).send(msg, cache_key(res), value, *args)
def cache_store res, msg, value, *args
start_time = Time.now
cache(res).send(msg, cache_key(res), value, *args)

if value
res
else
log(res,
Event::CacheCleared.new(Time.now - start_time, request_uri(res)))
if value
res
else
log(res,
Event::CacheCleared.new(Time.now - start_time, request_uri(res)))
end
end
end

def data_construct res
"#{ res[RESPONSE_STATUS]}\n" \
"#{(res[RESPONSE_HEADERS]||{}).map{|k,v|"#{k}: #{v}\n"}.join}\n\n" \
"#{ res[RESPONSE_BODY]}"
end
def data_construct res
"#{ res[RESPONSE_STATUS]}\n" \
"#{(res[RESPONSE_HEADERS]||{}).map{|k,v|"#{k}: #{v}\n"}.join}\n\n" \
"#{ res[RESPONSE_BODY]}"
end

def data_extract data, res, k
_, status, headers, body =
data.match(/\A(\d*)\n((?:[^\n]+\n)*)\n\n(.*)\Z/m).to_a
def data_extract data, res, k
_, status, headers, body =
data.match(/\A(\d*)\n((?:[^\n]+\n)*)\n\n(.*)\Z/m).to_a

result = res.merge(RESPONSE_STATUS => status.to_i,
RESPONSE_HEADERS =>
Hash[(headers||'').scan(/([^:]+): ([^\n]+)\n/)],
RESPONSE_BODY => body)
result = res.merge(RESPONSE_STATUS => status.to_i,
RESPONSE_HEADERS =>
Hash[(headers||'').scan(/([^:]+): ([^\n]+)\n/)],
RESPONSE_BODY => body)

result.merge(Promise.claim(result, &k).future_response)
end
result.merge(Promise.claim(result, &k).future_response)
end

def cache_for? env
[:get, :head, :otpions].include?(env[REQUEST_METHOD]) &&
!env[DRY] && !env[HIJACK]
end
def cache_for? env
[:get, :head, :otpions].include?(env[REQUEST_METHOD]) &&
!env[DRY] && !env[HIJACK]
end

def header_cache_key env
env[REQUEST_HEADERS].sort.map{|(k,v)|"#{k}=#{v}"}.join('&')
def header_cache_key env
env[REQUEST_HEADERS].sort.map{|(k,v)|"#{k}=#{v}"}.join('&')
end
end
end
28 changes: 15 additions & 13 deletions lib/rest-core/middleware/clash_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@
require 'rest-core/middleware'
require 'rest-core/util/clash'

class RestCore::ClashResponse
def self.members; [:clash_response]; end
include RestCore::Middleware
module RestCore
class ClashResponse
def self.members; [:clash_response]; end
include Middleware

def call env, &k
return app.call(env, &k) if env[DRY]
return app.call(env, &k) unless clash_response(env)
def call env, &k
return app.call(env, &k) if env[DRY]
return app.call(env, &k) unless clash_response(env)

app.call(env){ |res|
if res[RESPONSE_BODY].kind_of?(Hash)
yield(res.merge(RESPONSE_BODY => Clash.new(res[RESPONSE_BODY])))
else
yield(res)
end
}
app.call(env){ |res|
if res[RESPONSE_BODY].kind_of?(Hash)
yield(res.merge(RESPONSE_BODY => Clash.new(res[RESPONSE_BODY])))
else
yield(res)
end
}
end
end
end
52 changes: 27 additions & 25 deletions lib/rest-core/middleware/common_logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,36 @@
require 'rest-core/event'
require 'rest-core/middleware'

class RestCore::CommonLogger
def self.members; [:log_method]; end
include RestCore::Middleware
module RestCore
class CommonLogger
def self.members; [:log_method]; end
include Middleware

def call env
start_time = Time.now
flushed = flush(env)
app.call(flushed){ |response|
yield(process(response, start_time))
}
rescue
process(flushed, start_time)
raise
end
def call env
start_time = Time.now
flushed = flush(env)
app.call(flushed){ |response|
yield(process(response, start_time))
}
rescue
process(flushed, start_time)
raise
end

def process response, start_time
flush(log(response, log_request(start_time, response)))
end
def process response, start_time
flush(log(response, log_request(start_time, response)))
end

def flush env
return env if !log_method(env) || env[DRY]
(env[LOG] || []).compact.
each{ |obj| log_method(env).call("RestCore: #{obj}") }
env.merge(LOG => [])
end
def flush env
return env if !log_method(env) || env[DRY]
(env[LOG] || []).compact.
each{ |obj| log_method(env).call("RestCore: #{obj}") }
env.merge(LOG => [])
end

def log_request start_time, response
Event::Requested.new(Time.now - start_time,
"#{response[RC::REQUEST_METHOD].to_s.upcase} #{request_uri(response)}")
def log_request start_time, response
Event::Requested.new(Time.now - start_time,
"#{response[REQUEST_METHOD].to_s.upcase} #{request_uri(response)}")
end
end
end
Loading

0 comments on commit 29247c8

Please sign in to comment.