proxied 0.2.1 → 0.2.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 259fa06faa16224529c74da60047158116d019a7017972887cd9c91228f854b4
4
- data.tar.gz: a9a83e6416cc5db560e4b3d90129eabc7e0c55aeea4150bba155f482957091bb
3
+ metadata.gz: 670ca19a9100f67ddca208cad0c90c729d47f79148739657e7f031f5ce732df1
4
+ data.tar.gz: 4adedbbef5ab9765610080ccd34a6df00a6158f37728af7f059c7190b71e68cc
5
5
  SHA512:
6
- metadata.gz: 764f5d70013bf48d88064cf6bd90d5c29759f75b6672f26e4d443f3bebc7e49e18f71d4bd1dbd7628cfcbd3c9bd178027a2327d3f68732cf96b09a2be8234537
7
- data.tar.gz: 1a79de19edcfb1bdef83ff8d110489ab43501732dbb04c38f6a312e382f69fbc63142c6a60fc1de9e081628952c5a3984bfd55e8e4373dbf4e99e0c0f5ec28c2
6
+ metadata.gz: 7de2420827e224b1e4d23cc595714a0a15b526d94d68481efb3b008122090cde99f0ef7a1820f14b8fdb70473ab6f0cf1de0c5cf093ac160bc0f3e0c16c68656
7
+ data.tar.gz: 2eda880c9e511393a3e0224d6863a31e85bb3eb7804a66623446aa7ae6a171bbe46245e2416786f586c091a009c61a75cf95e2aa18f85774ccfcf0ce8b23811a
@@ -3,19 +3,23 @@
3
3
  class ProxiedCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
4
4
  def change
5
5
  create_table :<%= table_name %><%= primary_key_type %> do |t|
6
- t.string :host, null: false, index: true
7
- t.string :ip_address, null: false, index: true
8
- t.integer :port, null: false, index: true
9
- t.string :username
10
- t.string :password
6
+ t.string :host, null: false, index: true
7
+ t.string :ip_address, null: false, index: true
8
+ t.integer :port, null: false, index: true
11
9
 
12
- t.string :protocol, null: false, default: 'http', index: true
13
- t.string :proxy_type, null: false, default: 'public', index: true
14
- t.string :category
10
+ t.string :username
11
+ t.string :password
12
+ t.string :auth_mode, null: false, default: 'credentials', index: true
15
13
 
16
- t.string :country, index: true
17
- t.string :city, index: true
14
+ t.string :protocol, null: false, default: 'http', index: true
15
+ t.string :proxy_type, null: false, default: 'public', index: true
16
+ t.string :category
18
17
 
18
+ t.string :country, index: true
19
+ t.string :city, index: true
20
+
21
+ t.boolean :checkable, null: false, default: true, index: true
22
+ t.boolean :asyncable, null: false, default: true, index: true
19
23
  t.datetime :last_checked_at, index: true
20
24
 
21
25
  t.boolean :valid_proxy, null: false, default: false, index: true
@@ -27,6 +27,7 @@ module Mongoid
27
27
 
28
28
  field :username, type: String
29
29
  field :password, type: String
30
+ field :auth_mode, type: String, default: :credentials
30
31
 
31
32
  field :protocol, type: String, default: :http
32
33
  field :proxy_type, type: String, default: :public
@@ -39,6 +40,9 @@ module Mongoid
39
40
  field :successful_attempts, type: Integer, default: 0
40
41
  field :failed_attempts, type: Integer, default: 0
41
42
 
43
+ field :checkable, type: Boolean, default: true
44
+ field :asyncable, type: Boolean, default: true
45
+
42
46
  field :last_checked_at, type: DateTime
43
47
 
44
48
  # Validations
@@ -1,21 +1,38 @@
1
1
  ::Proxied.configure do |config|
