@@ -82,7 +82,9 @@ def post(path:, params: {}, headers: {}, request_options: {})
8282 # @see https://uploadcare.com/api-refs/upload-api/#operation/baseUpload
8383 def upload_file ( file :, request_options : { } , **options )
8484 Uploadcare ::Result . capture do
85- raise ArgumentError , 'file must be a File or IO object' unless file . respond_to? ( :read )
85+ unless file . respond_to? ( :read ) && file . respond_to? ( :path )
86+ raise ArgumentError , 'file must be a File or IO object with #read and #path'
87+ end
8688
8789 params = build_upload_params ( file , options )
8890 Uploadcare ::Result . unwrap ( post ( path : 'base/' , params : params , request_options : request_options ) )
@@ -302,7 +304,9 @@ def multipart_complete(uuid:, request_options: {})
302304 # end
303305 def multipart_upload ( file :, request_options : { } , **options , &)
304306 Uploadcare ::Result . capture do
305- raise ArgumentError , 'file must be a File or IO object' unless file . respond_to? ( :read )
307+ unless file . respond_to? ( :read ) && file . respond_to? ( :path )
308+ raise ArgumentError , 'file must be a File or IO object with #read and #path'
309+ end
306310
307311 file_size = file . respond_to? ( :size ) ? file . size : ::File . size ( file . path )
308312 filename = file . respond_to? ( :original_filename ) ? file . original_filename : ::File . basename ( file . path )
@@ -621,64 +625,49 @@ def upload_parts_parallel(file, presigned_urls, part_size, threads, &block)
621625 mutex = Mutex . new
622626 queue = Queue . new
623627
624- # Read all parts into memory (for thread safety)
625- parts = [ ]
626- presigned_urls . each_with_index do |presigned_url , index |
627- file . seek ( index * part_size )
628- part_data = file . read ( part_size )
629-
630- break if part_data . nil? || part_data . empty?
631-
632- parts << { url : presigned_url , data : part_data , index : index }
633- end
634-
635- # Add parts to queue
636- parts . each { |part | queue << part }
637-
638- # Add sentinel values (nil) to signal workers to stop
628+ presigned_urls . each_with_index { |url , index | queue << [ url , index ] }
639629 threads . times { queue << nil }
640630
641- # Track errors from threads
642631 errors = [ ]
632+ file_path = file . path
643633
644- # Create worker threads
645634 workers = threads . times . map do
646635 Thread . new do
647- loop do
648- part = begin
649- queue . pop ( true )
650- rescue ThreadError
651- # Queue is empty, exit cleanly
652- break
653- end
636+ worker_file = ::File . open ( file_path , 'rb' )
637+ begin
638+ loop do
639+ job = begin
640+ queue . pop
641+ rescue ThreadError
642+ break
643+ end
644+ break if job . nil?
645+
646+ presigned_url , index = job
647+ offset = index * part_size
648+ break if offset >= total_size
654649
655- # Sentinel value signals termination
656- break if part . nil?
650+ worker_file . seek ( offset )
651+ part_data = worker_file . read ( part_size )
652+ break if part_data . nil? || part_data . empty?
657653
658- begin
659- Uploadcare ::Result . unwrap ( multipart_upload_part ( presigned_url : part [ :url ] , part_data : part [ :data ] ) )
654+ Uploadcare ::Result . unwrap ( multipart_upload_part ( presigned_url : presigned_url , part_data : part_data ) )
660655
661656 mutex . synchronize do
662- uploaded += part [ :data ] . bytesize
663- block &.call ( { uploaded : uploaded , total : total_size , part : part [ : index] + 1 ,
664- total_parts : parts . length } )
657+ uploaded += part_data . bytesize
658+ block &.call ( { uploaded : uploaded , total : total_size , part : index + 1 ,
659+ total_parts : presigned_urls . length } )
665660 end
666- rescue StandardError => e
667- mutex . synchronize { errors << e }
668- raise # Re-raise to terminate thread
669661 end
662+ rescue StandardError => e
663+ mutex . synchronize { errors << e }
664+ ensure
665+ worker_file . close
670666 end
671667 end
672668 end
673669
674- # Wait for all threads to complete and collect any uncaught exceptions
675- workers . each do |worker |
676- worker . join
677- rescue StandardError => e
678- mutex . synchronize { errors << e unless errors . include? ( e ) }
679- end
680-
681- # Check for errors and raise the first one
670+ workers . each ( &:join )
682671 raise errors . first if errors . any?
683672 end
684673
0 commit comments