Skip to content

Commit 56d6941

Browse files
committed
Enable CLI modules to act as both client and server
1 parent e10b50d commit 56d6941

21 files changed

+471
-493
lines changed

.gitattributes

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto
3+
4+
# Rust source files should always use LF
5+
*.rs text eol=lf
6+
*.toml text eol=lf
7+
*.md text eol=lf
8+
9+
# Scripts should use LF
10+
*.sh text eol=lf
11+
*.py text eol=lf
12+
13+
# Windows scripts should use CRLF
14+
*.bat text eol=crlf
15+
*.ps1 text eol=crlf

.github/copilot-instructions.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ P2PFileTransfer/
300300
#### Python Integration Tests
301301
- Script: `test_transfer.py`
302302
- Tests real file transfers end-to-end
303-
- Verifies statistics, compression, data integrity
303+
- Verifies statistics, compression, windowed mode, data integrity
304304
- Remove `test_file` before running, when changing test size or compressibility
305305

306306
---
@@ -411,3 +411,20 @@ python3 benchmark.py
411411
2. **Fix the bug** and verify test passes
412412
3. **Run full test suite** to ensure no regressions
413413
4. **Update CHANGELOG.md** with the fix
414+
415+
### Documentation Policy
416+
**CRITICAL**: Never create new markdown documentation files for feature summaries or implementation notes.
417+
418+
**DO**:
419+
- Update `README.md` with usage examples and user-facing documentation
420+
- Update `DESIGN.md` with architecture and implementation details
421+
- Update `TODO.md` to remove completed features or add notes for partial implementations
422+
- Update `CHANGELOG.md` with dated entries for all changes
423+
- Add inline code comments and module documentation
424+
425+
**DON'T**:
426+
- Create files like `FEATURE_NAME.md`, `IMPLEMENTATION_SUMMARY.md`, `QUICK_REFERENCE.md`, etc.
427+
- Create separate documentation files for individual features
428+
- Create temporary documentation files that duplicate existing docs
429+
430+
**Rationale**: Keep documentation centralized in the four main files (README, DESIGN, TODO, CHANGELOG) to avoid fragmentation and maintenance burden.

.rustfmt.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ edition = "2021"
22
max_width = 100
33
hard_tabs = false
44
tab_spaces = 4
5-
newline_style = "Unix"
5+
newline_style = "Auto"
66
use_small_heuristics = "Default"
77
reorder_imports = true
88
reorder_modules = true
99
remove_nested_parens = true
10-
format_strings = true
11-
format_macro_bodies = true

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- **Bidirectional session support** (2025-10-06): CLI can now act as both client and server
12+
- Added `SessionParams` struct with `--role`, `--peer`, `--port`, and `--discover` parameters
13+
- Added `TransferParams` struct for common transfer configuration
14+
- Send command can operate as client (default) or server (`--role server`)
15+
- Receive command can operate as server (default) or client (`--role client`)
16+
- Both peers can send or receive after session establishment
17+
- Session documentation updated to clarify bidirectional capabilities
18+
- Added `P2PSession::establish()` convenience method for role-based connection (eliminates code duplication)
19+
1020
### Changed
1121
- **CLI parameter rename** (2025-10-06): `--log-level` renamed to `--verbosity` for better clarity
22+
- **CLI parameter rename** (2025-10-06): `--to` renamed to `--peer` for consistency with session role model
1223
- **Protocol optimization** (2025-10-06): Removed redundant `uncompressed_size` field from `ChunkMessage`, saving 4 bytes per chunk
1324
- **InFlightChunk refactoring** (2025-10-06): Now stores complete `ChunkMessage` for efficient retransmission without data duplication
1425

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "p2p-transfer"
33
version = "0.1.0"
44
edition = "2021"
5-
authors = ["Your Name <your.email@example.com>"]
5+
authors = ["cDc <cdc.seacave@gmail.com>"]
66
description = "A lightweight P2P file transfer tool with compression"
77
license = "MIT"
88
repository = "https://github.com/yourusername/p2p-transfer"