2
- config.proxy_class = "<%= class_name.camelize.to_s %>" # Must be set to the ActiveRecord or Mongoid model that will be used for managing proxies
2
+ # The ActiveRecord or Mongoid model that will be used for managing proxies - Must be set otherwise the gem won't work!
3
+ config.proxy_class = "<%= class_name.camelize.to_s %>"
3
4
 
5
+ # The minimum successful attempts and maximum failed attempts before a proxy shouldn't be considered valid anymore
4
6
  config.minimum_successful_attempts = 1
5
7
  config.maximum_failed_attempts = 10
6
8
 
9
+ # The queue that Sidekiq/ActiveJob will use to check proxies
7
10
  config.job_queue = :proxies
8
11
 
12
+ # Log settings - if Rails is available it will log to the Rails log, otherwise just puts
13
+ config.logger = defined?(Rails) ? -> (message) { Rails.logger.info(message) } : -> (message) { puts(message) }
14
+ config.log_level = :info
15
+
16
+ # The settings below are for configuring the proxy checker service
17
+ config.faraday = {
18
+ adapter: :net_http,
19
+ user_agent: -> { "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.1 Safari/605.1.15" },
20
+ verbose: false
21
+ }
22
+
23
+ # If you're using Typhoeus as adapter, consider setting the following setting either here or in a separate config/initializer:
24
+ # Ethon.logger = Logger.new(nil)
25
+
9
26
  config.http_test = {
10
27
  url: "http://ipinfo.io/ip",
11
- evaluate: -> (proxy, response) { response.to_s.strip.eql?(proxy.ip_address.strip) },
12
- timeout: 10,
28
+ evaluate: -> (proxy, response) { !(response&.to_s&.strip&.downcase =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i).nil? },
29
+ timeout: 30,
13
30
  }
14
31
 
15
32
  config.socks_test = {
16
33
  hostname: "whois.verisign-grs.com",
17
34
  port: 43,
18
35
  query: "=google.com",
19
- timeout: 10
36
+ timeout: 30
20
37
  }
21
38
  end
@@ -13,11 +13,12 @@ module Proxied
13
13
 
14
14
  def check_proxies(protocol: :all, proxy_type: :all, update: true)
15
15
  proxies = ::Proxied.configuration.proxy_class.constantize.should_be_checked(
16
- protocol: protocol,
17
- proxy_type: proxy_type,
18
- date: Time.now,
19
- limit: self.limit,
20
- maximum_failed_attempts: self.maximum_failed_attempts
16
+ mode: self.mode.to_sym,
17
+ protocol: protocol,
18
+ proxy_type: proxy_type,
19
+ date: Time.now,
20
+ limit: self.limit,
21
+ maximum_failed_attempts: self.maximum_failed_attempts
21
22
  )
22
23
 
23
24
  if proxies&.any?
@@ -68,18 +69,19 @@ module Proxied
68
69
  end
69
70
 
70
71
  def check_http_proxy(proxy, test_url: ::Proxied.configuration.http_test[:url], evaluate: ::Proxied.configuration.http_test[:evaluate], timeout: ::Proxied.configuration.http_test[:timeout], update: true)
71
- ::Proxied::Logger.log "#{Time.now}: Fetching #{::Proxied.configuration.http_test[:url]} with proxy #{proxy.proxy_address}."
72
-
73
- response = request(test_url, proxy, options: {timeout: timeout})
74
- valid_proxy = evaluate.call(proxy, response)
72
+ ::Proxied::Logger.log "#{Time.now}: Fetching #{::Proxied.configuration.http_test[:url]} with proxy #{proxy.proxy_address} (#{proxy.ip_address})."
73
+
74
+ response = request(test_url, proxy, options: {timeout: timeout})
75
+ valid_proxy = evaluate.call(proxy, response)
75
76
 
76
- update_proxy(proxy, valid_proxy) if update
77
+ update_proxy(proxy, valid_proxy, response) if update
77
78
 
78
79
  return valid_proxy
79
80
  end
80
81
 
