Rustypaste: простий та швидкий спосіб ділитися файлами

12.09.2025 6 хвилин Автор: D2-R2

У цій статті автор від першої особи ділиться власним досвідом створення сервісу для обміну файлами на Rust. Він згадує, як колись використовував IRC, де не було простого способу надсилати зображення чи документи, і пояснює, чому вирішив написати свій власний мінімалістичний інструмент rustypaste. Це сервіс, який дозволяє завантажувати файли, скорочувати посилання, створювати одноразові URL та задавати термін дії. Автор крок за кроком показує історію проєкту, його функції та розгортання у хмарі через Shuttle.rs, щоб зробити сервіс публічно доступним. Стаття написана у формі особистої розповіді, що робить її живою та цікавою навіть для тих, хто лише знайомиться з технологіями.

Хмарний обмін файлами без зайвого коду

 rustypaste » — це власний мінімальний сервіс завантаження/pastebin файлів, написаний на Rust. У цій публікації розповімо про його функції та історію розгортання на shuttle.rs, щоб зробити його загальнодоступним для безкоштовного використання.

Історія обміну файлами

Щоб правильно передати ідею, що лежить в основі обміну файлами, мені потрібно розповісти вам історію.

На зорі інтернету спілкування було простішим і, природно, менш безпечним. Однією з речей, якою люди користувалися, був всемогутній Internet Relay Chat (IRC), відома система чату, яка використовується й сьогодні деякими проектами. Колись люди створювали там канали та насолоджувалися незахищеним, менш цензурованим та ніби анонімним спілкуванням. Сьогодні ті часи деякі люди, включаючи мене, вважають золотою ерою інтернету. Все було так мирно, і можна було відчути запах запиленого повітря, що долинає від старого вентилятора ПК, який ледве працює на Windows XP з процесором Intel Pentium 4. *зітхає* Щасливі часи.

Ви не могли ділитися зображеннями в IRC. Принаймні, це було не так просто, оскільки IRC-клієнти були переважно текстовими та розроблені для запуску в терміналі (автор тут говорить про BitchX). Звичайно, це не було так просто та зручно, як сучасні програми для чату, і ми не можемо цього очікувати. Але думаю, що це все ще Cheff’s KISS, що взагалі таке підтримка обміну файлами?

Вона вимагає зберігання файлів десь та їх передачі одержувачу. Є так багато речей, які слід враховувати, такі як обмеження на завантаження, виявлення оголеної людини (якщо вам це важливо), конфіденційність, збереження файлів, додаткові витрати на сервер, дисковий простір тощо. Коротше кажучи, обмін файлами — це РОЗДУМ ! Описувати друзям, як створити кольчужну броню в Minecraft за допомогою виключно текстових повідомлень замість надсилання скріншоту, набагато КРАЩЕ. Або зачекайте, ми можемо використовувати ASCII-зображення, о так, це теж можливо. Правда ж?

На IRC не було простої підтримки обміну файлами, тому людям доводилося вигадувати власні рішення, іншими словами, власні сервери завантаження. За час  роботи в IRC я ​​зустрічав багатьох користувачів, які використовують посилання, подібні до наведеного нижче, лише для обміну файлами/зображеннями:

  • https://paste.xinu.at/jHKy

  • https://0x0.st/H8hSa.png

У певному сенсі, у сучасному світі робити це здається зайвим і насправді складнішим, ніж просто натискати 3 кнопки на інтерфейсі.

Технології — це, перш за все, контроль . Вважаю, що це особливо актуально сьогодні, оскільки кожен куточок людського мозку легко підкорюється технологіями. Ми глибоко інтегровані з цим світом, і в ситуації, коли ми його не контролюємо, він контролює нас. Кліше, але правда.

У випадку обміну файлами, наявність власного (власного хостингу) сервісу для завантаження ваших файлів – це просто контроль над тим, що ви надаєте цьому віртуальному світу. Те, чим ви хочете поділитися, є там, якщо ви цього хочете, і це там є за обраних вами обставин. Можливо, файли будуть завантажуватися із зовнішнього диска вашого домашнього сервера. Можливо, їх термін дії закінчиться через 2 години. Можливо, ви хочете побачити, хто перейшов за посиланням. Все зводиться до володіння вашими даними.