DESIGN.md

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -454,28 +454,55 @@ session.run_event_loop(&output_dir, auto_accept).await?;
454454
- ✅ Supports session multiplexing (future)
455455
- ✅ Foundation for file browsing protocol (future)
456456

457-
#### CLI Integration
457+
#### CLI Integration with Role Selection
458458

459-
**External interface unchanged:**
459+
**CLI interface (flexible role selection)**:
460460
```bash
461-
# Send (establishes session, sends, closes)
462-
p2p-transfer send file.zip --to host:port
461+
# Send as client (default) - connect to peer and send
462+
p2p-transfer send file.zip --peer host:port
463+
464+
# Send as server - listen for peer to connect, then send
465+
p2p-transfer send file.zip --role server --port 7778
463466

464-
# Receive (establishes session, auto-receives until closed)
467+
# Receive as server (default) - listen for peer and receive
465468
p2p-transfer receive --output ./downloads --port 7778
469+
470+
# Receive as client - connect to peer and receive
471+
p2p-transfer receive --output ./downloads --role client --peer host:port
466472
```
467473

468-
**Internal flow (new)**:
474+
**Internal flow**:
469475
```rust
470-
// Send command
471-
let mut session = P2PSession::connect(...).await?;
472-
session.send_path(&path, progress_callback).await?;
476+
// Unified session establishment using P2PSession::establish()
477+
let mut session = P2PSession::establish(
478+
&role, // "client" or "server"
479+
peer_addr, // Some(addr) for client, None for server
480+
bind_addr, // Bind address (used by server)
481+
device_id,
482+
capabilities,
483+
Some(config), // Config for client, can be None for server
484+
).await?;
473485

474-
// Receive command
475-
let mut session = P2PSession::accept(...).await?;
476-
session.run_event_loop(&output, auto_accept).await?; // Auto-receive loop
486+
// Then perform operation (send or receive)
487+
session.send_path(&path, progress_callback).await?;
488+
// or
489+
session.run_event_loop(&output, auto_accept).await?;
477490
```
478491

492+
**Common CLI Parameters**:
493+
- `SessionParams`: `--role`, `--peer`, `--port`, `--discover`
494+
- `TransferParams`: `--compress`, `--compress-level`, `--adaptive`, `--chunk-size`, `--window-size`, `--max-speed`, `--auto-reconnect`, `--max-retries`
495+
496+
**Role Defaults**:
497+
- `send` command: defaults to `client` (connects to peer)
498+
- `receive` command: defaults to `server` (listens for peer)
499+
- Can be overridden with `--role` parameter
500+
501+
**Code Reuse**:
502+
- `P2PSession::establish()` eliminates duplicate connection logic
503+
- Both `send.rs` and `receive.rs` use the same session establishment code
504+
- Cleaner, more maintainable CLI implementation
505+
479506
#### Future Enhancements
480507

481508
With session foundation in place:

README.md

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -89,43 +89,54 @@ cargo build --release
8989

9090
### Basic Usage
9191

92+
#### Bidirectional Sessions
93+
After a session is established, **both peers are equal** and can send or receive files. The `--role` parameter only determines who initiates the connection:
94+
- **Client role** (default for send): Connects to a peer
95+
- **Server role** (default for receive): Listens for incoming connections
96+
9297
#### Send a File
9398
```bash
94-
# Direct connection (windowed mode is default)
95-
p2p-transfer send myfile.zip --to 192.168.1.100:8080
99+
# Send as client (default) - connect to peer and send
100+
p2p-transfer send myfile.zip --peer 192.168.1.100:8080
101+
102+
# Send as server - listen for peer to connect, then send
103+
p2p-transfer send myfile.zip --role server --port 8080
96104

97-
# With auto-discovery
105+
# With auto-discovery (client mode)
98106
p2p-transfer send myfile.zip --discover
99107

100108
# Sequential mode (one chunk at a time)
101-
p2p-transfer send myfile.zip --to 192.168.1.100:8080 --window-size 1
109+
p2p-transfer send myfile.zip --peer 192.168.1.100:8080 --window-size 1
102110
```
103111