81
- def update_proxy(proxy, valid)
82
- ::Proxied::Logger.log "#{Time.now}: Proxy #{proxy.proxy_address} is #{valid ? "working" : "not working"}!"
82
+ def update_proxy(proxy, valid, response = nil)
83
+ ::Proxied::Logger.info "#{Time.now}: Proxy #{proxy.proxy_address} (#{proxy.ip_address}) is #{valid ? "working" : "not working"}!"
84
+ ::Proxied::Logger.debug "Response: #{response}" if !valid && response
83
85
 
84
86
  successful_attempts = proxy.successful_attempts || 0
85
87
  failed_attempts = proxy.failed_attempts || 0
@@ -103,22 +105,22 @@ module Proxied
103
105
  def request(url, proxy, options: {})
104
106
  response = nil
105
107
 
106
- user_agent = options.fetch(:user_agent, ::Proxied.configuration.faraday.fetch(:user_agent, nil))
108
+ user_agent = options.fetch(:user_agent, ::Proxied.configuration.faraday.fetch(:user_agent, nil)&.call)
107
109
  timeout = options.fetch(:timeout, ::Proxied.configuration.http_test[:timeout])
108
110
 
109
111
  begin
110
112
  response = ::Faraday.new(url: url) do |builder|
111
113
  builder.headers["User-Agent"] = user_agent if !user_agent.to_s.empty?
112
114
  builder.options[:timeout] = timeout if timeout
113
- builder.proxy = proxy.proxy_options_for_faraday
115
+ builder.proxy = proxy.proxy_options_for_faraday
114
116
  builder.response :logger if ::Proxied.configuration.verbose_faraday?
115
117
  builder.adapter ::Proxied.configuration.faraday.fetch(:adapter, :net_http)
116
- end.get&.body
118
+ end
117
119
  rescue Faraday::Error => e
118
120
  ::Proxied::Logger.log "Exception occured while trying to check proxy #{proxy.proxy_address}. Error Class: #{e.class}. Error Message: #{e.message}"
119
121
  end
120
122
 
121
- return response
123
+ return response.get&.body
122
124
  end
123
125
 
124
126
  end
@@ -2,39 +2,47 @@ module Proxied
2
2
  class Configuration
3
3
  attr_accessor :proxy_class
4
4
  attr_accessor :minimum_successful_attempts, :maximum_failed_attempts
5
+ attr_accessor :job_queue
6
+ attr_accessor :logger, :log_level
5
7
  attr_accessor :faraday
6
8
  attr_accessor :http_test, :socks_test
7
- attr_accessor :job_queue
8
- attr_accessor :logger
9
+
10
+
9
11
 
10
- def initialize
11
- self.proxy_class = nil # Must be set to the ActiveRecord or Mongoid model that will be used for managing proxies
12
+ def initialize
13
+ # The ActiveRecord or Mongoid model that will be used for managing proxies - Must be set otherwise the gem won't work!
14
+ self.proxy_class = nil
12
15
 
16
+ # The minimum successful attempts and maximum failed attempts before a proxy shouldn't be considered valid anymore
13
17
  self.minimum_successful_attempts = 1
14
18
  self.maximum_failed_attempts = 10
15
19
 
20
+ # The queue that Sidekiq/ActiveJob will use to check proxies
21
+ self.job_queue = :proxies
22
+
23
+ # Log settings - if Rails is available it will log to the Rails log, otherwise just puts
24
+ self.logger = defined?(Rails) ? -> (message) { Rails.logger.info(message) } : -> (message) { puts(message) }
25
+ self.log_level = :info
26
+
27
+ # The settings below are for configuring the proxy checker service
16
28
  self.faraday = {
17
29
  adapter: :net_http,
18
- user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.1 Safari/605.1.15",
30
+ user_agent: -> { "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.1 Safari/605.1.15" },
19
31
  verbose: false
20
32
  }
21
33
 
