269 lines
8.3 KiB
Markdown
269 lines
8.3 KiB
Markdown
# Analiza repozytorium: bin (Pastebin)
|
||
|
||
> Data analizy: 2026-04-21
|
||
|
||
---
|
||
|
||
## 1. Cel projektu
|
||
|
||
**Bin** to minimalistyczny, samodzielny serwis pastebin akceptujący zarówno tekst, jak i pliki binarne (obrazy, PDF-y itp.). Filozofia projektu opiera się na prostocie, łatwości wdrożenia i minimalizmie. W odróżnieniu od tradycyjnych pastebinów **nie wymaga bazy danych** — wszystkie pasty przechowywane są w płaskim systemie plików. Projekt zawiera klienty: interfejs webowy, CLI i integrację z Vimem.
|
||
|
||
**Live demo:** https://basedbin.fly.dev
|
||
**Docker:** `wantguns/bin` (multi-arch: amd64 + arm64)
|
||
|
||
---
|
||
|
||
## 2. Stack technologiczny
|
||
|
||
| Warstwa | Technologia |
|
||
|---------|-------------|
|
||
| Język | Rust (Edition 2021) |
|
||
| Framework web | Rocket 0.5.0-rc.1 (async) |
|
||
| Szablony HTML | Tera (via rocket_dyn_templates) |
|
||
| Kolorowanie składni | Syntect 4.6.0 + motyw Ayu Dark |
|
||
| Frontend | Vanilla JavaScript, HTML, CSS (brak frameworków) |
|
||
| Detekcja MIME | tree_magic 0.2.3 |
|
||
| CLI args | clap 3.0.9 |
|
||
| Kryptografia | sha256 (ETag) |
|
||
| Obsadzanie zasobów | rust-embed 6.3.0 |
|
||
| Konteneryzacja | Docker (obraz scratch) |
|
||
| Deployment | Fly.io |
|
||
|
||
---
|
||
|
||
## 3. Struktura katalogów
|
||
|
||
```
|
||
bin/
|
||
├── src/ # Kod źródłowy Rust
|
||
│ ├── main.rs # Punkt wejścia, setup serwera, parsowanie CLI
|
||
│ ├── routes/ # Handlery endpointów HTTP
|
||
│ │ ├── mod.rs
|
||
│ │ ├── index.rs # GET / – strona główna
|
||
│ │ ├── upload.rs # POST / – upload pliku binarnego
|
||
│ │ ├── submit.rs # POST /submit – formularz tekstowy
|
||
│ │ ├── retrieve.rs # GET /<id> – surowe pobranie pasty
|
||
│ │ ├── pretty_retrieve.rs # GET /p/<id> – wyświetlanie z podświetlaniem
|
||
│ │ └── static_files.rs # GET /static/<file> – zasoby statyczne
|
||
│ └── models/
|
||
│ ├── mod.rs
|
||
│ ├── paste_id.rs # Generowanie i walidacja ID pasty
|
||
│ ├── pretty_syntax.rs # Parsowanie rozszerzenia z URL
|
||
│ ├── pretty.rs # Logika podświetlania składni
|
||
│ └── response_wrapper.rs # Abstrakcja odpowiedzi HTTP
|
||
│
|
||
├── templates/ # Szablony Tera
|
||
│ ├── base.html.tera
|
||
│ ├── index.html.tera
|
||
│ └── pretty.html.tera
|
||
│
|
||
├── static/ # Zasoby osadzone w binarce
|
||
│ ├── css/
|
||
│ ├── js/
|
||
│ ├── fonts/ # Iosevka (ttf + woff2)
|
||
│ └── media/ # Favicony
|
||
│
|
||
├── resources/ # Zasoby binarne (syntaksy, motyw)
|
||
├── contrib/cli/client # Skrypt bash CLI
|
||
├── Cargo.toml # Manifest projektu
|
||
├── build.rs # Wstrzykiwanie git hash do binarki
|
||
├── Dockerfile # Wielostopniowy build
|
||
├── docker-compose.yml
|
||
└── fly.toml # Konfiguracja Fly.io
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Endpointy API
|
||
|
||
| Metoda | Ścieżka | Opis |
|
||
|--------|---------|------|
|
||
| GET | `/` | Strona główna z formularzem |
|
||
| GET | `/static/<file>` | Zasoby statyczne (CSS, JS, czcionki) |
|
||
| POST | `/` | Upload pliku binarnego → zwraca ID |
|
||
| POST | `/submit` | Formularz tekstowy → redirect do `/p/<id>.<ext>` |
|
||
| GET | `/<id>` | Surowa treść pasty |
|
||
| GET | `/<id>.<ext>` | Surowa treść z rozszerzeniem (rank=1) |
|
||
| GET | `/p/<id>` | Pasta z podświetlaniem składni (HTML) |
|
||
| GET | `/p/<id>.<ext>` | Pasta z wymuszonym językiem (rank=1) |
|
||
|
||
**Priorytet routingu:** trasy z rozszerzeniem (`rank=1`) są dopasowywane przed trasami generycznymi (`rank=2`).
|
||
|
||
---
|
||
|
||
## 5. Modele danych
|
||
|
||
### PasteId
|
||
```rust
|
||
pub struct PasteId<'a>(Cow<'a, str>)
|
||
```
|
||
- Generuje losowe 6-znakowe ID alfanumeryczne (36^6 ≈ 2,1 mld kombinacji)
|
||
- Implementuje `FromParam` dla automatycznej walidacji URL w Rocket
|
||
|
||
### PasteIdSyntax
|
||
```rust
|
||
pub struct PasteIdSyntax<'a> { syn_id: Cow<'a, str> }
|
||
```
|
||
- Parsuje URL typu `/p/abc123.cpp` na nazwę pliku i rozszerzenie
|
||
- `get_fname()` → `"abc123"`, `get_ext()` → `"cpp"`
|
||
|
||
### ResponseWrapper<R>
|
||
```rust
|
||
enum ResponseWrapper<R> {
|
||
MetaInterfaceResponse(R),
|
||
PrettyPasteContentResponse(R, SystemTime),
|
||
RawPasteContentResponse(R, SystemTime),
|
||
Redirect(Box<Redirect>),
|
||
NotFound(String),
|
||
ServerError(String),
|
||
}
|
||
```
|
||
Centralnie zarządza nagłówkami HTTP:
|
||
- `Server: bin v.<VERSION> (<GIT_HASH>)`
|
||
- `ETag`, `Last-Modified`, `Cache-Control`
|
||
|
||
---
|
||
|
||
## 6. Zależności (Cargo.toml)
|
||
|
||
| Crate | Wersja | Zastosowanie |
|
||
|-------|--------|--------------|
|
||
| `rand` | 0.8.4 | Generowanie ID |
|
||
| `rocket` | 0.5.0-rc.1 | Framework web |
|
||
| `tree_magic` | 0.2.3 | Detekcja MIME |
|
||
| `syntect` | 4.6.0 | Podświetlanie składni |
|
||
| `rust-embed` | 6.3.0 | Osadzanie zasobów |
|
||
| `clap` | 3.0.9 | Parsowanie CLI |
|
||
| `once_cell` | 1 | Lazy static |
|
||
| `sha256` | 1 | ETag |
|
||
| `time` | 0.3 | Formatowanie czasu |
|
||
| `rocket_dyn_templates` | 0.1.0-rc.1 | Szablony Tera |
|
||
|
||
---
|
||
|
||
## 7. System budowania
|
||
|
||
### build.rs
|
||
Przechwytuje hash commita git i wstrzykuje go jako stałą czasu kompilacji (`GIT_HASH`).
|
||
|
||
### .cargo/config.toml
|
||
- Kompilacja statyczna: `-C target-feature=+crt-static`
|
||
- Domyślny target: `x86_64-unknown-linux-gnu`
|
||
- Cross-kompilacja ARM64: `aarch64-linux-gnu-gcc`
|
||
|
||
### Docker (wielostopniowy)
|
||
1. **Builder:** obraz Rust → `cargo build --release`
|
||
2. **Runner:** obraz `scratch` (pusty) + tylko binarka
|
||
3. Rezultat: minimalistyczny obraz (~20-30 MB)
|
||
|
||
---
|
||
|
||
## 8. Konfiguracja serwera
|
||
|
||
### Argumenty CLI
|
||
|
||
| Flag | Domyślnie | Opis |
|
||
|------|-----------|------|
|
||
| `-a` | `127.0.0.1` | Adres nasłuchu |
|
||
| `-p` | `6162` | Port |
|
||
| `-u` | `./upload` | Katalog przechowywania plików |
|
||
| `-b` | `100 MiB` | Limit rozmiaru uploadu binarnego |
|
||
| `-c` | off | Pokaż opis klienta CLI na stronie głównej |
|
||
|
||
### Zmienne środowiskowe (prefiks `BIN_`)
|
||
```bash
|
||
BIN_PORT=6163
|
||
BIN_ADDRESS=0.0.0.0
|
||
BIN_LIMITS={form="16 MiB"}
|
||
BIN_WORKERS=8
|
||
BIN_IDENT=false
|
||
```
|
||
|
||
---
|
||
|
||
## 9. Architektura i wzorce projektowe
|
||
|
||
1. **Embedded Resources** — wszystkie zasoby (CSS, JS, czcionki, definicje syntaksy) skompilowane w binarce (`rust-embed`). Zero zależności zewnętrznych.
|
||
|
||
2. **Response Wrapper** — generyczny wrapper abstrakcji odpowiedzi z centralizowaną logiką nagłówków HTTP.
|
||
|
||
3. **Type-Safe URL Params** — `PasteId` i `PasteIdSyntax` implementują trait `FromParam` — Rocket automatycznie waliduje parametry URL.
|
||
|
||
4. **Lazy Static** — `BINARY_ETAG` obliczany raz przy starcie (SHA256 wersji) via `once_cell::sync::Lazy`.
|
||
|
||
5. **Build-Time Version Injection** — hash git osadzony w czasie kompilacji, widoczny w nagłówku `Server`.
|
||
|
||
6. **Flat Filesystem Storage** — brak bazy danych; pasty jako pliki w katalogu `./upload`.
|
||
|
||
---
|
||
|
||
## 10. Frontend (JavaScript)
|
||
|
||
### index.js (~150 linii)
|
||
- Drag-and-drop upload plików
|
||
- Wklejanie obrazów ze schowka (`paste` event)
|
||
- Tab jako 4 spacje (nie nawigacja formularza)
|
||
- Ctrl+Enter → submit
|
||
- Dynamiczne pokazywanie/ukrywanie UI
|
||
- Fork przez localStorage
|
||
|
||
### pretty.js
|
||
- Przełącznik zawijania: 3 stany (brak → auto → 80 znaków)
|
||
- Fork: kopiuje treść do localStorage, przekierowuje na główną
|
||
- Raw: przełącza `/p/<id>` → `/<id>`
|
||
- New: przejście do strony głównej
|
||
|
||
---
|
||
|
||
## 11. Strategia cachowania
|
||
|
||
| Typ odpowiedzi | Cache-Control |
|
||
|----------------|---------------|
|
||
| Pasta pretty | `max-age=604800, stale-while-revalidate=86400` |
|
||
| Pasta raw | `max-age=604800, immutable` |
|
||
| Meta/Statyczne | ETag (SHA256 wersji) → `304 Not Modified` |
|
||
|
||
---
|
||
|
||
## 12. Statystyki kodu
|
||
|
||
| Metryka | Wartość |
|
||
|---------|---------|
|
||
| Pliki źródłowe Rust | 13 |
|
||
| Linie kodu Rust | ~600 |
|
||
| Szablony HTML | 3 |
|
||
| Pliki JavaScript | 2 |
|
||
| Arkusze CSS | 2 |
|
||
| Obsługiwane języki (syntaksy) | 100+ |
|
||
| Endpointy API | 7 |
|
||
| Typy odpowiedzi HTTP | 6 |
|
||
|
||
---
|
||
|
||
## 13. Algorytmy kluczowe
|
||
|
||
### Generowanie ID
|
||
```
|
||
1. rand::thread_rng() → thread-safe RNG
|
||
2. Alphanumeric distribution (a-z, A-Z, 0-9)
|
||
3. Pobierz 6 próbek → String
|
||
4. Opakuj w Cow::Owned
|
||
```
|
||
|
||
### Detekcja MIME (upload binarny)
|
||
```
|
||
1. Wczytaj bajty pliku
|
||
2. tree_magic::from_filepath() → MIME
|
||
3. MIME zawiera "text" → /p/<id> (kolorowanie)
|
||
4. Inaczej → /<id> (surowe pobranie)
|
||
```
|
||
|
||
### Renderowanie składni
|
||
```
|
||
1. Parsuj URL /p/abc123.cpp
|
||
2. Wyodrębnij rozszerzenie ("cpp")
|
||
3. Znajdź definicję syntaxu w syntect
|
||
4. Fallback → plain_text
|
||
5. Renderuj HTML z motywem Ayu Dark
|
||
```
|