104112
#### Send a Folder
105113
```bash
106114
# Transfer entire directory with structure
107-
p2p-transfer send ./my_project --to 192.168.1.100:8080
115+
p2p-transfer send ./my_project --peer 192.168.1.100:8080
108116

109117
# With compression (adaptive by default)
110-
p2p-transfer send ./documents --to 192.168.1.100:8080 --compress --compress-level 5
118+
p2p-transfer send ./documents --peer 192.168.1.100:8080 --compress --compress-level 5
111119

112120
# Adaptive compression auto-disables for incompressible data (default: enabled)
113-
p2p-transfer send ./mixed_content --to 192.168.1.100:8080 --adaptive true
121+
p2p-transfer send ./mixed_content --peer 192.168.1.100:8080 --adaptive true
114122

115123
# Force compression even for incompressible data
116-
p2p-transfer send ./photos --to 192.168.1.100:8080 --adaptive false
124+
p2p-transfer send ./photos --peer 192.168.1.100:8080 --adaptive false
117125
```
118126

119127
#### Receive Files/Folders
120128
```bash
121-
# Start receiver on port 8080 (automatically receives when peer sends)
122-
p2p-transfer receive ./downloads --port 8080
129+
# Receive as server (default) - listen for peer to connect and receive
130+
p2p-transfer receive --output ./downloads --port 8080
131+
132+
# Receive as client - connect to peer and receive files
133+
p2p-transfer receive --output ./downloads --role client --peer 192.168.1.100:8080
123134

124135
# Auto-accept incoming transfers (no prompts)
125-
p2p-transfer receive ./received --port 7778 --auto-accept
136+
p2p-transfer receive --output ./received --port 7778 --auto-accept
126137

127138
# Short form
128-
p2p-transfer receive ./received -p 7778 -a
139+
p2p-transfer receive -o ./received -p 7778 -a
129140
```
130141

131142
**Note**: The receiver now runs in an event loop that automatically handles incoming transfers. When a peer initiates a send, the receiver will automatically start receiving - no manual action needed. The session stays alive for multiple transfers until the connection is closed.
@@ -185,18 +196,18 @@ Currently, when both machines are behind NAT, you need to manually use the disco
185196
2. **On Machine B (sender)** - Connect using Machine A's public IP:
186197
```bash
187198
# Send to Machine A's public IP and forwarded port
188-
p2p-transfer send myfile.zip --to 203.0.113.5:7778
199+
p2p-transfer send myfile.zip --peer 203.0.113.5:7778
189200
```
190201

191202
#### Resume Interrupted Transfer
192203
```bash
193204
# Transfer gets interrupted (Ctrl+C)
194-
p2p-transfer send ./large_folder --to 192.168.1.100:8080
205+
p2p-transfer send ./large_folder --peer 192.168.1.100:8080
195206
# State saved to: transfer_12345678-1234-5678-1234-567812345678.json
196207

197208
# Resume later (supports chunk-level resume)
198209
p2p-transfer resume 12345678-1234-5678-1234-567812345678 \
199-
--to 192.168.1.100:8080 \
210+
--peer 192.168.1.100:8080 \
200211
--path ./large_folder
201212
```
202213

@@ -222,16 +233,16 @@ p2p-transfer history --failed
222233