22
34
  self.http_test = {
23
35
  url: "http://ipinfo.io/ip",
24
- evaluate: -> (proxy, response) { response.to_s.strip.eql?(proxy.ip_address.strip) },
25
- timeout: 10,
36
+ evaluate: -> (proxy, response) { !(response&.to_s&.strip&.downcase =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i).nil? },
37
+ timeout: 30,
26
38
  }
27
39
 
28
40
  self.socks_test = {
29
41
  hostname: "whois.verisign-grs.com",
30
42
  port: 43,
31
43
  query: "=google.com",
32
- timeout: 10
44
+ timeout: 30
33
45
  }
34
-
35
- self.job_queue = :proxies
36
-
37
- self.logger = defined?(Rails) ? -> (message) { Rails.logger.info(message) } : -> (message) { puts(message) }
38
46
  end
39
47
 
40
48
  def verbose_faraday?
@@ -21,19 +21,22 @@ module Proxied
21
21
  ip_address = proxy_item.fetch(:ip_address, host)&.to_s&.strip&.downcase
22
22
 
23
23
  query = {
24
- host: host,
25
- port: port
24
+ host: host,
25
+ port: port
26
26
  }
27
27
 
28
28
  parsed = {
29
- ip_address: ip_address,
30
- protocol: proxy_item.fetch(:protocol, "http")&.to_s&.strip&.downcase,
31
- proxy_type: proxy_item.fetch(:type, :private)&.to_s&.strip,
32
- category: proxy_item.fetch(:category, nil)&.to_s&.strip&.downcase,
33
- country: proxy_item.fetch(:country, nil)&.to_s&.strip&.upcase,
34
- city: proxy_item.fetch(:city, nil)&.to_s&.strip&.downcase,
35
- username: proxy_item.fetch(:username, nil)&.to_s&.strip,
36
- password: proxy_item.fetch(:password, nil)&.to_s&.strip
29
+ ip_address: ip_address,
30
+ protocol: proxy_item.fetch(:protocol, "http")&.to_s&.strip&.downcase,
31
+ proxy_type: proxy_item.fetch(:type, :private)&.to_s&.strip,
32
+ category: proxy_item.fetch(:category, nil)&.to_s&.strip&.downcase,
33
+ country: proxy_item.fetch(:country, nil)&.to_s&.strip&.upcase,
34
+ city: proxy_item.fetch(:city, nil)&.to_s&.strip&.downcase,
35
+ username: proxy_item.fetch(:username, nil)&.to_s&.strip,
36
+ password: proxy_item.fetch(:password, nil)&.to_s&.strip,
37
+ auth_mode: proxy_item.fetch(:auth_mode, :credentials)&.to_s&.strip,
38
+ checkable: proxy_item.fetch(:checkable, true),
39
+ asyncable: proxy_item.fetch(:asyncable, true),
37
40
  }.merge(query)
38
41
 
39
42
  proxy = ::Proxied.configuration.proxy_class.constantize.where(query).first || ::Proxied.configuration.proxy_class.constantize.new
@@ -1,9 +1,19 @@
1
1
  module Proxied
2
2
  class Logger
3
+ class << self
4
+
5
+ def info(message)
6
+ log(message) if ::Proxied.configuration.log_level.to_sym.eql?(:info)
7
+ end
3
8
 
4
- def self.log(message)
5
- ::Proxied.configuration.logger.call(message)
6
- end
9
+ def debug(message)
10
+ log(message) if ::Proxied.configuration.log_level.to_sym.eql?(:debug)
11
+ end
12
+
13
+ def log(message)
14
+ ::Proxied.configuration.logger.call(message)
15
+ end
7
16
 
17
+ end
8
18
  end
9
19
  end
@@ -11,8 +11,10 @@ module Proxied
11
11
  end
12
12
 
13
13
  module ClassMethods
