Class: Pangea::Utilities::IpDiscovery

Inherits:
Object
  • Object
show all
Defined in:
lib/pangea/utilities/ip_discovery.rb

Overview

IP Discovery service for finding public IP addresses

Constant Summary collapse

SERVICES =

Service definitions with parsers

[
  {
    name: 'ipify',
    url: 'https://api.ipify.org?format=json',
    parser: ->(body) { JSON.parse(body)['ip'] }
  },
  {
    name: 'ipinfo',
    url: 'https://ipinfo.io/ip',
    parser: ->(body) { body.strip }
  },
  {
    name: 'aws_checkip',
    url: 'https://checkip.amazonaws.com',
    parser: ->(body) { body.strip }
  },
  {
    name: 'ifconfig_me',
    url: 'https://ifconfig.me',
    parser: ->(body) { body.strip }
  }
].freeze
IP_REGEX =
/\A(?:\d{1,3}\.){3}\d{1,3}\z/.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(timeout: 5, logger: nil) ⇒ IpDiscovery

Returns a new instance of IpDiscovery.



52
53
54
55
# File 'lib/pangea/utilities/ip_discovery.rb', line 52

def initialize(timeout: 5, logger: nil)
  @timeout = timeout
  @logger = logger || Logger.new(STDOUT)
end

Instance Attribute Details

#loggerObject (readonly)

Returns the value of attribute logger.



50
51
52
# File 'lib/pangea/utilities/ip_discovery.rb', line 50

def logger
  @logger
end

#timeoutObject (readonly)

Returns the value of attribute timeout.



50
51
52
# File 'lib/pangea/utilities/ip_discovery.rb', line 50

def timeout
  @timeout
end

Instance Method Details

#discoverObject

Discover public IP address from multiple services

Raises:



58
59
60
61
62
63
64
65
# File 'lib/pangea/utilities/ip_discovery.rb', line 58

def discover
  SERVICES.each do |service|
    ip = try_service(service)
    return ip if ip
  end
  
  raise DiscoveryError, "Failed to discover public IP from any service"
end

#try_service(service) ⇒ Object

Try a single service with timeout



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/pangea/utilities/ip_discovery.rb', line 68

def try_service(service)
  Timeout.timeout(@timeout) do
    uri = URI(service[:url])
    response = Net::HTTP.get_response(uri)
    
    if response.is_a?(Net::HTTPSuccess)
      ip = service[:parser].call(response.body)
      
      if validate_ip_format(ip)
        @logger&.info("[IpDiscovery] Discovered public IP from #{service[:name]}: #{ip}")
        return ip
      else
        @logger&.warn("[IpDiscovery] Invalid IP format from #{service[:name]}: #{ip}")
      end
    else
      @logger&.warn("[IpDiscovery] HTTP error from #{service[:name]}: #{response.code}")
    end
  end
  
  nil
rescue Timeout::Error
  @logger&.warn("[IpDiscovery] Timeout querying #{service[:name]}")
  nil
rescue StandardError => e
  @logger&.warn("[IpDiscovery] Error querying #{service[:name]}: #{e.message}")
  nil
end