Якщо врахувати ці моменти, то стає зрозуміло, що недостатні умови часів IRC виявили ідеальне рішення для обміну файлами, що доповнює ідею про те, що централізація — це погано. Досить іронічно, що обмеження IRC призвели до появи самостійно розміщеного обміну файлами.

Спільнота IRC завжди приваблювала користувачів, навіть тих, хто долучився до неї порівняно нещодавно. Спершу для обміну файлами активно використовувались публічні сервіси, однак поступово виникла потреба у власному самохостинговому рішенні. Це привело до створення поста під назвою «Розкрутіть свій власний сервіс хостингу файлів без дурниць з 0x0», опублікованого два роки тому.

Тривалий час як базове рішення застосовувався 0x0, але згодом виникла необхідність перенесення на інший сервер. Переналаштовувати систему було незручно, та й сам факт того, що вона написана на Python, не додавав ентузіазму. Саме тоді з’явилась ідея розробити власний сервіс Pastebin, але вже з використанням мови програмування Rust, яка забезпечує високу швидкість роботи та безпечне управління пам’яттю.

Блискавично швидкий обмін файлами

rustypaste— це мінімальний та простий сервіс завантаження, написаний на Rust та реалізований за допомогою веб-фреймворку Actix. Я обрав Actix тоді, оскільки це був найбільш підходящий фреймворк з точки зору безпеки, продуктивності та простоти. Як постійний користувач rustypasteвже майже 2 роки, можу сказати, що він перебуває у стабільному стані та має купу функцій, що підтримують розширене налаштування.

Найпростіший спосіб взаємодії із rustypasteсервером – це використання , curlале ви також можете скористатися інструментом командного рядка під назвою, rpasteякий написаний на Rust.

 Інструмент командного рядка : https://github.com/orhun/rustypaste-cli

Usage:
    rpaste [options] <file(s)>

Options:
    -h, --help          prints help information
    -v, --version       prints version information
    -V, --server-version
                        retrieves the server version
    -o, --oneshot       generates one shot links
    -p, --pretty        prettifies the output
    -c, --config CONFIG sets the configuration file
    -s, --server SERVER sets the address of the rustypaste server
    -a, --auth TOKEN    sets the authentication token
    -u, --url URL       sets the URL to shorten
    -r, --remote URL    sets the remote URL for uploading
    -e, --expire TIME   sets the expiration time for the link

Ось список функцій разом із прикладами:

Завантажити файл

curl -F "[email protected]" https://rustypaste.shuttleapp.rs

rpaste ferris.txt

Скорочення URL-адреси

curl -F "url=https://example.com/some/long/url" https://rustypaste.shuttleapp.rs

rpaste -u https://example.com/some/long/url

Завантажити файл з URL-адреси

curl -F "remote=https://example.com/file.png" https://rustypaste.shuttleapp.rs

rpaste -r https://example.com/file.png

Термін дії файлу закінчується через 10 хвилин (також працює для URL-адрес)

curl -F "[email protected]" -H "expire:10min" https://rustypaste.shuttleapp.rs

rpaste -e 10min ferris.txt

Видалити файл після перегляду один раз

curl -F "[email protected]" https://rustypaste.shuttleapp.rs

rpaste -o ferris.txt

Автентифікуватися на сервері

curl -F "[email protected]" -H "Authorization: <auth_token>" https://rustypaste.shuttleapp.rs

rpaste -a "<auth_token>" ferris.txt(ви також можете використовувати файл конфігурації)

Для налаштування rustypasteвам потрібен лише один файл конфігурації. Файл за замовчуванням можна переглянути в репозиторії GitHub ( config.toml) .