14
- def should_be_checked(protocol: :all, proxy_type: :all, date: Time.now, limit: 10, maximum_failed_attempts: 10)
15
- proxies = get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
14
+ def should_be_checked(mode: :synchronous, protocol: :all, proxy_type: :all, category: nil, date: Time.now, limit: nil, maximum_failed_attempts: 10)
15
+ proxies = get_proxies(protocol: protocol, proxy_type: proxy_type, category: category)
16
+ proxies = proxies.where(checkable: true)
17
+ proxies = proxies.where(asyncable: true) if mode.to_sym.eql?(:asynchronous)
16
18
 
17
19
  proxies = proxies.any_of(
18
20
  {:last_checked_at.exists => false},
@@ -27,16 +29,15 @@ module Proxied
27
29
  )
28
30
 
29
31
  proxies = proxies.order_by([[:valid_proxy, :asc], [:failed_attempts, :asc], [:last_checked_at, :asc]])
30
- proxies = proxies.limit(limit)
32
+ proxies = proxies.limit(limit) if limit && !limit.zero?
31
33
 
32
34
  return proxies
33
35
  end
34
36
 
35
37
  def get_valid_proxies(protocol: :all, proxy_type: :all, category: nil, maximum_failed_attempts: nil)
36
- proxies = get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
38
+ proxies = get_proxies(protocol: protocol, proxy_type: proxy_type, category: category)
37
39
  proxies = proxies.where(valid_proxy: true)
38
40
  proxies = proxies.where(:failed_attempts.lte => maximum_failed_attempts) if maximum_failed_attempts
39
- proxies = proxies.where(category: category) unless category.to_s.empty?
40
41
  end
41
42
 
42
43
  def get_random_proxy(protocol: :all, proxy_type: :all, category: nil, maximum_failed_attempts: nil, retries: 3)
@@ -2,10 +2,11 @@ module Proxied
2
2
  module Shared
3
3
 
4
4
  module ClassMethods
5
- def get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
5
+ def get_proxies(protocol: :all, proxy_type: :all, category: nil)
6
6
  proxies = ::Proxy.where(nil)
7
7
  proxies = proxies.where(protocol: protocol) if (protocol && !protocol.downcase.to_sym.eql?(:all))
8
8
  proxies = proxies.where(proxy_type: proxy_type) if (proxy_type && !proxy_type.downcase.to_sym.eql?(:all))
9
+ proxies = proxies.where(category: category) unless category.to_s.empty?
9
10
 
10
11
  return proxies
11
12
  end
@@ -34,7 +35,7 @@ module Proxied
34
35
  end
35
36
 
36
37
  def proxy_options_for_faraday
37
- ::Proxied::Utilities.proxy_options_for_faraday(host: self.host, port: self.port, username: self.username, password: self.password)
38
+ ::Proxied::Utilities.proxy_options_for_faraday(host: self.host, port: self.port, username: self.username, password: self.password, auth_mode: self.auth_mode)
38
39
  end
39
40
 
40
41
  def proxy_switcher_import_format
@@ -11,21 +11,22 @@ module Proxied
11
11
  end
12
12
 
13
13
  module ClassMethods
14
- def should_be_checked(protocol: :all, proxy_type: :all, date: Time.now, limit: 10, maximum_failed_attempts: 10)
15
- proxies = get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
14
+ def should_be_checked(mode: :synchronous, protocol: :all, proxy_type: :all, category: nil, date: Time.now, limit: nil, maximum_failed_attempts: 10)
15
+ proxies = get_proxies(protocol: protocol, proxy_type: proxy_type, category: category)
16
+ proxies = proxies.where(checkable: true)
17
+ proxies = proxies.where(asyncable: true) if mode.to_sym.eql?(:asynchronous)
16
18
  proxies = proxies.where(["(last_checked_at IS NULL OR last_checked_at < ?)", date])
17
19
  proxies = proxies.where(["failed_attempts <= ?", maximum_failed_attempts])
18
20
  proxies = proxies.order("valid_proxy ASC, failed_attempts ASC, last_checked_at ASC")
