cloudscrape-client 0.1.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.
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "cloud_scrape/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cloudscrape-client"
8
+ spec.version = CloudScrape::VERSION
9
+ spec.authors = ["Charles J Hardy"]
10
+ spec.email = ["support@cloudscrape.com"]
11
+
12
+ spec.summary = "Wrapper for CloudScrape API"
13
+ spec.description = "Wrapper for CloudScrape API"
14
+ spec.homepage = "http://cloudscrape.com"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_runtime_dependency "faraday", "~> 0.9"
26
+ spec.add_runtime_dependency "faraday_middleware", "~> 0.10"
27
+ spec.add_runtime_dependency "faraday-conductivity", "~> 0.3"
28
+ spec.add_runtime_dependency "faraday_middleware-multi_json", "~> 0.0"
29
+
30
+ spec.add_development_dependency "bundler", "~> 1.10"
31
+ spec.add_development_dependency "rake", "~> 10.0"
32
+ spec.add_development_dependency "rspec"
33
+ spec.add_development_dependency "rubocop"
34
+ spec.add_development_dependency "simplecov"
35
+ spec.add_development_dependency "vcr"
36
+ spec.add_development_dependency "webmock"
37
+ end
@@ -0,0 +1,27 @@
1
+ require "logger"
2
+
3
+ require "cloud_scrape/version"
4
+ require "cloud_scrape/configuration"
5
+ require "cloud_scrape/dto"
6
+ require "cloud_scrape/runs"
7
+ require "cloud_scrape/executions"
8
+
9
+ class CloudScrape
10
+ extend Configure
11
+
12
+ NotFound = Class.new(StandardError)
13
+ InternalServerError = Class.new(StandardError)
14
+
15
+ def initialize(api_key: nil, account_id: nil)
16
+ CloudScrape.configuration.api_key = api_key if api_key
17
+ CloudScrape.configuration.account_id = account_id if account_id
18
+ end
19
+
20
+ def runs(id)
21
+ Runs.new(id: id)
22
+ end
23
+
24
+ def executions(id)
25
+ Executions.new(id: id)
26
+ end
27
+ end
@@ -0,0 +1,87 @@
1
+ require "digest"
2
+ require "faraday"
3
+ require "faraday_middleware"
4
+ require "faraday/conductivity"
5
+ require "faraday_middleware/multi_json"
6
+
7
+ class CloudScrape
8
+ class API
9
+ InvalidApiKey = Class.new(StandardError)
10
+ InvalidAccountId = Class.new(StandardError)
11
+
12
+ def self.get(*args)
13
+ new.get(*args)
14
+ end
15
+
16
+ def self.post(*args)
17
+ new.post(*args)
18
+ end
19
+
20
+ def self.delete(*args)
21
+ new.delete(*args)
22
+ end
23
+
24
+ def get(domain:, url:, options: {})
25
+ connection(domain).get(URI.escape(url), options)
26
+ end
27
+
28
+ def post(domain:, url:, options: {})
29
+ connection(domain).post do |req|
30
+ req.url URI.escape(url)
31
+ req.headers["Content-Type"] = "application/json"
32
+ req.body = options.to_json
33
+ end
34
+ end
35
+
36
+ def delete(domain:, url:, options: {})
37
+ connection(domain).delete(URI.escape(url), options)
38
+ end
39
+
40
+ private
41
+
42
+ def access_key
43
+ fail InvalidAccountId, account_id unless account_id
44
+ fail InvalidApiKey, api_key unless api_key
45
+
46
+ Digest::MD5.hexdigest(account_id + api_key)
47
+ end
48
+
49
+ def account_id
50
+ CloudScrape.configuration.account_id
51
+ end
52
+
53
+ def api_key
54
+ CloudScrape.configuration.api_key
55
+ end
56
+
57
+ # rubocop:disable Metrics/AbcSize
58
+ # rubocop:disable Metrics/MethodLength
59
+ def connection(domain)
60
+ Faraday.new(url: domain) do |faraday|
61
+ faraday.request :url_encoded
62
+
63
+ faraday.request :user_agent,
64
+ app: CloudScrape.configuration.user_agent_app,
65
+ version: CloudScrape.configuration.user_agent_version
66
+
67
+ faraday.request :request_headers,
68
+ accept: "application/json",
69
+ "X-CloudScrape-Access" => access_key,
70
+ "X-CloudScrape-Account" => account_id,
71
+ content_type: "application/json"
72
+
73
+ if CloudScrape.configuration.verbose
74
+ faraday.response :logger, CloudScrape.configuration.logger
75
+ end
76
+
77
+ faraday.response :multi_json,
78
+ content_type: /\bjson$/,
79
+ symbolize_keys: true
80
+
81
+ faraday.adapter Faraday.default_adapter
82
+ end
83
+ end
84
+ # rubocop:enable Metrics/AbcSize
85
+ # rubocop:enable Metrics/MethodLength
86
+ end
87
+ end
@@ -0,0 +1,57 @@
1
+ class CloudScrape
2
+ module Configure
3
+ def configuration
4
+ @configuration ||= Configuration.new
5
+ end
6
+
7
+ def configure
8
+ yield(configuration)
9
+ configuration
10
+ end
11
+
12
+ private
13
+
14
+ class Configuration
15
+ attr_accessor :base_url,
16
+ :api_key,
17
+ :account_id,
18
+ :user_agent_app,
19
+ :user_agent_version,
20
+ :timeout,
21
+ :verbose,
22
+ :logger
23
+
24
+ def initialize # rubocop:disable Metrics/AbcSize
25
+ self.base_url = base_url_default
26
+ self.user_agent_app = user_agent_app_default
27
+ self.user_agent_version = user_agent_version_default
28
+ self.timeout = timeout_default
29
+
30
+ self.api_key = ENV["CLOUD_SCRAPE_CLIENT_API_KEY"]
31
+ self.account_id = ENV["CLOUD_SCRAPE_CLIENT_ACCOUNT_ID"]
32
+ self.verbose = ENV["CLOUD_SCRAPE_CLIENT_VERBOSE"] || false
33
+
34
+ self.logger = Logger.new(STDOUT)
35
+ end
36
+
37
+ private
38
+
39
+ def base_url_default
40
+ ENV["CLOUD_SCRAPE_CLIENT_BASE_URL"] ||
41
+ "https://app.cloudscrape.com/api/"
42
+ end
43
+
44
+ def user_agent_app_default
45
+ ENV["CLOUD_SCRAPE_CLIENT_USER_AGENT_APP"] || "CS-RUBY-CLIENT"
46
+ end
47
+
48
+ def user_agent_version_default
49
+ ENV["CLOUD_SCRAPE_CLIENT_USER_AGENT_VERSION"] || "1.0"
50
+ end
51
+
52
+ def timeout_default
53
+ ENV["CLOUD_SCRAPE_CLIENT_TIMEOUT"] || 3600
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,58 @@
1
+ require "cloud_scrape/api"
2
+ require "cloud_scrape/validate"
3
+
4
+ class CloudScrape
5
+ class DTO
6
+ attr_reader :options
7
+
8
+ def initialize(options:)
9
+ @options = options
10
+ end
11
+
12
+ def self.for(options)
13
+ new(options: options).response(options.fetch(:method))
14
+ end
15
+
16
+ def self.get(options = {})
17
+ new(options: options).response(:get)
18
+ end
19
+
20
+ def self.post(options = {})
21
+ new(options: options).response(:post)
22
+ end
23
+
24
+ def self.delete(options = {})
25
+ new(options: options).response(:delete)
26
+ end
27
+
28
+ def response(method)
29
+ API.public_send(
30
+ method,
31
+ domain: domain,
32
+ url: endpoint,
33
+ options: {
34
+ api_key: api_key,
35
+ format: "json"
36
+ }.merge(params)
37
+ ).tap(&CloudScrape::Validate).body
38
+ end
39
+
40
+ def params
41
+ {}
42
+ end
43
+
44
+ def endpoint
45
+ fail NotImplementedError, "Inheriting class must implement"
46
+ end
47
+
48
+ private
49
+
50
+ def domain
51
+ CloudScrape.configuration.base_url
52
+ end
53
+
54
+ def api_key
55
+ CloudScrape.configuration.api_key
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,17 @@
1
+ class CloudScrape
2
+ class ExecutionDTO < DTO
3
+ def endpoint
4
+ "executions/#{id}/#{url}"
5
+ end
6
+
7
+ private
8
+
9
+ def id
10
+ options.fetch(:id)
11
+ end
12
+
13
+ def url
14
+ options.fetch(:url)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ require "cloud_scrape/execution_dto"
2
+ require "cloud_scrape/executions/get"
3
+ require "cloud_scrape/executions/result"
4
+
5
+ class CloudScrape
6
+ class Executions
7
+ def initialize(id:)
8
+ @id = id
9
+ end
10
+
11
+ def get
12
+ Get.new(response: dto("", :get))
13
+ end
14
+
15
+ def result
16
+ Result.new(response: dto("result", :get))
17
+ end
18
+
19
+ def remove
20
+ dto("", :delete)
21
+ end
22
+
23
+ def stop
24
+ dto("stop", :post)
25
+ end
26
+
27
+ def continue
28
+ dto("continue", :post)
29
+ end
30
+
31
+ private
32
+
33
+ def dto(url, method)
34
+ ExecutionDTO.for(id: @id, url: url, method: method)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,41 @@
1
+ class CloudScrape
2
+ class Executions
3
+ class Get
4
+ def initialize(response:)
5
+ @response = response
6
+ end
7
+
8
+ def queued?
9
+ %w(QUEUED).include?(state)
10
+ end
11
+
12
+ def pending?
13
+ %w(PENDING).include?(state)
14
+ end
15
+
16
+ def running?
17
+ %w(RUNNING).include?(state)
18
+ end
19
+
20
+ def failed?
21
+ %w(FAILED).include?(state)
22
+ end
23
+
24
+ def stopped?
25
+ %w(STOPPED).include?(state)
26
+ end
27
+
28
+ def ok?
29
+ %w(OK).include?(state)
30
+ end
31
+
32
+ private
33
+
34
+ attr_reader :response
35
+
36
+ def state
37
+ response.fetch(:state)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ class CloudScrape
2
+ class Executions
3
+ class Result
4
+ attr_reader :response
5
+
6
+ def initialize(response:)
7
+ @response = response
8
+ build
9
+ end
10
+
11
+ def build
12
+ as_hash.each(&define_method_for_header)
13
+ end
14
+
15
+ def as_hash
16
+ @as_hash ||= Hash[headers.zip(rows)]
17
+ end
18
+
19
+ private
20
+
21
+ def headers
22
+ response.fetch(:headers, [])
23
+ end
24
+
25
+ def rows
26
+ response.fetch(:rows, [[]]).flatten
27
+ end
28
+
29
+ def define_method_for_header
30
+ ->(key, value) { self.class.send(:define_method, key) { value } }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ class CloudScrape
2
+ class RunDTO < DTO
3
+ def endpoint
4
+ "runs/#{id}/#{url}?connect=#{connect}"
5
+ end
6
+
7
+ private
8
+
9
+ def id
10
+ options.fetch(:id)
11
+ end
12
+
13
+ def url
14
+ options.fetch(:url)
15
+ end
16
+
17
+ def connect
18
+ options.fetch(:connect)
19
+ end
20
+
21
+ def params
22
+ options.fetch(:input)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ require "cloud_scrape/run_dto"
2
+
3
+ class CloudScrape
4
+ class Runs
5
+ def initialize(id:)
6
+ @id = id
7
+ end
8
+
9
+ def execute(input: {}, connect: false)
10
+ RunDTO.for(
11
+ id: @id,
12
+ url: (input.empty? ? "execute" : "execute/inputs"),
13
+ input: input,
14
+ connect: connect,
15
+ method: :post
16
+ ).fetch(:_id)
17
+ end
18
+ end
19
+ end