Ось деякі речі, які ви можете налаштувати та змінити:

  • Випадкові назви файлів: Кличка домашньої тварини ( capital-mosquito.txt). Буквено-цифровий рядок ( yB84D2Dv.txt)

  • Типи MIME: Підтримує перевизначення та додавання до чорного списку. Підтримує примусове завантаження через?download=true

  • Підтримка вимкнення дублікатів завантажень

  • Автоматичне закінчення терміну дії + автоматичне видалення файлів

Якщо ви хочете розмістити власний rustypasteсервер, є кілька способів зробити це:

  • Запустіть єдиний бінарний файл (бажано встановлений з менеджера пакетів вашого дистрибутива). rustypasteдоступний у репозиторіях Arch Linux .

Використовуйте полегшений образ Docker

Або ж ви можете розгорнути його в хмарі!

Розгортання Rust-сервісів через Shuttle

Shuttle — це хмарна платформа для розробки, створена на Rust, яка дозволяє розгортати ваш застосунок, одночасно піклуючись про всю вашу інфраструктуру.

Shuttle отримує визначення інфраструктури з самого коду Rust за допомогою сигнатур функцій та анотацій . Це чудовий сервіс, який надзвичайно спрощує розгортання хмари та підтримує кілька фреймворків Rust, включаючи Actix. Крім того, ви можете керувати всім (розгортанням, моніторингом, управлінням ресурсами тощо) за допомогою однієї підкоманди cargo, запущеної cargo shuttleз командного рядка. Якщо врахувати все це, не дивно, що вони підтримуються YC😮

Наразі вони підтримують план хобі , який є практично безкоштовним, і ви можете звернутися до них, якщо наступні функції вам не підходять/недостатньо:

  • Необмежене розгортання

  • 150 тис. запитів на місяць

  • 500 МБ місця для зберігання бази даних

Цього цілком достатньо, rustypasteтому було вирішено скористатися Shuttle. 

Однак, у мене виникло одне питання щодо місця для зберігання. Тож я поставив його їм у Discord:

  • orhun : Як розгортання Shuttle зберігає файли? Чи завантажуються вони всередині ізольованого контейнера? Якщо так, то чи є якісь обмеження щодо дискового простору/пам’яті/процесора?

  • jonaro00 : Ваш проект працює в контейнері Docker, але запис у файлову систему не рекомендується, оскільки контейнер очищається під час цього cargo shuttle project restart(що ви робите під час оновлення версії Shuttle або коли щось ламається). Для постійного зберігання вам потрібно використовувати певну форму бази даних. Ви можете перевірити підтримувані бази даних у документації, але також є й інші в розробці.

  • orhun : Планую автоматично видаляти файли приблизно через годину. Чи рекомендуєте ви використовувати файлову систему в цьому випадку?

  • jonaro00 : Так, для такого випадку використання, мабуть, все працює добре.

Тим не менш, я не впевнений, чи є якісь обмеження дискового простору для розгортання Shuttle, і ми не змогли з’ясувати це в Discord, тому повідомте мені, якщо вам щось відомо про це. Тепер, коли у нас достатньо інформації про Shuttle, давайте розгорнемо проєкт Rust!

Почніть з встановлення cargo-shuttleта входу в систему:

$ cargo install cargo-shuttle

$ cargo shuttle login

Після цього кроку ви можете просто створити проєкт Rust, готовий до розгортання. Для створення шаблону Actix ми можемо виконати:

$ cargo shuttle init -t actix-web

Станом на зараз cargo-shuttleпідтримує такі шаблони: actix-webaxumpoempoiserocketsalvoserenitytide, , thrustertower,warp

Після створення проєкт виглядає приблизно так:

#!/usr/bin/env rust-script

//! [dependencies]
//! shuttle-runtime = "0.16.0"
//! actix-web = "4.3.1"
//! shuttle-actix-web = "0.16.0"
//! tokio = "1.28.1"

use actix_web::{get, web::ServiceConfig};
use shuttle_actix_web::ShuttleActixWeb;

// Define a route for the root path ("/") that returns a string "Hello World!"
#[get("/")]
async fn hello_world() -> &'static str {
    "Hello World!"
}

