Services

S3 links

Signed upload and download links for S3, R2, MinIO and the like: browsers move the bytes, not your server.

Version 1.0.0 · 3 functions · 2 crates

#uploads#storage#s3#r2#files

Functions

What use s3.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use s3_download_url, s3_upload_url from s3 (Quillo 0.6).

s3_download_url(key: str, seconds: int) → stror an error

A link that downloads key for seconds: put it in an <a> or an <img>.

s3_upload_url(key: str, seconds: int) → stror an error

A link the browser PUTs a file to, as key, for seconds: fetch(url, { method: "PUT", body: file }).

s3_delete_url(key: str, seconds: int) → stror an error

A link that deletes key, for seconds: call it from the server with http.request.

Get it

$ quillo install s3               # s3.qwer into this folder$ quillo install s3 --example     # and its example, s3.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/s3.qwer$ curl -O https://quillolang.org/plugins/files/s3.qwe

Then, in your program, all of it or only what you call:

main.qwe
use s3.qweruse s3_download_url, s3_upload_url from s3      // Quillo 0.6: only these

It uses these crates, which cargo fetches the first time the plugin is built:

[dependencies]
rusty-s3 = "0.5"url = "2"

Example

s3.qwe
// Avatars uploaded by the browser straight to a bucket.////   S3_ENDPOINT=https://<account>.r2.cloudflarestorage.com S3_REGION=auto S3_BUCKET=avatars \//   S3_ACCESS_KEY=... S3_SECRET_KEY=... quillo run s3.qwe      then open http://localhost:8080/upload-linkuse "s3.qwer"route GET /upload-link {    let key = `avatars/${uuid()}.jpg`    { key, put: s3_upload_url(key, 300)?, get: s3_download_url(key, 3600)? }}
$ quillo run s3.qwe$ curl 'localhost:8080/upload-link'

Source

s3.qwer
//! Signed links to S3, Cloudflare R2, MinIO, Backblaze or DigitalOcean Spaces: browsers upload and download directly, the server never holds the bytes.//! version: 1.0.0//!//! [dependencies]//! rusty-s3 = "0.5"//! url = "2"use rusty_s3::{Bucket, Credentials, S3Action, UrlStyle};use std::time::Duration;fn env(name: &str) -> Result<String, String> {    std::env::var(name).map_err(|_| format!("{} is not set (S3_ENDPOINT, S3_REGION, S3_BUCKET, S3_ACCESS_KEY, S3_SECRET_KEY)", name))}fn bucket() -> Result<(Bucket, Credentials), String> {    let endpoint = url::Url::parse(&env("S3_ENDPOINT")?).map_err(|e| e.to_string())?;    let style = if std::env::var("S3_VIRTUAL_HOSTS").is_ok() { UrlStyle::VirtualHost } else { UrlStyle::Path };    let b = Bucket::new(endpoint, style, env("S3_BUCKET")?, env("S3_REGION")?).map_err(|e| e.to_string())?;    Ok((b, Credentials::new(env("S3_ACCESS_KEY")?, env("S3_SECRET_KEY")?)))}fn secs(s: i64) -> Duration {    Duration::from_secs(s.clamp(1, 7 * 24 * 3600) as u64)}/// A link that downloads `key` for `seconds`: put it in an `<a>` or an `<img>`.pub fn s3_download_url(key: &str, seconds: i64) -> Result<String, String> {    let (b, c) = bucket()?;    Ok(b.get_object(Some(&c), key).sign(secs(seconds)).to_string())}/// A link the browser PUTs a file to, as `key`, for `seconds`: `fetch(url, { method: "PUT", body: file })`.pub fn s3_upload_url(key: &str, seconds: i64) -> Result<String, String> {    let (b, c) = bucket()?;    Ok(b.put_object(Some(&c), key).sign(secs(seconds)).to_string())}/// A link that deletes `key`, for `seconds`: call it from the server with `http.request`.pub fn s3_delete_url(key: &str, seconds: i64) -> Result<String, String> {    let (b, c) = bucket()?;    Ok(b.delete_object(Some(&c), key).sign(secs(seconds)).to_string())}
Azure Blob SAS links azure_sas.qwer · 1.0.0Azure Blob Storage SAS links signed from the account key: browsers upload and download blobs directly, with the permissions and lifetime you choose.uploadsstorageazurefilessigning8 views · 7 downloadsDropbox dropbox.qwer · 1.0.0Dropbox over its HTTP API: uploads in one request or by upload sessions that recover a lost answer, downloads, folders listed with cursors, shared links made or found again, a refresh token traded for short-lived tokens, and 429s waited out as Retry-After says.filesstorageoauthuploads2 views · 9 downloadsGoogle Cloud Storage links gcs_sign.qwer · 1.0.0Google Cloud Storage V4 signed URLs from a service-account key: browsers upload and download directly, signed without a network call.uploadsstoragegcpfilessigning6 views · 8 downloadsContent-addressed files blob_store.qwer · 1.0.0Uploads kept in a folder by their SHA-256, as Git keeps objects: the same file stored once, names pointing at contents, atomic writes, every file verified against its hash, and contents nothing names swept away.filesstorageuploadsdedupeintegrity6 views · 7 downloadsGoogle Drive google_drive.qwer · 1.0.0Google Drive's v3 API: files listed with quoted queries and page tokens, uploads by multipart or a resumable session that recovers a lost piece, downloads and Google Doc exports, sharing, and service-account JWT sign-in.filesgoogleuploadsservice-account2 views · 6 downloads3D models models_3d.qwer · 1.0.0STL and OBJ models read: triangles, size, volume, surface area and whether the mesh is closed, a 3D-print quote by weight, and OBJ turned into binary STL.filesuploadsprintingcalculators6 views · 7 downloads
Thread
88Useful? Like it, or add to its thread below.

Thread 0 posts

On S3 links: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.