19
- proxies = proxies.limit(limit)
21
+ proxies = proxies.limit(limit) if limit && !limit.zero?
20
22
 
21
23
  return proxies
22
24
  end
23
25
 
24
26
  def get_valid_proxies(protocol: :all, proxy_type: :all, category: nil, maximum_failed_attempts: nil)
25
- proxies = get_proxies_for_protocol_and_proxy_type(protocol, proxy_type)
27
+ proxies = get_proxies(protocol: protocol, proxy_type: proxy_type, category: category)
26
28
  proxies = proxies.where(["valid_proxy = ? AND last_checked_at IS NOT NULL", true])
27
29
  proxies = proxies.where(["failed_attempts <= ?", maximum_failed_attempts]) if maximum_failed_attempts
28
- proxies = proxies.where(category: category) unless category.to_s.empty?
29
30
 
30
31
  return proxies
31
32
  end
@@ -45,7 +46,7 @@ module Proxied
45
46
  "RAND() DESC"
46
47
  end
47
48
 
48
- proxies = proxies.order(order_clause)
49
+ proxies = proxies.order(Arel.sql(order_clause))
49
50
 
50
51
  proxy = nil
51
52
 
@@ -1,11 +1,11 @@
1
1
  module Proxied
2
2
  class Utilities
3
-
4
3
  class << self
5
4
 
6
- def format_proxy_address(host:, port: 80, include_http: false)
5
+ def format_proxy_address(host:, port: 80, username: nil, password: nil, include_http: false)
7
6
  address = "#{host.strip}:#{port}"
8
- address = "http://#{address}" if include_http && !address.start_with?("http://")
7
+ address = "#{format_proxy_credentials(username, password)}@#{address}" if !username.to_s.empty? && !password.to_s.empty?
8
+ address = (include_http && !address.start_with?("http://")) ? "http://#{address}" : address
9
9
 
10
10
  return address
11
11
  end
@@ -23,12 +23,18 @@ module Proxied
23
23
  return credentials
24
24
  end
25
25
 
26
- def proxy_options_for_faraday(host:, port: 80, username: nil, password: nil)
26
+ def proxy_options_for_faraday(host:, port: 80, username: nil, password: nil, auth_mode: :credentials)
27
27
  proxy_options = {}
28
-
29
- proxy_options[:uri] = format_proxy_address(host: host, port: port, include_http: true)
30
- proxy_options[:user] = username if !username.to_s.empty?
31
- proxy_options[:password] = password if !password.to_s.empty?
28
+ username = CGI::escape(username)
29
+ password = CGI::escape(password)
30
+
31
+ options = {host: host, port: port, include_http: true}
32
+ options[:username] = username if !username.to_s.empty? && auth_mode&.to_sym&.eql?(:basic_auth)
33
+ options[:password] = password if !password.to_s.empty? && auth_mode&.to_sym&.eql?(:basic_auth)
34
+
35
+ proxy_options[:uri] = format_proxy_address(options)
36
+ proxy_options[:user] = username if !username.to_s.empty? && auth_mode&.to_sym&.eql?(:credentials)
37
+ proxy_options[:password] = password if !password.to_s.empty? && auth_mode&.to_sym&.eql?(:credentials)
32
38
 
33
39
  return proxy_options
34
40
  end
@@ -51,6 +57,5 @@ module Proxied
51
57
  end
52
58
 
53
59
  end
54
-
55
60
  end
56
61
  end
@@ -1,3 +1,3 @@
1
1
  module Proxied
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -5,8 +5,7 @@ namespace :proxied do
5
5
  checker = ::Proxied::Checker.new(mode: args.mode.to_sym, maximum_failed_attempts: args.maximum_failed_attempts.to_i)
6
6
  checker.check_proxies(
7
7
  protocol: args.protocol.to_sym,
8
- proxy_type: args.proxy_type.to_sym,
9
-
8
+ proxy_type: args.proxy_type.to_sym,
10
9
  )
11
10
  end
12
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: proxied
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian