Module: Lemans::Environments::Daytona::FaradayTransfer

Defined in:
lib/lemans/environments/daytona/faraday_transfer.rb

Overview

Reroutes the SDK's streaming file transfers from typhoeus/libcurl to Faraday over Net::HTTP: pure-Ruby I/O is immune to the libcurl GC race that segfaults the VM under concurrent transfers. Only the FileTransfer entry points move — the generated JSON clients stay on typhoeus. Opt-in via .apply!

Defined Under Namespace

Modules: Transfers Classes: UploadIO

Class Method Summary collapse

Class Method Details

.apply!Object



17
18
19
# File 'lib/lemans/environments/daytona/faraday_transfer.rb', line 17

def self.apply!
  ::Daytona::FileTransfer.singleton_class.prepend(Transfers)
end

.download(api_client:, remote_path:, timeout:, on_progress:, cancel_event:, &block) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/lemans/environments/daytona/faraday_transfer.rb', line 62

def download(api_client:, remote_path:, timeout:, on_progress:, cancel_event:, &block)
  parser = nil
  bytes_received = 0
  sink = proc do |chunk|
    raise ::Daytona::Sdk::Error, "Download cancelled: #{remote_path}" if cancel_event&.set?

    if on_progress
      bytes_received += chunk.bytesize
      on_progress.call(::Daytona::DownloadProgress.new(bytes_received:, total_bytes: parser&.part_total_bytes))
    end
    block.call(chunk)
  end
  parser = ::Daytona::MultipartDownloadStreamParser.new(&sink)

  error_body = String.new.b
  response = perform_download(api_client, remote_path, timeout, parser, error_body, cancel_event)

  raise ::Daytona::Sdk::Error, "Download cancelled: #{remote_path}" if cancel_event&.set?
  raise ::Daytona::Sdk::Error, parser.error_message if parser.error_message
  raise ::Daytona::Sdk::Error, "HTTP #{response.status}: #{error_body}" unless response.success?

  parser.finish!
  ::Daytona::FileTransfer.assert_download_length!(parser, remote_path)
  nil
rescue Faraday::TimeoutError
  raise ::Daytona::Sdk::Error, "Download timed out: #{remote_path}"
rescue Faraday::Error => e
  raise ::Daytona::Sdk::Error, "Download failed for #{remote_path}: #{e.message}"
end

.upload(api_client:, remote_path:, source:, timeout:, on_progress:, cancel_event:) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/lemans/environments/daytona/faraday_transfer.rb', line 92

def upload(api_client:, remote_path:, source:, timeout:, on_progress:, cancel_event:)
  ::Daytona::FileTransfer.with_upload_file(source, cancel_event, remote_path) do |upload_path|
    expected_bytes = File.size(upload_path)
    response = File.open(upload_path, "rb") do |file|
      io = UploadIO.new(file, remote_path, on_progress:, cancel_event:)
      perform_upload(api_client, remote_path, timeout, io)
    end
    raise ::Daytona::Sdk::Error, "HTTP #{response.status}: #{response.body}" unless response.success?

    verify_upload(response.body, remote_path, expected_bytes)
  end
rescue Faraday::TimeoutError
  raise ::Daytona::Sdk::Error, "Upload timed out: #{remote_path}"
rescue Faraday::Error => e
  raise ::Daytona::Sdk::Error, "Upload failed for #{remote_path}: #{e.message}"
end