capgun 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +1 -8
  4. data/Gemfile.lock +32 -0
  5. data/HISTORY.md +14 -3
  6. data/LICENSE.md +26 -0
  7. data/README.md +306 -4
  8. data/Rakefile +10 -2
  9. data/capgun.gemspec +27 -16
  10. data/examples/hubot/capgun.coffee +68 -0
  11. data/lib/capgun.rb +29 -1
  12. data/lib/capgun/account.rb +13 -0
  13. data/lib/capgun/base.rb +48 -0
  14. data/lib/capgun/client.rb +82 -0
  15. data/lib/capgun/config.rb +73 -0
  16. data/lib/capgun/connection.rb +36 -0
  17. data/lib/capgun/core_ext/hash.rb +19 -0
  18. data/lib/capgun/creatable.rb +21 -0
  19. data/lib/capgun/error.rb +17 -0
  20. data/lib/capgun/error/bad_gateway.rb +7 -0
  21. data/lib/capgun/error/bad_request.rb +7 -0
  22. data/lib/capgun/error/client_error.rb +7 -0
  23. data/lib/capgun/error/forbidden.rb +7 -0
  24. data/lib/capgun/error/internal_server_error.rb +7 -0
  25. data/lib/capgun/error/not_acceptable.rb +7 -0
  26. data/lib/capgun/error/not_found.rb +7 -0
  27. data/lib/capgun/error/server_error.rb +7 -0
  28. data/lib/capgun/error/service_unavailable.rb +7 -0
  29. data/lib/capgun/error/unauthorized.rb +7 -0
  30. data/lib/capgun/estimate.rb +11 -0
  31. data/lib/capgun/job.rb +13 -0
  32. data/lib/capgun/order.rb +13 -0
  33. data/lib/capgun/request.rb +33 -0
  34. data/lib/capgun/request/gateway.rb +20 -0
  35. data/lib/capgun/response/parse_json.rb +28 -0
  36. data/lib/capgun/response/raise_client_error.rb +48 -0
  37. data/lib/capgun/response/raise_server_error.rb +23 -0
  38. data/lib/capgun/version.rb +27 -7
  39. data/spec/capgun/account_spec.rb +45 -0
  40. data/spec/capgun/base_spec.rb +29 -0
  41. data/spec/capgun/client_spec.rb +181 -0
  42. data/spec/capgun/config_spec.rb +43 -0
  43. data/spec/capgun/estimate_spec.rb +7 -0
  44. data/spec/capgun/job_spec.rb +45 -0
  45. data/spec/capgun/order_spec.rb +45 -0
  46. data/spec/capgun/version_spec.rb +11 -0
  47. data/spec/capgun_spec.rb +17 -0
  48. data/spec/faraday/response_spec.rb +68 -0
  49. data/spec/fixtures/account.json +9 -0
  50. data/spec/fixtures/completed-order.json +46 -0
  51. data/spec/fixtures/estimate.json +34 -0
  52. data/spec/fixtures/job.json +9 -0
  53. data/spec/fixtures/notfound.json +1 -0
  54. data/spec/fixtures/order.json +43 -0
  55. data/spec/fixtures/unauthorized.json +1 -0
  56. data/spec/spec_helper.rb +27 -0
  57. metadata +218 -10
