Lalit (owner)

Fork Of

Revisions

gist: 59834 Download_button fork
public
Public Clone URL: git://gist.github.com/59834.git
Embed All Files: show embed
Easy client-caching with RestClient and Rack-Cache.rb #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# Author: Cyril Rohr
require 'rubygems'
require 'rest_client' # sudo gem install rest-client
require 'rack/cache' # sudo gem install rack-cache
 
module RestClient
  # this is a quick hack to show how you can use rack-cache as a powerful client cache.
  class CacheableResource < Resource
    attr_reader :cache
    CACHE_DEFAULT_OPTIONS = {}.freeze
    
    def initialize(*args)
      super(*args)
      # rack-cache creates a singleton, so that there is only one instance of the cache at any time
      @cache = Rack::Cache.new(self, options[:cache] || CACHE_DEFAULT_OPTIONS)
    end
  
    def get(additional_headers = {}, pass_through_cache = true)
      if pass_through_cache && cache
        uri = URI.parse(url)
        uri_path_split = uri.path.split("/")
        path_info = (last_part = uri_path_split.pop) ? "/"+last_part : ""
        script_name = uri_path_split.join("/")
        env = {
          "REQUEST_METHOD" => 'GET',
          "SCRIPT_NAME" => script_name,
          "PATH_INFO" => path_info,
          "QUERY_STRING" => uri.query,
          "SERVER_NAME" => uri.host,
          "SERVER_PORT" => uri.port
        }
        debeautify_headers(additional_headers).each do |key, value|
          env.merge!("HTTP_"+key.to_s.upcase => value)
        end
        cache.call(env)
      else
        super(additional_headers)
      end
    end
  
    def debeautify_headers(headers = {})
      headers.inject({}) do |out, (key, value)|
   out[key.to_s.gsub(/_/, '-')] = value#.first
   out
   end
    end
  
    def call(env)
      http_headers = env.inject({}) do |out, (header, value)|
        if header =~ /HTTP_/
          out[header.gsub("HTTP_", '')] = value unless value.nil? || value.empty?
        end
        out
      end
      response = get(debeautify_headers(http_headers), pass_through_cache=false)
      response.headers.delete(:x_content_digest) # don't know why, but it seems to make the validation fail if kept...
      [response.code, debeautify_headers( response.headers ), response.to_s]
    rescue RestClient::NotModified
      # Unfortunately, RestClient does not return the Net::HTTP response in the exception...
      [304, {}, ""]
    end
  end
end
 
RestClient.log = "stdout"
# will store the cached data in files
# cache_options = {:verbose => true, :metastore => 'file:/tmp/cache/meta', :entitystore => 'file:/tmp/cache/body'}
# will store the cached data in heap (all data are lost at the end of the script)
cache_options = {}
resource = RestClient::CacheableResource.new('http://some/cacheable/resource', :cache => cache_options)
 
begin
  10.times do
    resource['/'].get(:accept => 'application/json')
    sleep 1
  end
rescue RestClient::ResourceNotFound
  puts 'Resource not found.'
rescue RestClient::RequestTimeout
  puts 'Timeout.'
rescue RestClient::Unauthorized
  puts 'Unauthorized.'
rescue RestClient::RequestFailed
  puts 'Request failed.'
rescue RestClient::ServerBrokeConnection
  puts 'Connection broken.'
rescue Exception => e
  puts e.message
end