nzb-nntp
Async NNTP client library for Rust, designed for high-performance Usenet article downloading.
Features
- Async/await — Built on Tokio for non-blocking I/O
- TLS — Implicit TLS via rustls with optional certificate verification bypass
- Authentication — AUTHINFO USER/PASS (RFC 4643)
- Pipelining — Send multiple ARTICLE/STAT commands before reading responses, dramatically improving throughput on high-latency links
- Connection pooling — Per-server pools with health checking, idle timeouts, and automatic reconnection
- Multi-server failover — Priority-based server selection with automatic retry on next server
- Penalty system — Temporarily backs off servers experiencing errors (auth, timeout, connection)
- GZIP compression — XFEATURE COMPRESS GZIP negotiation and transparent decompression
- SOCKS5 proxy — Route connections through SOCKS5 proxies with optional authentication
- Bandwidth limiting — Global bandwidth throttling
- Pause/resume/shutdown — Runtime control of download operations
Quick Start
Add to your Cargo.toml:
[]
= "0.1"
= { = "1", = ["full"] }
Single Connection
use ;
async
Group Browsing
use ;
async
Pipelining
Pipelining sends multiple commands before reading responses, reducing round-trip overhead:
use ;
async
Multi-Server Downloading
The Downloader coordinates article fetching across multiple servers with automatic failover:
use ;
use mpsc;
async
Connection Pooling
use ;
use Arc;
async
Architecture
┌──────────────┐
│ Downloader │ Orchestrates multi-server downloads
│ (failover) │ with priority, pause/resume, bandwidth
└──────┬───────┘
│
┌─────────┼─────────┐
▼ ▼ ▼
┌───────────┐ ┌───────────┐
│ServerState│ ... │ServerState│ Per-server health tracking,
│ + Pool │ │ + Pool │ penalties, speed metrics
└─────┬─────┘ └─────┬─────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ConnectionPool │ │ConnectionPool │ Semaphore-limited pools,
│ (idle conns) │ │ (idle conns) │ health checks, reconnect
└────────┬────────┘ └────────┬────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│NntpConnection │ │NntpConnection │ TCP/TLS state machine,
│ (state machine) │ │ (state machine) │ auth, commands, compression
└────────┬────────┘ └────────┬────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Transport │ │ Transport │ Plain TCP or TLS stream
│ (TCP / TLS) │ │ (TCP / TLS) │ with buffered I/O
└──────────────┘ └──────────────┘
Module Summary
| Module | Purpose |
|---|---|
config |
ServerConfig, Article, ListActiveEntry — serializable configuration types |
error |
NntpError enum with NNTP-specific variants and response code mapping |
connection |
RFC 3977 state machine: connect, auth, TLS, compression, all NNTP commands |
pipeline |
Pipeline (ARTICLE) and StatPipeline (STAT) for request pipelining |
pool |
Per-server connection pool with semaphore limiting and health checks |
server |
ServerState with penalty system, speed tracking, failure ratios |
downloader |
Downloader orchestrator: priority failover, pause/resume, bandwidth limiting |
Configuration
ServerConfig supports serde serialization for easy config file integration:
| Field | Default | Description |
|---|---|---|
id |
— | Unique identifier for the server |
name |
— | Human-readable display name |
host |
— | NNTP server hostname |
port |
563 |
Server port (563 = NNTPS) |
ssl |
true |
Enable TLS |
ssl_verify |
true |
Verify TLS certificates |
username |
None |
Auth username |
password |
None |
Auth password |
connections |
4 |
Max concurrent connections to this server |
priority |
0 |
Server priority (0 = highest, tried first) |
enabled |
true |
Include this server in downloads |
retention |
0 |
Article retention in days (0 = unlimited) |
pipelining |
1 |
Pipeline depth (1 = no pipelining) |
optional |
false |
If true, failures don't block the download |
compress |
false |
Negotiate XFEATURE COMPRESS GZIP |
proxy_url |
None |
SOCKS5 proxy: socks5://[user:pass@]host:port |
Error Handling
All operations return NntpResult<T> (alias for Result<T, NntpError>). Errors are structured by cause:
| Error | Trigger | Recoverable? |
|---|---|---|
ArticleNotFound |
430 response | Yes — try another server |
NoSuchGroup |
411 response | Yes — check group name |
NoArticleSelected |
412, 420 responses | Yes — select group first |
AuthRequired |
480 response | No — needs reconnection with credentials |
Auth |
481, 482 responses | No — check credentials |
ServiceUnavailable |
502 response | No — server is down |
Connection |
TCP/socket errors | No — reconnect required |
Tls |
TLS handshake failure | No — check TLS config |
Protocol |
Unexpected response codes | No — possible server bug |
Io |
Underlying I/O errors | No — reconnect required |
Timeout |
Pool acquire timeout | Retry after delay |
AllServersExhausted |
Article not on any server | No — article is unavailable |
Shutdown |
Downloader shut down | No — intentional |
Fatal errors (Auth, ServiceUnavailable, Connection, I/O) transition the connection to Error state, requiring a new connection. Non-fatal errors (ArticleNotFound, NoSuchGroup) keep the connection in Ready state.
NNTP Commands Supported
| Command | Method | RFC |
|---|---|---|
| ARTICLE | fetch_article() |
RFC 3977 §6.2.1 |
| BODY | fetch_body() |
RFC 3977 §6.2.3 |
| STAT | stat_article() |
RFC 3977 §6.2.4 |
| GROUP | group() |
RFC 3977 §6.1.1 |
| XOVER | xover() |
RFC 2980 §2.8 |
| XHDR | xhdr() |
RFC 2980 §2.6 |
| XPAT | xpat() |
RFC 2980 §2.9 |
| LIST ACTIVE | list_active() |
RFC 3977 §7.6.3 |
| AUTHINFO USER/PASS | connect() (automatic) |
RFC 4643 §2.3 |
| XFEATURE COMPRESS GZIP | connect() (automatic) |
De-facto standard |
| QUIT | quit() |
RFC 3977 §5.4 |
For detailed spec compliance analysis, see NNTP_COMPLIANCE.md.
Testing
The test suite uses an in-process mock NNTP server (testutil::MockNntpServer) that supports all implemented commands with configurable responses and error injection. No external NNTP server is required.
License
MIT