Cargo installation
Add dilnaka 0.0.1 and Tokio to an async Rust application.
SDK library
Python, TypeScript, PHP, and Rust are live now. Each route documents the same Dilnaka upload lifecycle in the conventions of its own runtime.
Environment-driven setup, direct-to-S3 uploads, and the current Python reference implementation.
Node 18+ uploads, typed file helpers, and fetch injection for tests or custom runtimes.
Composer installation, PHP 8.1+, Guzzle transport, and the same Dilnaka file lifecycle.
Async Rust uploads, strongly typed responses, multipart streaming, and structured errors.
Documentation
Async Rust SDK for uploading files through the Dilnaka Upload API. It resolves explicit builder settings before environment variables and .env, requests a presigned URL, uploads directly to S3, and completes the file record.
Add dilnaka 0.0.1 and Tokio to an async Rust application.
One async call selects a single presigned PUT or a streamed multipart transfer based on file size.
Typed file models and structured errors sit on the same backend contract used by every Dilnaka SDK.
Setup
Add the Dilnaka client and a Tokio runtime to your application. The SDK requires Rust 1.85 or newer.
Published on crates.io/crates/dilnaka as version 0.0.1.
[dependencies]
dilnaka = "0.0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
Configuration
The SDK only needs your API key in .env. It is built specifically for Dilnaka Storage.
DILNAKA_API_KEY=dlk_dev_your_api_key_here
DILNAKA_TIMEOUT=60
DILNAKA_MULTIPART_THRESHOLD=104857600
DILNAKA_UPLOAD_TIMEOUT=300
Optional: set DILNAKA_TIMEOUT (default 60) for JSON API request timeouts in seconds.
Set DILNAKA_MULTIPART_THRESHOLD (default 104857600, or 100 MB) to control when uploads switch to the multipart flow.
Set DILNAKA_UPLOAD_TIMEOUT (default 300) for each S3 transfer request in seconds.
Core flow
Create the client from environment settings and upload a local path with one awaited call.
use dilnaka::Dilnaka;
#[tokio::main]
async fn main() -> dilnaka::Result<()> {
let client = Dilnaka::from_env()?;
let uploaded = client.upload("./test-upload.txt").await?;
println!("{} {} {}", uploaded.id, uploaded.key, uploaded.status);
Ok(())
}
Alternate setup
Use the builder when configuration belongs in code. Explicit values take precedence over environment values.
use std::time::Duration;
use dilnaka::{Dilnaka, UploadOptions};
let client = Dilnaka::builder()
.api_key("dlk_live_your_api_key_here")
.timeout(Duration::from_secs(90))
.upload_timeout(Duration::from_secs(600))
.build()?;
let uploaded = client
.upload_with_options(
"./avatar.png",
UploadOptions::default().folder("avatars"),
)
.await?;
Large files
Files at or above 100 MB automatically use a resumable multipart upload. The SDK reads one part at a time, retries failed parts with newly presigned URLs, and performs a best-effort abort when transfer or completion fails.
use std::time::Duration;
use dilnaka::UploadOptions;
let options = UploadOptions::default()
.folder("courses")
.multipart_threshold(25 * 1024 * 1024)
.upload_timeout(Duration::from_secs(600));
let uploaded = client
.upload_with_options("./course-bundle.zip", options)
.await?;
For manual orchestration, use create_multipart_upload, presign_multipart_parts, complete_multipart_upload, and abort_multipart_upload.
Read access
Request a temporary download or preview URL. Pass None to use the backend default expiry.
let access = client
.get_file_access_url("file_123", Some(600))
.await?;
println!("{}", access.url);
API surface
Dilnaka::new(api_key)?
Dilnaka::from_env()?
Dilnaka::builder().api_key(...).timeout(...).build()?
client.upload(path).await?
client.upload_with_options(path, options).await?
client.create_presigned_upload(&options).await?
client.complete_upload(file_id).await?
client.create_multipart_upload(&options).await?
client.presign_multipart_parts(file_id, &part_numbers).await?
client.complete_multipart_upload(file_id, &parts).await?
client.abort_multipart_upload(file_id).await?
client.list_files().await?
client.get_file(file_id).await?
client.get_file_access_url(file_id, Some(600)).await?
client.delete_file(file_id).await?
Backend contract
The Rust SDK uses the same endpoints and bearer-token scopes as the Python, TypeScript, and PHP clients.
POST /v1/uploads/presign
POST /v1/uploads/complete
POST /v1/uploads/multipart/create
POST /v1/uploads/multipart/parts
POST /v1/uploads/multipart/complete
POST /v1/uploads/multipart/abort
GET /v1/files
GET /v1/files/{file_id}
GET /v1/files/{file_id}/access-url?expiresIn=600
DELETE /v1/files/{file_id}
Typed responses
id, key, status, original_name, content_type, size, optional public URL, ETag, and metadata.
file_id, url, optional expires_in, and is_temporary.
File identifiers, upload URL, HTTP method, expiry, and required S3 headers.
Upload identifiers plus the server-selected part size, part count, bucket, and expiry.
Failures
Every operation returns dilnaka::Result<T>. API errors preserve the HTTP status and raw response body.
match client.get_file("file_123").await {
Ok(file) => println!("{}", file.key),
Err(error) => {
eprintln!("{error}");
eprintln!("status: {:?}", error.status_code());
}
}
Security
The SDK never receives AWS credentials. It receives short-lived presigned upload URLs from Dilnaka and sends file bytes directly to S3.
The client redacts the API key from its configuration's debug output. Your backend remains responsible for key validation, scopes, file validation, metadata persistence, completion verification, and read URL expiration.