# PeerDrop

A programmable peer-to-peer file sharing platform powered by IPFS and libp2p. Share files directly between devices on your local network without relying on centralized servers.

## Features

- **Zero-config peer discovery** — devices find each other automatically via mDNS
- **Direct file transfer** — files go device-to-device, no cloud storage
- **Content-addressed integrity** — every file is verified via cryptographic hashes
- **Multiple interfaces** — CLI, REST API, MCP server, and desktop GUI
- **Single daemon architecture** — one process manages all connections, clients share state
- **Deterministic identities** — restart with the same peer ID using `--seed`

## Quick Start

### Installation

```bash
pip install -e .
```

### Start the daemon

```bash
peerdrop daemon start --port 4001
```

### Discover peers

```bash
peerdrop discover
```

### Send a file

```bash
peerdrop send ./photo.jpg --to <peer-id>
```

### List transfers

```bash
peerdrop transfers
```

### Stop the daemon

```bash
peerdrop daemon stop
```

## Usage

### CLI Commands

```bash
# Show all commands
peerdrop --help

# Daemon management
peerdrop daemon start --port 4001          # Start daemon on port 4001
peerdrop daemon stop                        # Stop the daemon
peerdrop daemon status                      # Check if daemon is running

# Peer operations
peerdrop discover                           # Find peers on local network
peerdrop connect /ip4/192.168.1.100/tcp/4001/p2p/12D3KooW...  # Connect to peer
peerdrop ping <peer-id>                     # Measure latency

# File transfer
peerdrop send ./file.txt --to <peer-id>    # Send a file
peerdrop transfers                          # List all transfers

# Identity
peerdrop identity                           # Show your peer ID and addresses

# Configuration
peerdrop download-dir                       # Show download directory
peerdrop set-download-dir /path/to/dir      # Change download directory
```

### Deterministic Peer ID

Use `--seed` to get the same peer ID across restarts:

```bash
peerdrop --seed "my-device-name" daemon start --port 4001
```

### Custom Download Directory

```bash
peerdrop daemon start --download-dir ~/PeerDrop-Files
```

### REST API

Start the daemon with REST API enabled:

```bash
peerdrop daemon start --port 4001 --rest-port 8080
```

Endpoints:

```bash
GET  /health                     # Health check
GET  /api/identity               # Get device identity
GET  /api/peers                  # Discover peers
GET  /api/peers/<peer-id>        # Get peer info
POST /api/peers/connect          # Connect to peer
POST /api/peers/<peer-id>/ping   # Ping peer
POST /api/transfers/send         # Send file
GET  /api/transfers              # List transfers
GET  /api/transfers/<id>         # Get transfer details
DELETE /api/transfers/<id>       # Cancel transfer
GET  /api/settings/download-dir  # Get download directory
PUT  /api/settings/download-dir  # Set download directory
```

### MCP Server

Use PeerDrop as an MCP tool for AI assistants:

```bash
peerdrop mcp
```

Configure in Claude Desktop or other MCP clients to use `peerdrop mcp` as the server command.

Available tools: `health`, `get_identity`, `discover_peers`, `get_peer`, `connect_peer`, `ping_peer`, `send_file`, `list_transfers`, `get_transfer`, `cancel_transfer`, `get_download_dir`, `set_download_dir`.

### Desktop GUI

```bash
peerdrop-gui
```

## Architecture

PeerDrop uses a **daemon architecture** where a single process holds the engine and all clients communicate via IPC:

```
┌─────────────────────────────────────────────────┐
│                  PeerDrop Daemon                  │
│                                                  │
│  ┌─────────────┐    ┌──────────────────────────┐│
│  │  PeerEngine  │◄──│     ServiceInterface      ││
│  │  (py-ipfs-   │    │  (typed API layer)       ││
│  │   lite)      │    └──────────┬───────────────┘│
│  └──────┬──────┘               │                │
│         │                      │                │
│  ┌──────┴──────┐    ┌──────────┴───────────────┐│
│  │  Discovery   │    │      RequestHandler      ││
│  │  (mDNS)      │    │  (routes IPC actions)    ││
│  └─────────────┘    └──────────┬───────────────┘│
│                                │                │
│  ┌─────────────┐    ┌──────────┴───────────────┐│
│  │  Transfer    │    │      DaemonServer        ││
│  │  Manager     │    │  (Unix socket IPC)       ││
│  └─────────────┘    └──────────┬───────────────┘│
└────────────────────────────────┼────────────────┘
                                 │
                    ┌────────────┴────────────┐
                    │     Unix Socket IPC     │
                    └────────────┬────────────┘
                                 │
         ┌───────────┬───────────┼───────────┬───────────┐
         │           │           │           │           │
    ┌────┴────┐ ┌────┴────┐ ┌───┴───┐ ┌────┴────┐ ┌───┴───┐
    │   CLI   │ │REST API │ │  MCP  │ │   GUI   │ │  SDK  │
    └─────────┘ └─────────┘ └───────┘ └─────────┘ └───────┘
```

