11# frozen_string_literal: true
22
3+ require 'net/http'
4+ require 'uri'
5+ require 'fileutils'
6+
37module Mindee
48 module Input
59 module Source
@@ -13,6 +17,110 @@ def initialize(url)
1317
1418 @url = url
1519 end
20+
21+ # Downloads the file from the URL and saves it to the specified path.
22+ #
23+ # @param path [String] Path to save the file to.
24+ # @param filename [String, nil] Optional name to give to the file.
25+ # @param username [String, nil] Optional username for authentication.
26+ # @param password [String, nil] Optional password for authentication.
27+ # @param token [String, nil] Optional token for JWT-based authentication.
28+ # @param max_redirects [Integer] Maximum amount of redirects to follow.
29+ # @return [String] The full path of the saved file.
30+ def save_to_file ( path , filename : nil , username : nil , password : nil , token : nil , max_redirects : 3 )
31+ response_body = fetch_file_content ( username : username , password : password , token : token ,
32+ max_redirects : max_redirects )
33+
34+ filename = fill_filename ( filename )
35+
36+ full_path = File . join ( path . chomp ( '/' ) , filename )
37+ File . write ( full_path , response_body )
38+
39+ full_path
40+ end
41+
42+ # Downloads the file from the url, and returns a BytesInputSource wrapper object for it.
43+ #
44+ # @param filename [String, nil] Optional name to give to the file.
45+ # @param username [String, nil] Optional username for authentication.
46+ # @param password [String, nil] Optional password for authentication.
47+ # @param token [String, nil] Optional token for JWT-based authentication.
48+ # @param max_redirects [Integer] Maximum amount of redirects to follow.
49+ # @return [BytesInputSource] The full path of the saved file.
50+ def as_local_input_source ( filename : nil , username : nil , password : nil , token : nil , max_redirects : 3 )
51+ filename = fill_filename ( filename )
52+ response_body = fetch_file_content ( username : username , password : password , token : token ,
53+ max_redirects : max_redirects )
54+ bytes = StringIO . new ( response_body )
55+
56+ BytesInputSource . new ( bytes . read , filename )
57+ end
58+
59+ # Fetches the file content from the URL.
60+ #
61+ # @param username [String, nil] Optional username for authentication.
62+ # @param password [String, nil] Optional password for authentication.
63+ # @param token [String, nil] Optional token for JWT-based authentication.
64+ # @param max_redirects [Integer] Maximum amount of redirects to follow.
65+ # @return [String] The downloaded file content.
66+ def fetch_file_content ( username : nil , password : nil , token : nil , max_redirects : 3 )
67+ uri = URI . parse ( @url )
68+ request = Net ::HTTP ::Get . new ( uri )
69+
70+ request [ 'Authorization' ] = "Bearer #{ token } " if token
71+ request . basic_auth ( username , password ) if username && password
72+
73+ response = make_request ( uri , request , max_redirects )
74+ if response . code . to_i > 299
75+ raise "Failed to download file: HTTP status code #{ response . code } "
76+ elsif response . code . to_i < 200
77+ raise "Failed to download file: Invalid response code #{ response . code } ."
78+ end
79+
80+ response . body
81+ end
82+
83+ private
84+
85+ def extract_filename_from_url ( uri )
86+ filename = File . basename ( uri . path )
87+ filename . empty? ? '' : filename
88+ end
89+
90+ def fill_filename ( filename )
91+ filename ||= extract_filename_from_url ( URI . parse ( @url ) )
92+ if filename . empty? || File . extname ( filename ) . empty?
93+ filename = generate_file_name ( extension : get_file_extension ( filename ) )
94+ end
95+ filename
96+ end
97+
98+ def make_request ( uri , request , max_redirects )
99+ Net ::HTTP . start ( uri . hostname , uri . port , use_ssl : true ) do |http |
100+ response = http . request ( request )
101+ if response . is_a? ( Net ::HTTPRedirection ) && max_redirects . positive?
102+ location = response [ 'location' ]
103+ raise 'No location in redirection header.' if location . nil?
104+
105+ new_uri = URI . parse ( location )
106+ request = Net ::HTTP ::Get . new ( new_uri )
107+ make_request ( new_uri , request , max_redirects - 1 )
108+ else
109+ response
110+ end
111+ end
112+ end
113+
114+ def get_file_extension ( filename )
115+ ext = File . extname ( filename )
116+ ext . empty? ? nil : ext . downcase
117+ end
118+
119+ def generate_file_name ( extension : nil )
120+ extension ||= '.tmp'
121+ random_string = Array . new ( 8 ) { rand ( 36 ) . to_s ( 36 ) } . join
122+ "mindee_temp_#{ Time . now . strftime ( '%Y-%m-%d_%H-%M-%S' ) } _#{ random_string } #{ extension } "
123+ end
16124 end
17125 end
18126 end
0 commit comments