hensei-api/app/services/summon_image_validator.rb

96 lines
2.6 KiB
Ruby

# frozen_string_literal: true
# Validates that a granblue_id has accessible images on the Granblue Fantasy game server.
# Used to verify that a summon ID is valid before creating a database record.
#
# @example Validate a summon ID
# validator = SummonImageValidator.new("2040001000")
# if validator.valid?
# puts validator.image_urls
# else
# puts validator.error_message
# end
class SummonImageValidator
BASE_URL = 'https://prd-game-a-granbluefantasy.akamaized.net/assets_en/img/sp/assets/summon'
SIZES = {
main: 'ls',
grid: 'party_sub',
square: 's'
}.freeze
attr_reader :granblue_id, :error_message, :image_urls
def initialize(granblue_id)
@granblue_id = granblue_id.to_s
@error_message = nil
@image_urls = {}
end
# Validates the granblue_id by checking if the main image is accessible.
#
# @return [Boolean] true if valid, false otherwise
def valid?
return invalid_format unless valid_format?
check_image_accessibility
end
# Checks if a summon with this granblue_id already exists in the database.
#
# @return [Boolean] true if exists, false otherwise
def exists_in_db?
Summon.exists?(granblue_id: @granblue_id)
end
private
def valid_format?
@granblue_id.present? && @granblue_id.match?(/^\d{10}$/)
end
def invalid_format
@error_message = 'Invalid granblue_id format. Must be a 10-digit number.'
false
end
def check_image_accessibility
# Summons use the raw granblue_id without variant suffix for base image
variant_id = @granblue_id
# Build image URLs for all sizes
SIZES.each do |size_name, directory|
url = "#{BASE_URL}/#{directory}/#{variant_id}.jpg"
@image_urls[size_name] = url
end
# Check if the main image is accessible via HEAD request
main_url = @image_urls[:main]
begin
uri = URI.parse(main_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.open_timeout = 5
http.read_timeout = 5
# Skip CRL verification in development (Akamai CDN can have CRL issues locally)
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if Rails.env.development?
request = Net::HTTP::Head.new(uri.request_uri)
response = http.request(request)
if response.code == '200'
true
else
@error_message = "No images found for this granblue_id (HTTP #{response.code})"
false
end
rescue Net::OpenTimeout, Net::ReadTimeout => e
@error_message = "Request timed out while validating image URL: #{e.message}"
false
rescue StandardError => e
@error_message = "Failed to validate image URL: #{e.message}"
false
end
end
end