Module: Daytona::Sdk::FileDownloadPatch

Defined in:
lib/daytona/sdk/file_download_patch.rb

Class Method Summary collapse

Class Method Details

.apply!(api_client_class, api_error_class) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/daytona/sdk/file_download_patch.rb', line 31

def self.apply!(api_client_class, api_error_class)
  api_client_class.class_eval do
    define_method(:download_file) do |request, &block|
      tempfile = nil
      encoding = nil
      stream_to_tempfile = false
      error_body = String.new.b
      @_daytona_error_body = nil

      request.on_headers do |response|
        stream_to_tempfile = response.code && response.code >= 200 && response.code < 300
        next unless stream_to_tempfile

        content_disposition = response.headers['Content-Disposition']
        if content_disposition && content_disposition =~ /filename=/i
          filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
          prefix = sanitize_filename(filename)
        else
          prefix = 'download-'
        end
        prefix += '-' unless prefix.end_with?('-')
        encoding = response.body.encoding
        tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding)
      end

      request.on_body do |chunk|
        if stream_to_tempfile
          chunk.force_encoding(encoding)
          tempfile.write(chunk)
        else
          error_body << chunk.b
        end
      end

      request.on_complete do
        if stream_to_tempfile
          if tempfile.nil?
            raise api_error_class.new(
              "Failed to create the tempfile based on the HTTP response from the server: #{request.inspect}"
            )
          end
          tempfile.close
          @config.logger.info(
            "Temp file written to #{tempfile.path}, please copy the file to a proper folder " \
            "with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file " \
            'will be deleted automatically with GC. It\'s also recommended to delete the temp file ' \
            'explicitly with `tempfile.delete`'
          )
          block&.call(tempfile)
        else
          @_daytona_error_body = error_body unless error_body.empty?
        end
      end
    end

    alias_method :_daytona_orig_call_api, :call_api

    define_method(:call_api) do |http_method, path, opts = {}|
      _daytona_orig_call_api(http_method, path, opts)
    rescue api_error_class => e
      if opts[:return_type] == 'File' && @_daytona_error_body && !@_daytona_error_body.empty?
        new_err = api_error_class.new(
          code: e.code,
          response_headers: e.response_headers,
          response_body: @_daytona_error_body
        )
        @_daytona_error_body = nil
        raise new_err, e.message
      end
      raise
    ensure
      @_daytona_error_body = nil
    end
  end
end