### Core Layer

| Module | Purpose |
|--------|---------|
| `core/engine.py` | Orchestrates discovery, transfers, and events |
| `core/service.py` | Typed API layer between engine and clients |
| `core/models.py` | Data models (`Peer`, `Transfer`, `TransferStatus`) |
| `core/discovery.py` | mDNS peer discovery via py-ipfs-lite |
| `core/transfer.py` | File transfer via stream handshake + bitswap |
| `core/events.py` | Event bus using trio memory channels |

### Daemon Layer

| Module | Purpose |
|--------|---------|
| `daemon/server.py` | Unix socket IPC server (trio-based) |
| `daemon/handler.py` | Routes 12 IPC actions to service methods |
| `daemon/protocol.py` | msgpack serialization for requests/responses |
| `daemon/lifecycle.py` | Daemon start/stop/signal handling |

### Interface Layer

| Module | Purpose |
|--------|---------|
| `interfaces/client.py` | Unified IPC client (sync + async) |
| `interfaces/cli/` | Click CLI commands |
| `interfaces/rest/` | HTTP REST API server |
| `interfaces/mcp/` | MCP server for AI assistants |
| `interfaces/gui/` | PySide6 desktop GUI |

### Shared Utilities

| Module | Purpose |
|--------|---------|
| `constants.py` | Shared paths (`DEFAULT_SOCK_PATH`, etc.) |
| `utils/framing.py` | Length-prefix IPC message framing |

### Data Flow

```
peerdrop send file.txt --to 12D3KooW...
    │
    ▼
CLI → Unified IPC Client (PeerDropClient)
    │ msgpack over Unix socket
    ▼
DaemonServer → RequestHandler → ServiceInterface
    │
    ▼
PeerEngine.send_file()
    │
    ├── add_file() → root_cid (py-ipfs-lite)
    ├── open_stream(receiver, ["/peerdrop/transfer/1.0.0"])
    ├── send TransferRequest { file_name, file_size, root_cid }
    ├── wait for ACK
    │
    ▼
Receiver fetches blocks via bitswap
    │
    ▼
TransferCompleted event → CLI shows done
```

### Transfer Protocol

The stream is only for the handshake. Actual data transfer happens via bitswap:

1. Sender opens stream to receiver with transfer protocol
2. Sender sends `TransferRequest` (file metadata + root CID)
3. Receiver ACKs and fetches blocks via bitswap using the root CID
4. Receiver writes file to disk and sends `DONE` confirmation

This pattern gives you:
- Block-level reliability (retransmission, deduplication)
- Content addressing (integrity verification)
- Automatic resume support (re-fetch missing CIDs)

## Technology Stack

| Component | Technology |
|-----------|-----------|
| Networking | py-ipfs-lite (wraps py-libp2p) |
| Async framework | trio |
| Data models | dataclasses |
| IPC | Unix sockets + msgpack |
| CLI | Click |
| GUI | PySide6 |
| Transfer | libp2p streams + bitswap |
| Discovery | mDNS |
| MCP | mcp package (v2.0) |

## Development

### Run tests

```bash
python -m pytest tests/ -v
```

### Project structure

```
peerdrop/
├── core/              # Engine, models, discovery, transfers, events
├── daemon/            # IPC server, handler, protocol, lifecycle
├── interfaces/        # CLI, REST, MCP, GUI clients + unified client
├── utils/             # Shared utilities (framing)
├── constants.py       # Shared constants
└── tests/             # 208 tests (unit + E2E)
```

## License

MIT