// The main entry point for the Shuttle runtime.
#[shuttle_runtime::main]
async fn actix_web(
) -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Send + Clone + 'static> {
    // Define a closure to configure the ServiceConfig of the HttpServer.
    let config = move |cfg: &mut ServiceConfig| {
        // Register the hello_world function as a service at the root path.
        cfg.service(hello_world);
    };

    // Wrap the closure in a ShuttleActixWeb object and return it.
    Ok(config.into())
}

Щоб перевірити це локально:

$ cargo shuttle run

Для розгортання це просто, як виконати таку команду:

$ cargo shuttle deploy

Потім ви можете переглянути розгортання за адресою <app>.shuttleapp.rsта переглянути журнали через cargo shuttle logs.

У випадку з rustypaste, у мене вже є застосунок Actix, тому мені потрібно трохи налаштувати його для розгортання. Головним чином, мені потрібно було змінити головну точку входу застосунку. Було вирішено додати прапорець функції під назвою “shuttle” для обгортання додаткових залежностей Shuttle та активації іншої точки входу. Я не чіпав решту коду, і це чудово, коли зусиль менше.

[features]
default = []
shuttle = [
  "dep:shuttle-actix-web",
  "dep:shuttle-runtime",
  "dep:shuttle-static-folder",
  "dep:tokio",
]

[dependencies]
# other dependencies
# ...
shuttle-actix-web = { version = "0.16.0", optional = true }
shuttle-runtime = { version = "0.16.0", optional = true }
shuttle-static-folder = { version = "0.16.0", optional = true }
tokio = { version = "1.28.1", optional = true }

Шатл можна активувати вже --features shuttleзараз. Потім натрапив на ще одну перешкоду.

Бачите, для роботи rustypasteпотрібен config.tomlфайл. А коли ми розгортаємо його як один бінарний файл, поруч із ним не буде файлу конфігурації. Щоб вирішити цю проблему,  використавуемо статичну папку для розгортання Shuttle та відредагував точку входу програми наступним чином:

#[cfg(feature = "shuttle")]
#[shuttle_runtime::main]
async fn actix_web(
    #[shuttle_static_folder::StaticFolder(folder = "shuttle")] static_folder: PathBuf,
) -> ShuttleActixWeb<impl FnOnce(&mut ServiceConfig) + Send + Clone + 'static>

Отже, якщо я поміщу файл конфігурації в “shuttle/config.toml”, він буде частиною розгортання. Чудово.

Тепер все здається добре. Давайте розгортати!

З : Зачекайте, як увімкнути функцію “шатл” через cargo shuttle? Іншими словами, чи можна перейти --features shuttleдо неї?

A : На момент написання цього допису в блозі це неможливо. Тому було створено цю задачу: https://github.com/shuttle-hq/shuttle/issues/913

З : О, чудово, чи є якийсь спосіб вирішення?

A : Так, було вирішено тимчасово ввімкнути функцію “шатл” за замовчуванням у Cargo.toml, коли я хочу розгорнути.

З : Чудово. Це так працює?

В : Звичайно!

# make "shuttle" feature default
$ sed -i 's|default = \[\]|default = \["shuttle"\]|g' Cargo.toml

# deploy without running tests
$ cargo shuttle deploy --no-test

2023-05-16T13:56:37.027724537Z  INFO Entering queued state
2023-05-16T13:56:37.036643575Z DEBUG hyper::client::connect::http: connecting to 10.99.82.119:8001
2023-05-16T13:56:37.039322882Z DEBUG hyper::client::connect::http: connected to 10.99.82.119:8001
2023-05-16T13:56:37.041805834Z DEBUG hyper::client::pool: pooling idle connection for ("http", gateway:8001)

2023-05-16T13:56:37.046562562Z  INFO Entering building state
2023-05-16T13:57:08.734972530Z  INFO     Finished release [optimized] target(s) in 31.63s

2023-05-16T13:57:08.924988890Z  INFO Entering built state

