# How CasaOS Handles File Upload Progress Tracking with the Progress Struct

> Discover how CasaOS tracks file uploads using the Progress struct. Learn how this custom struct wraps data streams, calculates completion, and reports UI progress for a seamless user experience.

- Repository: [IceWhale/CasaOS](https://github.com/IceWhaleTech/CasaOS)
- Tags: internals
- Published: 2026-06-26

---

**CasaOS tracks file uploads by wrapping the data stream in a custom `Progress` struct that implements `io.Writer`, calculating percentage completion on every write operation and invoking a callback to report progress to the UI.**

CasaOS (IceWhaleTech/CasaOS) provides a generic mechanism for real-time file upload progress tracking that works across local and cloud storage drivers. At the heart of this system lies the `Progress` struct defined in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go), which bridges the gap between raw byte streams and user-visible percentage indicators. This architecture allows any storage backend to report granular upload status without implementing driver-specific progress logic.

## The Core Architecture of the Progress Struct

### The UpdateProgress Callback Type

The foundation of CasaOS upload progress tracking is the `UpdateProgress` function type defined at approximately line 113 in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go). This callback accepts an integer representing the completion percentage.

```go
type UpdateProgress func(percentage int)

```

### Progress Struct Definition

The `Progress` struct encapsulates the total byte count, bytes written so far, and the callback function. Defined at lines 115-118 in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go), it maintains the state necessary to calculate completion percentages.

```go
type Progress struct {
    Total int64          // total size of the upload
    Done  int64          // bytes already written
    up    UpdateProgress // callback to report the current percent
}

```

## How the Progress Writer Calculates Upload Percentage

The `Progress` struct implements the standard `io.Writer` interface through its `Write` method (lines 121-125). Every time a chunk of bytes is written, the method updates the `Done` counter, computes the current percentage using floating-point division, and invokes the callback.

```go
func (p *Progress) Write(b []byte) (n int, err error) {
    n = len(b)
    p.Done += int64(n)
    p.up(int(float64(p.Done) / float64(p.Total) * 100))
    return
}

```

This implementation ensures that **CasaOS file upload progress tracking** remains accurate regardless of chunk size, as the percentage calculation occurs on every write operation.

## Creating Progress Trackers with the Factory Function

To instantiate a new progress tracker, CasaOS provides the `NewProgress` factory function at lines 128-133 in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go). This helper initializes the struct with the total file size and the update callback.

```go
func NewProgress(total int64, up UpdateProgress) *Progress {
    return &Progress{Total: total, up: up}
}

```

## Integration with Storage Drivers

### Driver Interface Requirements

Every storage driver in CasaOS implements a `Put` method that accepts an `UpdateProgress` argument, defined at lines 31-33 in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go). This standardizes progress reporting across all backends including local storage, Google Drive, and OneDrive.

```go
Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error

```

### Google Drive Implementation Example

The Google Drive driver ([`drivers/google_drive/drive.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/drivers/google_drive/drive.go)) demonstrates how drivers receive and utilize the progress callback. While the driver ultimately streams the file via `stream.GetReadCloser()` (lines 75-80), the caller can wrap the stream with a `Progress` writer before invoking `Put`, as shown in lines 31-33.

```go
func (d *GoogleDrive) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
    // ...
    req.SetHeader("Content-Length", strconv.FormatInt(stream.GetSize(), 10)).SetBody(stream.GetReadCloser())
    // ...
}

```

## Practical Usage Pattern for Real-Time Progress

When an API endpoint needs to expose real-time upload progress to a web UI, it creates a `Progress` object with the total file size, provides a callback that pushes the percentage over a websocket or SSE, and then copies the incoming data through that writer. The `io.Copy` call triggers `prog.Write`, which updates the progress percentage and invokes the UI callback.

```go
func uploadHandler(c echo.Context) error {
    // 1. read multipart file header
    fh, err := c.FormFile("file")
    if err != nil { return err }

    // 2. total size for progress tracking
    total := fh.Size

    // 3. create a Progress writer that forwards percent to the client
    prog := driver.NewProgress(total, func(p int) {
        // broadcast `p` to the front-end (e.g., via websocket)
        log.Printf("upload %d%% complete", p)
    })

    // 4. open the uploaded file (multipart part)
    src, err := fh.Open()
    if err != nil { return err }
    defer src.Close()

    // 5. copy through Progress – this fires the callback on every chunk
    if _, err = io.Copy(prog, src); err != nil {
        return err
    }

    return nil
}

```

### Chunked Upload Handling

CasaOS also provides a `FileUploadService` (see [`service/file_upload.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/file_upload.go), lines 16-80) that manages chunked uploads by storing each chunk on disk and assembling the final file. While this service handles chunk bookkeeping, it can wrap the incoming data stream with a `Progress` writer before writing each chunk to provide visual progress feedback to the user.

## Summary

- **CasaOS file upload progress tracking** relies on the `Progress` struct in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go) to wrap data streams and report completion percentages.
- The `Progress` struct implements `io.Writer` by updating a `Done` counter and invoking an `UpdateProgress` callback on every write operation (lines 121-125).
- Storage drivers receive progress callbacks through the standard `Put` method interface (lines 31-33), enabling consistent progress reporting across local and cloud backends.
- The `NewProgress` factory function (lines 128-133) creates ready-to-use progress trackers that calculate percentages using `Done/Total*100`.
- Handlers can stream uploads through the `Progress` writer using `io.Copy`, triggering real-time UI updates via websockets or SSE.

## Frequently Asked Questions

### What is the Progress struct in CasaOS?

The `Progress` struct is a custom writer defined in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go) (lines 115-118) that tracks how many bytes have been written during a file upload. It stores the total file size, the current bytes written (`Done`), and a callback function (`up`) that receives the completion percentage.

### How does CasaOS calculate upload percentage?

CasaOS calculates upload percentage in the `Write` method of the `Progress` struct (lines 121-125). After each write operation, it computes the percentage using the formula `int(float64(p.Done) / float64(p.Total) * 100)` and passes this integer to the `UpdateProgress` callback.

### Can CasaOS track progress for cloud storage uploads?

Yes, CasaOS supports progress tracking for cloud storage drivers including Google Drive, OneDrive, and others. The driver interface requires a `Put` method that accepts an `UpdateProgress` callback (lines 31-33 in [`internal/driver/driver.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/internal/driver/driver.go)), allowing the same `Progress` struct to report status regardless of whether the destination is local disk or remote cloud storage.

### How does the Progress struct integrate with chunked uploads?

While the `FileUploadService` ([`service/file_upload.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/file_upload.go), lines 16-80) manages the logic for storing and assembling upload chunks on disk, the `Progress` struct provides the visual feedback mechanism. The service can wrap each chunk's data stream with a `Progress` writer before saving it, ensuring users see continuous progress updates even when files are uploaded in multiple pieces.