# `DocuSign.FileDownloader`
[🔗](https://github.com/neilberkman/docusign_elixir/blob/v3.4.0/lib/docusign/file_downloader.ex#L1)

File download utilities for DocuSign documents and attachments.

This module provides functionality for downloading files from DocuSign APIs
with automatic filename extraction from Content-Disposition headers,
flexible file handling options, and support for multiple file formats.

## Features

- Automatic filename extraction from Content-Disposition headers
- Configurable temporary file management
- Multiple download strategies (to file, to memory, streaming)
- Support for various file formats (PDF, HTML, images, etc.)
- Filename sanitization and collision handling
- Content-Type detection and validation

## Usage

    # Download to a temporary file
    {:ok, path} = DocuSign.FileDownloader.download_to_temp(conn, url)

    # Download to a specific path
    {:ok, path} = DocuSign.FileDownloader.download_to_file(conn, url, "/path/to/file.pdf")

    # Download to memory
    {:ok, {content, filename, content_type}} = DocuSign.FileDownloader.download_to_memory(conn, url)

    # Download with options
    {:ok, result} = DocuSign.FileDownloader.download(conn, url,
      strategy: :file,
      filename: "custom_name.pdf",
      temp_dir: "/custom/temp"
    )

## Configuration

You can configure the file downloader options:

    config :docusign, :file_downloader,
      max_filename_length: 255,
      sanitize_filenames: true,
      allowed_content_types: ~w(application/pdf text/html image/png image/jpeg),
      track_temp_files: true

# `download_options`

```elixir
@type download_options() :: [
  strategy: download_strategy(),
  filename: String.t() | nil,
  temp_options: keyword() | nil,
  max_size: non_neg_integer() | nil,
  validate_content_type: boolean(),
  overwrite: boolean()
]
```

# `download_result`

```elixir
@type download_result() ::
  {:ok, binary()}
  | {:ok, {binary(), String.t(), String.t()}}
  | {:ok, String.t()}
  | {:error, term()}
```

# `download_strategy`

```elixir
@type download_strategy() :: :file | :memory | :temp | :stream
```

# `cleanup_temp_files`

```elixir
@spec cleanup_temp_files() :: :ok
```

Cleans up tracked temporary files.

This function calls `Temp.cleanup/0` to remove all tracked temporary files.
Useful for manual cleanup before process exit.

## Examples

    DocuSign.FileDownloader.cleanup_temp_files()

# `download`

```elixir
@spec download(DocuSign.Connection.t(), String.t(), download_options()) ::
  download_result()
```

Downloads a file from the given URL using the DocuSign connection.

## Options

- `:strategy` - Download strategy (`:file`, `:memory`, `:temp`, `:stream`)
- `:filename` - Custom filename (overrides Content-Disposition)
- `:temp_options` - Options passed to `Temp` library for temporary files
- `:max_size` - Maximum file size in bytes
- `:validate_content_type` - Whether to validate content type
- `:overwrite` - Whether to overwrite existing files

## Returns

- `{:ok, content}` when strategy is `:memory`
- `{:ok, {content, filename, content_type}}` when strategy is `:memory` with metadata
- `{:ok, filepath}` when strategy is `:file` or `:temp`
- `{:error, reason}` on failure

## Examples

    # Download envelope document to temporary file
    {:ok, temp_path} = DocuSign.FileDownloader.download(conn,
      "/v2.1/accounts/123/envelopes/456/documents/1")

    # Download with custom temp options
    {:ok, path} = DocuSign.FileDownloader.download(conn, url,
      temp_options: [prefix: "contract", suffix: ".pdf"])

    # Download to memory for processing
    {:ok, {content, filename, content_type}} = DocuSign.FileDownloader.download(conn, url,
      strategy: :memory)

# `download_to_file`

```elixir
@spec download_to_file(DocuSign.Connection.t(), String.t(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, term()}
```

Downloads a file to a specific path.

Returns `{:ok, filepath}` on success.

## Examples

    {:ok, path} = DocuSign.FileDownloader.download_to_file(conn, url, "/path/to/save/document.pdf")

# `download_to_memory`

```elixir
@spec download_to_memory(DocuSign.Connection.t(), String.t(), keyword()) ::
  {:ok, {binary(), String.t(), String.t()}} | {:error, term()}
```

Downloads a file to memory.

Returns `{:ok, {content, filename, content_type}}` on success.

## Examples

    {:ok, {pdf_content, "document.pdf", "application/pdf"}} =
      DocuSign.FileDownloader.download_to_memory(conn, url)

# `download_to_temp`

```elixir
@spec download_to_temp(DocuSign.Connection.t(), String.t(), keyword()) ::
  {:ok, String.t()} | {:error, term()}
```

Downloads a file to a temporary location.

Returns `{:ok, filepath}` on success, where filepath is the path to the
temporary file. The caller is responsible for cleaning up the temporary file.

## Examples

    {:ok, temp_path} = DocuSign.FileDownloader.download_to_temp(conn, url)
    content = File.read!(temp_path)
    File.rm!(temp_path)  # Clean up

# `ensure_unique_filename`

```elixir
@spec ensure_unique_filename(String.t()) :: String.t()
```

Generates a unique filename by appending a number if the file already exists.

## Examples

    # If document.pdf exists, returns document_1.pdf
    # If document_1.pdf also exists, returns document_2.pdf, etc.
    DocuSign.FileDownloader.ensure_unique_filename("/path/to/document.pdf")

# `extract_filename_from_header`

```elixir
@spec extract_filename_from_header(String.t()) ::
  {:ok, String.t()} | {:error, :no_filename}
```

Extracts filename from Content-Disposition header.

## Examples

    iex> DocuSign.FileDownloader.extract_filename_from_header("attachment; filename=document.pdf")
    {:ok, "document.pdf"}

    iex> DocuSign.FileDownloader.extract_filename_from_header("attachment; filename*=UTF-8''document%20name.pdf")
    {:ok, "document name.pdf"}

    iex> DocuSign.FileDownloader.extract_filename_from_header("attachment")
    {:error, :no_filename}

# `sanitize_filename`

```elixir
@spec sanitize_filename(String.t()) :: String.t()
```

Sanitizes a filename by removing invalid characters and path components.

## Examples

    iex> DocuSign.FileDownloader.sanitize_filename("../../malicious.pdf")
    "malicious.pdf"

    iex> DocuSign.FileDownloader.sanitize_filename("file<>:"|?*.pdf")
    "file.pdf"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