@@ -0,0 +1,68 @@
1
+ # Description
2
+ # Grab web screens/thumbs of URLs using the capgun.io service
3
+ #
4
+ # Requires a CapGun API token to be set in the env var HUBOT_CAPGUN_TOKEN
5
+ #
6
+ # Dependencies:
7
+ # none
8
+ #
9
+ # Configuration:
10
+ # HUBOT_CAPGUN_TOKEN
11
+ #
12
+ # Commands:
13
+ # hubot cap <url> - Get a web screen of the url
14
+ #
15
+ # Notes:
16
+ # none
17
+ #
18
+ # Author:
19
+ # monde
20
+
21
+ module.exports = (robot) ->
22
+ robot.respond /cap (.*)/i, (msg) ->
23
+ Capgun.start msg, msg.match[1]
24
+
25
+ Capgun =
26
+
27
+ interval: 2500
28
+
29
+ token: process.env.HUBOT_CAPGUN_TOKEN
30
+
31
+ start: (msg, url) ->
32
+ this.submitOrder(msg, url)
33
+
34
+ submitOrder: (msg, url) ->
35
+ capgun = this
36
+ data = JSON.stringify({"url": url})
37
+ msg.http('https://api.capgun.io/v1/orders.json')
38
+ .headers
39
+ 'Authorization': capgun.token,
40
+ 'Accept': 'application/json'
41
+ .post(data) (err, res, body) ->
42
+ result = JSON.parse(body)
43
+ if err || res.statusCode != 200
44
+ message = result.message || "???"
45
+ msg.send "Capgun job failed with message '" + message + "', I'm bailing out!"
46
+ else
47
+ setTimeout (-> capgun.checkJob(msg, url, result.order.id, 0)), capgun.interval
48
+
49
+ checkJob: (msg, url, order_id, duration) ->
50
+ capgun = this
51
+
52
+ if duration > 90000
53
+ msg.send "Capgun job hung past 90 seconds for URL " + url + " , I'm bailing out!"
54
+ else
55
+ msg.http('https://api.capgun.io/v1/orders/' + order_id + '.json')
56
+ .headers
57
+ 'Authorization': capgun.token,
58
+ 'Accept': 'application/json'
59
+ .get() (err, res, body) ->
60
+ result = JSON.parse(body)
61
+ state = result.order.job.state
62
+
63
+ if state.search(/failed/) >= 0
64
+ msg.send "Capgun order " + order_id + " failed for URL " + url
65
+ else if state.search(/completed/) >= 0
66
+ msg.send result.order.asset_urls['640x480']
67
+ else
68
+ setTimeout (-> capgun.checkJob(msg, url, result.order.id, duration + capgun.interval)), capgun.interval
@@ -1,3 +1,31 @@
1
1
  module Capgun
2
- require 'capgun/version'
2
+
3
+ require 'capgun/config'
4
+ require 'capgun/client'
5
+
6
+ extend Config
7
+
8
+ class << self
9
+
10
+ extend Config
11
+
12
+ # Alias for Capgun::Client.new
13
+ #
14
+ # @param [Hash] options options for the Capgun::Client
15
+ # @return [Capgun::Client]
16
+ def new(options={})
17
+ Capgun::Client.new(options)
18
+ end
19
+
20
+ # Delegate methods to Capgun::Client
21
+ def method_missing(method, *args, &block)
22
+ return super unless new.respond_to?(method)
23
+ new.send(method, *args, &block)
24
+ end
25
+
26
+ # Corollary of #method_missing delegated to Capgun::Client
27
+ def respond_to?(method, include_private=false)
28
+ new.respond_to?(method, include_private) || super(method, include_private)
29
+ end
30
+ end
3
31
  end
