diff options
| author | Luc Donnet | 2015-03-23 21:12:56 +0100 |
|---|---|---|
| committer | Luc Donnet | 2015-03-23 21:12:56 +0100 |
| commit | fa7e745459aefd64086869882fcca73f948b46fa (patch) | |
| tree | a5df17d4498b4ca612f6398156a667d2593cc76e /lib/ievkit/client.rb | |
| parent | 0740decc6a2c5117d1dc89e3665774460626f86b (diff) | |
| download | chouette-core-fa7e745459aefd64086869882fcca73f948b46fa.tar.bz2 | |
Change ruby client for iev server
Diffstat (limited to 'lib/ievkit/client.rb')
| -rw-r--r-- | lib/ievkit/client.rb | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/lib/ievkit/client.rb b/lib/ievkit/client.rb new file mode 100644 index 000000000..53eb61074 --- /dev/null +++ b/lib/ievkit/client.rb @@ -0,0 +1,307 @@ +require 'sawyer' +require 'ievkit/arguments' +require 'ievkit/configurable' +require 'ievkit/client/jobs' + +module Ievkit + + # Client for the Iev API + class Client + + include Ievkit::Configurable + include Ievkit::Authentication + include Ievkit::Client::Jobs + + # Header keys that can be passed in options hash to {#get},{#head} + CONVENIENCE_HEADERS = Set.new([:accept, :content_type]) + + def initialize(options = {}) + # Use options passed in, but fall back to module defaults + Ievkit::Configurable.keys.each do |key| + instance_variable_set(:"@#{key}", options[key] || Ievkit.instance_variable_get(:"@#{key}")) + end + end + + # Compares client options to a Hash of requested options + # + # @param opts [Hash] Options to compare with current client options + # @return [Boolean] + def same_options?(opts) + opts.hash == options.hash + end + + # Text representation of the client, masking tokens and passwords + # + # @return [String] + def inspect + inspected = super + + # mask password + inspected = inspected.gsub! @password, "*******" if @password + # Only show last 4 of token, secret + if @access_token + inspected = inspected.gsub! @access_token, "#{'*'*36}#{@access_token[36..-1]}" + end + if @client_secret + inspected = inspected.gsub! @client_secret, "#{'*'*36}#{@client_secret[36..-1]}" + end + + inspected + end + + # Make a HTTP GET request + # + # @param url [String] The path, relative to {#api_endpoint} + # @param options [Hash] Query and header params for request + # @return [Sawyer::Resource] + def get(url, options = {}) + request :get, url, parse_query_and_convenience_headers(options) + end + + # Make a HTTP POST request + # + # @param url [String] The path, relative to {#api_endpoint} + # @param options [Hash] Body and header params for request + # @return [Sawyer::Resource] + def post(url, options = {}) + request :post, url, options + end + + # Make a HTTP PUT request + # + # @param url [String] The path, relative to {#api_endpoint} + # @param options [Hash] Body and header params for request + # @return [Sawyer::Resource] + def put(url, options = {}) + request :put, url, options + end + + # Make a HTTP PATCH request + # + # @param url [String] The path, relative to {#api_endpoint} + # @param options [Hash] Body and header params for request + # @return [Sawyer::Resource] + def patch(url, options = {}) + request :patch, url, options + end + + # Make a HTTP DELETE request + # + # @param url [String] The path, relative to {#api_endpoint} + # @param options [Hash] Query and header params for request + # @return [Sawyer::Resource] + def delete(url, options = {}) + request :delete, url, options + end + + # Make a HTTP HEAD request + # + # @param url [String] The path, relative to {#api_endpoint} + # @param options [Hash] Query and header params for request + # @return [Sawyer::Resource] + def head(url, options = {}) + request :head, url, parse_query_and_convenience_headers(options) + end + + # Make one or more HTTP GET requests, optionally fetching + # the next page of results from URL in Link response header based + # on value in {#auto_paginate}. + # + # @param url [String] The path, relative to {#api_endpoint} + # @param options [Hash] Query and header params for request + # @param block [Block] Block to perform the data concatination of the + # multiple requests. The block is called with two parameters, the first + # contains the contents of the requests so far and the second parameter + # contains the latest response. + # @return [Sawyer::Resource] + def paginate(url, options = {}, &block) + opts = parse_query_and_convenience_headers(options.dup) + if @auto_paginate || @per_page + opts[:query][:per_page] ||= @per_page || (@auto_paginate ? 100 : nil) + end + + data = request(:get, url, opts) + + if @auto_paginate + while @last_response.rels[:next] && rate_limit.remaining > 0 + @last_response = @last_response.rels[:next].get + if block_given? + yield(data, @last_response) + else + data.concat(@last_response.data) if @last_response.data.is_a?(Array) + end + end + + end + + data + end + + # Hypermedia agent for the Iev API + # + # @return [Sawyer::Agent] + def agent + @agent ||= Sawyer::Agent.new(api_endpoint, sawyer_options) do |http| + http.headers[:accept] = default_media_type + http.headers[:content_type] = "application/json" + http.headers[:user_agent] = user_agent + + # Activate if authentication is needed + # + # if basic_authenticated? + # http.basic_auth(@login, @password) + # elsif token_authenticated? + # http.authorization 'token', @access_token + # elsif application_authenticated? + # http.params = http.params.merge application_authentication + # end + end + end + + # Fetch the root resource for the API + # + # @return [Sawyer::Resource] + def root + get "/" + end + + # Response for last HTTP request + # + # @return [Sawyer::Response] + def last_response + @last_response if defined? @last_response + end + + # Duplicate client using client_id and client_secret as + # Basic Authentication credentials. + # @example + # Ievkit.client_id = "foo" + # Ievkit.client_secret = "bar" + # + # # GET https://api.github.com/?client_id=foo&client_secret=bar + # Ievkit.get "/" + # + # Ievkit.client.as_app do |client| + # # GET https://foo:bar@api.github.com/ + # client.get "/" + # end + def as_app(key = client_id, secret = client_secret, &block) + if key.to_s.empty? || secret.to_s.empty? + raise ApplicationCredentialsRequired, "client_id and client_secret required" + end + app_client = self.dup + app_client.client_id = app_client.client_secret = nil + app_client.login = key + app_client.password = secret + + yield app_client if block_given? + end + + # Set username for authentication + # + # @param value [String] GitHub username + def login=(value) + reset_agent + @login = value + end + + # Set password for authentication + # + # @param value [String] GitHub password + def password=(value) + reset_agent + @password = value + end + + # Set OAuth access token for authentication + # + # @param value [String] 40 character GitHub OAuth access token + def access_token=(value) + reset_agent + @access_token = value + end + + # Set OAuth app client_id + # + # @param value [String] 20 character GitHub OAuth app client_id + def client_id=(value) + reset_agent + @client_id = value + end + + # Set OAuth app client_secret + # + # @param value [String] 40 character GitHub OAuth app client_secret + def client_secret=(value) + reset_agent + @client_secret = value + end + + # Wrapper around Kernel#warn to print warnings unless + # IEVKIT_SILENT is set to true. + # + # @return [nil] + def ievkit_warn(*message) + unless ENV['IEVKIT_SILENT'] + warn message + end + end + + private + + def reset_agent + @agent = nil + end + + def request(method, path, data, options = {}) + if data.is_a?(Hash) + options[:query] = data.delete(:query) || {} + options[:headers] = data.delete(:headers) || {} + if accept = data.delete(:accept) + options[:headers][:accept] = accept + end + end + + @last_response = response = agent.call(method, URI::Parser.new.escape(path.to_s), data, options) + response.data + end + + # Executes the request, checking if it was successful + # + # @return [Boolean] True on success, false otherwise + def boolean_from_response(method, path, options = {}) + request(method, path, options) + @last_response.status == 204 + rescue Ievkit::NotFound + false + end + + + def sawyer_options + opts = { + :links_parser => Sawyer::LinkParsers::Hal.new + } + conn_opts = @connection_options + conn_opts[:builder] = @middleware if @middleware + conn_opts[:proxy] = @proxy if @proxy + opts[:faraday] = Faraday.new(conn_opts) + + opts + end + + def parse_query_and_convenience_headers(options) + headers = options.fetch(:headers, {}) + CONVENIENCE_HEADERS.each do |h| + if header = options.delete(h) + headers[h] = header + end + end + query = options.delete(:query) + opts = {:query => options} + opts[:query].merge!(query) if query && query.is_a?(Hash) + opts[:headers] = headers unless headers.empty? + + opts + end + end +end |