223234
```bash
224235
# LAN (low latency, < 5ms)
225-
p2p-transfer send file.zip --to 192.168.1.100:8080 --window-size 8
236+
p2p-transfer send file.zip --peer 192.168.1.100:8080 --window-size 8
226237

227238
# WiFi (medium latency, 10-20ms) - DEFAULT
228-
p2p-transfer send file.zip --to 192.168.1.100:8080 --window-size 16
239+
p2p-transfer send file.zip --peer 192.168.1.100:8080 --window-size 16
229240

230241
# Internet (high latency, 50-100ms)
231-
p2p-transfer send file.zip --to 192.168.1.100:8080 --window-size 32
242+
p2p-transfer send file.zip --peer 192.168.1.100:8080 --window-size 32
232243

233244
# Satellite/VPN (very high latency, 500ms+)
234-
p2p-transfer send file.zip --to 192.168.1.100:8080 --window-size 64
245+
p2p-transfer send file.zip --peer 192.168.1.100:8080 --window-size 64
235246
```
236247

237248
**Memory Usage**: Window size × 1MB chunk size
@@ -243,16 +254,16 @@ p2p-transfer send file.zip --to 192.168.1.100:8080 --window-size 64
243254

244255
```bash
245256
# Limit to 10 MB/s (useful for shared networks)
246-
p2p-transfer send largefile.zip --to 192.168.1.100:8080 --max-speed 10M
257+
p2p-transfer send largefile.zip --peer 192.168.1.100:8080 --max-speed 10M
247258

248259
# Limit to 1 GB/s (for very fast networks)
249-
p2p-transfer send largefile.zip --to 192.168.1.100:8080 --max-speed 1G
260+
p2p-transfer send largefile.zip --peer 192.168.1.100:8080 --max-speed 1G
250261

251262
# Limit to 512 KB/s (for slow connections)
252-
p2p-transfer send largefile.zip --to 192.168.1.100:8080 --max-speed 512K
263+
p2p-transfer send largefile.zip --peer 192.168.1.100:8080 --max-speed 512K
253264

254265
# Unlimited bandwidth (default)
255-
p2p-transfer send largefile.zip --to 192.168.1.100:8080
266+
p2p-transfer send largefile.zip --peer 192.168.1.100:8080
256267
```
257268

258269
**How it works**:
@@ -267,16 +278,16 @@ Transfers automatically recover from network failures with exponential backoff:
267278

268279
```bash
269280
# Auto-reconnect is enabled by default
270-
p2p-transfer send large_folder/ --to 192.168.1.100:8080
281+
p2p-transfer send large_folder/ --peer 192.168.1.100:8080
271282

272283
# Disable auto-reconnect (manual resume only)
273-
p2p-transfer send large_folder/ --to 192.168.1.100:8080 --auto-reconnect false
284+
p2p-transfer send large_folder/ --peer 192.168.1.100:8080 --auto-reconnect false
274285

275286
# Unlimited retries (keeps trying until success or permanent error)
276-
p2p-transfer send large_folder/ --to 192.168.1.100:8080 --max-retries 0
287+
p2p-transfer send large_folder/ --peer 192.168.1.100:8080 --max-retries 0
277288

278289
# Custom retry limit
279-
p2p-transfer send large_folder/ --to 192.168.1.100:8080 --max-retries 10
290+
p2p-transfer send large_folder/ --peer 192.168.1.100:8080 --max-retries 10
280291
```
281292

282293
**How it works**:
@@ -347,7 +358,7 @@ Progress: 100/100 chunks (100.0%, complete)
347358
348359
# Later...
349360
$ p2p-transfer resume abc12345-def6-7890-ghij-klmnopqrstuv \
350-
--to 192.168.1.100:8080 --path my_project
361+
--peer 192.168.1.100:8080 --path my_project
351362
352363
🔄 Resuming transfer
353364
Progress: 8/10 files (80.0%)

benchmark.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def run_sender_test(self, test_name: str, file_path: Path, mode: str, window_siz
9999
# Build command
100100
cmd = [
101101
self.binary_path, "send", str(file_path),
102-
"--to", f"{self.receiver_ip}:{self.port}"
102+
"--peer", f"{self.receiver_ip}:{self.port}"
103103
]
104104

105105
# Set window size: 1 for sequential, or specified value for windowed

0 commit comments

Comments
 (0)