@@ -0,0 +1,13 @@
1
+ module Capgun
2
+
3
+ # capgun account
4
+
5
+ class Account < Capgun::Base
6
+
7
+ include Capgun::Creatable
8
+
9
+ lazy_attr_reader :id, :name, :balance
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,48 @@
1
+ require 'capgun/creatable'
2
+
3
+ module Capgun
4
+ class Base
5
+ attr_accessor :attrs
6
+ alias :to_hash :attrs
7
+
8
+ # Define methods that retrieve the value from an initialized instance variable Hash, using the attribute as a key
9
+ #
10
+ # @overload self.lazy_attr_reader(attr)
11
+ # @param attr [Symbol]
12
+ # @overload self.lazy_attr_reader(attrs)
13
+ # @param attrs [Array<Symbol>]
14
+ def self.lazy_attr_reader(*attrs)
15
+ attrs.each do |attribute|
16
+ class_eval do
17
+ define_method attribute do
18
+ @attrs[attribute.to_s]
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ # Initializes a new Base object
25
+ #
26
+ # @param attrs [Hash]
27
+ # @return [Capgun::Base]
28
+ def initialize(attrs={})
29
+ @attrs = attrs.dup
30
+ end
31
+
32
+ # Initializes a new Base object
33
+ #
34
+ # @param method [String, Symbol] Message to send to the object
35
+ def [](method)
36
+ self.__send__(method.to_sym)
37
+ rescue NoMethodError
38
+ nil
39
+ end
40
+
41
+ # @param other [Capgun::Base]
42
+ # @return [Boolean]
43
+ def ==(other)
44
+ super || (other.class == self.class && other.id == self.id)
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,82 @@
1
+ require 'json'
2
+ require 'json/pure'
3
+ require 'capgun/base'
4
+ require 'capgun/account'
5
+ require 'capgun/estimate'
6
+ require 'capgun/job'
7
+ require 'capgun/order'
8
+ require 'capgun/config'
9
+ require 'capgun/connection'
10
+ require 'capgun/request'
11
+
12
+ module Capgun
13
+
14
+ # Wrapper for the Capgun REST API
15
+ class Client
16
+
17
+ include Capgun::Connection
18
+ include Capgun::Request
19
+
20
+ attr_accessor *Config::VALID_OPTIONS_KEYS
21
+
22
+ # Initializes a new API object. Accessor attributes are set based
23
+ # on Capgun::Config::VALID_OPTIONS_KEYS
24
+ #
25
+ # @param [Hash] attrs Addition client attributes.
26
+ # @return [Capgun::Client]
27
+ def initialize(attrs={})
28
+ attrs = Capgun.options.merge(attrs)
29
+ Config::VALID_OPTIONS_KEYS.each do |key|
30
+ instance_variable_set("@#{key}".to_sym, attrs[key])
31
+ end
32
+ end
33
+
34
+ # Estimates a capgun job cost / availability.
35
+ #
36
+ # @param [String] url A url that will be captured.
37
+ # @param [Hash] options Additional options to the capture request.
38
+ # @return [Capgun::Estimate] The estimate for the capture request.
39
+ def estimate(url, options = {})
40
+ estimate = post("/v1/orders/estimate.json", options.merge(:url => url))
41
+ Capgun::Estimate.new(estimate['order'])
42
+ end
43
+
44
+ # Creates a capgun job
45
+ #
46
+ # @param [String] url A url that will be captured.
47
+ # @param [Hash] options Additional options to the capture request.
48
+ # @return [Capgun::Order] The capture request order.
49
+ def capture(url, options = {})
50
+ order = post("/v1/orders.json", options.merge(:url => url))
51
+ Capgun::Order.new(order['order'])
52
+ end
53
+
54
+ # Query the order
55
+ #
56
+ # @param [String] order_id The id of a previously submitted order.
57
+ # @return [Capgun::Order] The capture order.
58
+ def order(order_id)
59
+ order = get("/v1/orders/#{order_id}.json")
60
+ Capgun::Order.new(order['order'])
61
+ end
62
+
63
+ # Query the status of a capture job.
64
+ #
65
+ # @param [String] job_id The id of a previously submitted capture job.
66
+ # @return [Capgun::Job] The capture request is a job that encapsulates status.
67
+ def status(job_id)
68
+ job = get("/v1/jobs/#{job_id}.json")
69
+ Capgun::Job.new(job['job'])
70
+ end
71
+
72
+ # Fetch account information
73
+ #
74
+ # @return [Capgun::Account] The account
75
+ def account
76
+ account = get("/v1/account.json")
77
+ Capgun::Account.new(account['account'])
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,73 @@
1
+ require 'capgun/version'
2
+
3
+ module Capgun
4
+
5
+ # Defines constants and methods related to configuration
6
+ module Config
7
+
8
+ # The HTTP connection adapter that will be used to connect if none is set
9
+ DEFAULT_ADAPTER = :net_http
10
+
11
+ # The Faraday connection options if none is set
12
+ DEFAULT_CONNECTION_OPTIONS = {}
13
+
14
+ # API endpoint
15
+ DEFAULT_ENDPOINT = 'https://api.capgun.io'
16
+
17
+ # The gateway server if none is set
18
+ DEFAULT_GATEWAY = nil
19
+
20
+ # The auth token if none is set
21
+ DEFAULT_AUTH_TOKEN = ""
22
+
23
+ # The value sent in the 'User-Agent' header if none is set
24
+ DEFAULT_USER_AGENT = "Capgun.io Ruby Gem #{Capgun::Version}"
25
+
26
+ # The proxy server if none is set
27
+ DEFAULT_PROXY = nil
28
+
29
+ # An array of valid keys in the options hash when configuring a {Capgun::Client}
30
+ VALID_OPTIONS_KEYS = [
31
+ :adapter,
32
+ :connection_options,
33
+ :endpoint,
34
+ :gateway,
35
+ :auth_token,
36
+ :user_agent,
37
+ :proxy,
38
+ ]
39
+
40
+ attr_accessor *VALID_OPTIONS_KEYS
41
+
42
+ # When this module is extended, set all configuration options to their default values
43
+ def self.extended(base)
44
+ base.reset
45
+ end
46
+
47
+ # Convenience method to allow configuration options to be set in a block
48
+ def configure
49
+ yield self
50
+ self
51
+ end
52
+
53
+ # Create a hash of options and their values
54
+ def options
55
+ options = {}
56
+ VALID_OPTIONS_KEYS.each{|k| options[k] = send(k)}
57
+ options
58
+ end
59
+
60
+ # Reset all configuration options to defaults
61
+ def reset
62
+ self.adapter = DEFAULT_ADAPTER
63
+ self.connection_options = DEFAULT_CONNECTION_OPTIONS
64
+ self.endpoint = DEFAULT_ENDPOINT
65
+ self.gateway = DEFAULT_GATEWAY
66
+ self.auth_token = DEFAULT_AUTH_TOKEN
67
+ self.user_agent = DEFAULT_USER_AGENT
68
+ self.proxy = DEFAULT_PROXY
69
+ self
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,36 @@
1
+ require 'faraday'
2
+ require 'capgun/core_ext/hash'
3
+ require 'capgun/request/gateway'
4
+ require 'capgun/response/parse_json'
5
+ require 'capgun/response/raise_client_error'
6
+ require 'capgun/response/raise_server_error'
7
+
8
+ module Capgun
9
+ module Connection
10
+ private
11
+
12
+ # Returns a Faraday::Connection object
13
+ #
14
+ # @param options [Hash] A hash of options
15
+ # @return [Faraday::Connection]
16
+ def connection(options={})
17
+ default_options = {
18
+ :headers => {
19
+ :accept => 'application/json',
20
+ :user_agent => user_agent,
21
+ :authorization => auth_token,
22
+ },
23
+ :proxy => proxy,
24
+ :ssl => {:verify => false},
25
+ :url => options.fetch(:endpoint, endpoint),
26
+ }
27
+ @connection ||=Faraday.new(default_options.deep_merge(connection_options)) do |builder|
28
+ builder.use Capgun::Request::Gateway, gateway if gateway
29
+ builder.use Capgun::Response::RaiseClientError
30
+ builder.use Capgun::Response::ParseJson
31
+ builder.use Capgun::Response::RaiseServerError
32
+ builder.adapter(adapter)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ class Hash
2
+
3
+ # Merges self with another hash, recursively
4
+ #
5
+ # @param hash [Hash] The hash to merge
6
+ # @return [Hash]
7
+ def deep_merge(hash)
8
+ target = self.dup
9
+ hash.keys.each do |key|
10
+ if hash[key].is_a?(Hash) && self[key].is_a?(Hash)
11
+ target[key] = target[key].deep_merge(hash[key])
12
+ next
13
+ end
14
+ target[key] = hash[key]
15
+ end
16
+ target
17
+ end
18
+
19
+ end
@@ -0,0 +1,21 @@
1
+ require 'time'
2
+
3
+ module Capgun
4
+ module Creatable
5
+
6
+ # Time when the object was created
7
+ #
8
+ # @return [Time]
9
+ def created_at
10
+ @created_at ||= Time.parse(@attrs['created_at']) unless @attrs['created_at'].nil?
11
+ end
12
+
13
+ # Time when the object was updated
14
+ #
15
+ # @return [Time]
16
+ def updated_at
17
+ @updated_at ||= Time.parse(@attrs['updated_at']) unless @attrs['updated_at'].nil?
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ module Capgun
2
+ # Custom error class for rescuing from all Capgun errors
3
+ class Error < StandardError
4
+ attr_reader :http_headers
5
+
6
+ # Initializes a new Error object
7
+ #
8
+ # @param message [String]
9
+ # @param http_headers [Hash]
10
+ # @return [Capgun::Error]
11
+ def initialize(message, http_headers)
12
+ @http_headers = Hash[http_headers]
13
+ super(message)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ require 'capgun/error/server_error'
2
+
3
+ module Capgun
4
+ # Raised when Capgun returns the HTTP status code 502
5
+ class Error::BadGateway < Capgun::Error::ServerError
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'capgun/error/client_error'
2
+
3
+ module Capgun
4
+ # Raised when Capgun returns the HTTP status code 400
5
+ class Error::BadRequest < Capgun::Error::ClientError
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require 'capgun/error'
2
+
3
+ module Capgun
4
+ # Raised when Capgun returns a 4xx HTTP status code
5
+ class Error::ClientError < Capgun::Error
6
+ end
7
+ end