class UploadIO

Overview

UploadIO supports chunked uploads with a built-in progress callback and provides upload cancellation through either a callback or direct method call.

require "upload_io"
require "http/client"

file = File.open("/path/to/file")
size = file.size
uploaded_total = 0

upload_io = UploadIO.new(file, 4096, ->(uploaded_chunk : Int32) {
  uploaded_total += uploaded_chunk
  puts "Uploaded: #{uploaded_total} / #{size} bytes"
})

headers = HTTP::Headers{
  "Content-Type"   => "application/octet-stream",
  "Content-Length" => size.to_s,
}

response = HTTP::Client.post("http://example.com/upload", headers: headers, body: upload_io)
puts "Upload complete! Response: #{response.status_code}"

Defined in:

upload_io.cr

Constant Summary

CHUNK_SIZE = 4096
VERSION = {{ (`shards version /srv/crystaldoc.info/github-mamantoha-upload_io-v0.6.0/src`).chomp.stringify }}

Constructors

Instance Method Summary

Constructor Detail

def self.new(data : HTTP::Client::BodyType, chunk_size : Int32, on_progress : Proc(Int32, Nil) | Nil = nil, should_cancel : Proc(Bool) | Nil = nil, *, max_speed : Int64 | Nil = nil) #

Creates a new UploadIO with given arguments.

  • data - the upload data source
  • chunk_size - the maximum size of each chunk for Bytes and String data
  • #on_progress - optional callback to track progress
  • #should_cancel - optional callback to control upload cancellation
  • #max_speed - optional maximum upload speed in bytes per second

[View source]
def self.new(data : HTTP::Client::BodyType, chunk_size : Int32 = CHUNK_SIZE, &block : self -> ) #

Creates a new UploadIO with a block for configuration.

file = File.open("/path/to/file")
size = file.size
uploaded_total = 0

upload_io = UploadIO.new(file) do |io|
  io.on_progress ->(uploaded_chunk : Int32) do
    uploaded_total += uploaded_chunk
    puts "Uploaded: #{uploaded_total} / #{size} bytes"
  end

  io.should_cancel -> { uploaded_total >= size / 2 }
  io.max_speed = 125_000 # 1 Mbps
end

response = HTTP::Client.post("http://example.com/upload", body: upload_io)

[View source]
def self.new(data : HTTP::Client::BodyType, on_progress : Proc(Int32, Nil) | Nil = nil, should_cancel : Proc(Bool) | Nil = nil, *, max_speed : Int64 | Nil = nil) #

[View source]

Instance Method Detail

def cancel #

Cancels the upload process. After calling this method:

  • Subsequent reads will return 0 bytes
  • If the data source is an IO, it will be closed
  • The upload cannot be resumed

[View source]
def cancelled? : Bool #

Returns true if the upload has been cancelled


[View source]
def max_speed : Int64 | Nil #

Maximum upload speed in bytes per second. If nil, no speed limit is applied.


[View source]
def max_speed=(max_speed : Int64 | Nil) #

[View source]
def on_progress(on_progress : Proc(Int32, Nil)) #

Optional callback function that receives the size of each uploaded chunk.

file = File.open("/path/to/file")
size = file.size
uploaded_total = 0

upload_io = UploadIO.new(file)
upload_io.on_progress ->(uploaded_chunk : Int32) do
  uploaded_total += uploaded_chunk
  puts "Uploaded: #{uploaded_total} / #{size} bytes"
end

response = HTTP::Client.post("http://example.com/upload", body: upload_io)

[View source]
def pause #

Pauses the upload process. While paused:

  • Subsequent reads will block until #resume is called
  • The upload can be resumed using the #resume method

[View source]
def paused? : Bool #

Returns true if the upload is currently paused


[View source]
def read(slice : Bytes) : Int32 #

Reads the next chunk of data and copies it into the provided buffer.

This method is called automatically by HTTP::Client when sending data. It reads up to chunk_size bytes for Bytes and String data. Wrapped IO sources are read directly into the provided buffer, so their read size is controlled by the caller's buffer size.

Returns the number of bytes that will be sent to the server (not the total send bytes), which is 0 if and only if there is no more data to reads (so checking for 0 is the way to detect end of file).

Since UploadIO only provides data to HTTP::Client, we can only track the amount of data read and not the actual bytes transmitted to the server.


[View source]
def resume #

Resumes a paused upload. After calling this method:

  • Subsequent reads will continue from where they left off

[View source]
def rewind #
Description copied from class IO

Rewinds this IO. By default this method raises, but including types may implement it.


[View source]
def should_cancel(should_cancel : Proc(Bool)) #

Optional callback function that determines if the upload should be cancelled. Return true to cancel the upload.

file = File.open("/path/to/file")
start_time = Time.instant

upload_io = UploadIO.new(file)
# Stop upload after 5 seconds
upload_io.should_cancel -> { (Time.instant - start_time).total_seconds > 5 }

response = HTTP::Client.post("http://example.com/upload", body: upload_io)

[View source]
def uploaded : Int64 #

Tracks the total bytes uploaded so far.


[View source]
def write(slice : Bytes) : Nil #

Required method by IO but not used in UploadIO.

UploadIO is read-only, so #write does nothing.


[View source]