2023-05-16T13:57:08.925183822Z  INFO Entering loading state
2023-05-16T13:57:08.933992618Z DEBUG shuttle_deployer::runtime_manager: Starting alpha runtime at: /opt/shuttle/shuttle-executables/abe6d63d-8a0f-4d59-9545-8979261889e4
2023-05-16T13:57:10.937504021Z  INFO shuttle_proto::runtime: connecting runtime client
2023-05-16T13:57:10.937602528Z DEBUG hyper::client::connect::http: connecting to 127.0.0.1:18369
2023-05-16T13:57:10.940519024Z DEBUG hyper::client::connect::http: connected to 127.0.0.1:18369
2023-05-16T13:57:10.942760924Z DEBUG {service.ready=true} tower::buffer::worker: processing request
2023-05-16T13:57:10.949727188Z DEBUG {service.ready=true} tower::buffer::worker: processing request
2023-05-16T13:57:10.954448150Z  INFO shuttle_deployer::deployment::run: loading project from: /opt/shuttle/shuttle-executables/abe6d63d-8a0f-4d59-9545-8979261889e4
2023-05-16T13:57:10.956904512Z DEBUG shuttle_deployer::deployment::run: loading service
2023-05-16T13:57:10.961554512Z DEBUG {service.ready=true} tower::buffer::worker: processing request
2023-05-16T13:57:10.978349558Z  INFO {success="true"} shuttle_deployer::deployment::run: loading response
These static folders can be accessed by rustypaste
╭─────────╮
│ Folders │
╞═════════╡
│ shuttle │
╰─────────╯

Service Name:  rustypaste
Deployment ID: abe6d63d-8a0f-4d59-9545-8979261889e4
Status:        running
Last Updated:  2023-05-16T10:57:10Z

Ура, сервіс вже доступний за посиланням https://rustypaste.shuttleapp.rs !

Як бонус, хотів розгорнути цей сервіс, коли надсилаємо новий тег до репозиторію, тому було створено наступний робочий процес дій GitHub:

name: Deploy on Shuttle

on:
  push:
    branches:
      - master
    tags:
      - "v*.*.*"
  pull_request:
    branches:
      - master
  # allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  build:
    name: Build / Deploy
    runs-on: ubuntu-22.04
    steps:
      - name: Checkout the repository
        uses: actions/checkout@v3

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          override: true

      - name: Install cargo-binstall
        uses: taiki-e/install-action@cargo-binstall

      - name: Install cargo-shuttle
        run: cargo binstall -y cargo-shuttle

      - name: Prepare for deployment
        shell: bash
        run: sed -i 's|default = \[\]|default = \["shuttle"\]|g' Cargo.toml

      - name: Build
        run: cargo build --locked --verbose

      - name: Deploy
        if: ${{ startsWith(github.event.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' }}
        run: |
          cargo shuttle login --api-key ${{ secrets.SHUTTLE_TOKEN }}
          cargo shuttle project restart
          cargo shuttle deploy --allow-dirty --no-test

Варто зазначити одне, що було б зручніше встановлювати cargo-shuttleчерез, cargo-binstallоскільки це швидше завантажує попередньо зібрані бінарні файли. І нарешті, ось приклад:https://github.com/orhun/rustypaste/commit/29ddef8

Висновок

Спочатку здається, що розміщувати власний сервер і все налаштовувати складно, але це того варте. Ви rustypasteнавіть можете поділитися дуже секретним документом як одноразовою URL-адресою, щоб він зникав з поверхні Інтернету після першого перегляду.

І хто може заперечувати, що використання власного домену для обміну зображенням/файлом – це супер круто?

До речі, не соромтеся використовувати публічний екземпляр rustypasteі повідомте мені, чи сподобався він вам. Гарантії стабільності для розгортань Shuttle немає, але спробувати варто!

Щасливого завантаження!

Підписатися
Сповістити про
0 Коментарі
Найстаріші
Найновіше Найбільше голосів
Знайшли помилку?
Якщо ви знайшли помилку, зробіть скріншот і надішліть його боту.