Metadata-Version: 2.2
Name: verlihub-py
Version: 1.7.0.0
Summary: Python FastAPI wrapper for Verlihub DC hub with native C++ core (a modified fork of Verlihub, maintained at github.com/transfix/verlihub)
Keywords: dc,direct-connect,hub,p2p,fastapi
Author: Joe Rivera
Author-Email: Verlihub Team <info@verlihub.net>
License: GPL-3.0-or-later
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: C++
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Communications :: File Sharing
Classifier: Topic :: Internet
Project-URL: Homepage, https://github.com/transfix/verlihub
Project-URL: Repository, https://github.com/transfix/verlihub
Project-URL: Documentation, https://verlihub.net/doc/
Project-URL: Upstream project, https://github.com/verlihub/verlihub
Requires-Python: >=3.10
Requires-Dist: fastapi>=0.109.0
Requires-Dist: uvicorn[standard]>=0.27.0
Requires-Dist: sqlmodel>=0.0.14
Requires-Dist: asyncmy>=0.2.9
Requires-Dist: asyncpg>=0.29.0
Requires-Dist: aiosqlite>=0.19.0
Requires-Dist: pydantic>=2.5.0
Requires-Dist: pydantic-settings>=2.1.0
Requires-Dist: python-jose[cryptography]>=3.3.0
Requires-Dist: bcrypt>=4.0.0
Requires-Dist: httpx>=0.26.0
Requires-Dist: jinja2>=3.1.0
Requires-Dist: python-multipart>=0.0.6
Requires-Dist: pyyaml>=6.0.0
Requires-Dist: click>=8.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
Requires-Dist: black>=24.1.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=1.8.0; extra == "dev"
Requires-Dist: mcp[cli]>=1.0.0; extra == "dev"
Provides-Extra: mcp
Requires-Dist: mcp[cli]>=1.0.0; extra == "mcp"
Provides-Extra: ai
Requires-Dist: mcp[cli]>=1.0.0; extra == "ai"
Requires-Dist: openai>=1.0.0; extra == "ai"
Description-Content-Type: text/markdown

# Verlihub Python API

A FastAPI-based REST API and web dashboard for managing Verlihub DC hubs.

> **Fork notice:** `verlihub-py` is a **modified fork** of
> [Verlihub](https://github.com/verlihub/verlihub), maintained at
> [github.com/transfix/verlihub](https://github.com/transfix/verlihub). It is not the
> original project. Licensed GPL-3.0-or-later; all upstream copyrights are preserved.

## Features

- **REST API** - Full hub management via HTTP endpoints
- **Web Dashboard** - Browser-based administration UI
- **WebSocket** - Real-time hub events and log streaming
- **CLI Tools** - Command-line management utilities
- **Performance Benchmarks** - Load testing and performance analysis
- **Remote Client** - Python client library for hub administration
- **NMDCpb Protocol Extension** - Protobuf structured messaging with hub-relayed
  transfers, E2E encrypted PM, media sharing, channels, and voice/video signaling
- **LLM & MCP Integration** - AI chat assistant with hub tool-calling, an NMDC
  `Hub-Security` bot, and a Model Context Protocol server for AI editors

## Quick Start

### Installation

```bash
# From PyPI (recommended)
pip install verlihub-py

# With LLM / MCP integration extras (OpenAI-compatible client + MCP server)
pip install "verlihub-py[ai]"

# From source (development)
git clone https://github.com/transfix/verlihub
cd verlihub/python
pip install -e ".[dev]"
```

> **Note:** the published wheels bundle the native Verlihub C++ core (built via
> scikit-build-core + SWIG). A source build additionally needs CMake, SWIG, a
> C++17 compiler, and the hub's build dependencies.

### Running the API Server

```bash
# Start the API server
verlihub-api

# Or with custom settings
verlihub-api --host 0.0.0.0 --port 8000
```

### Using the CLI

```bash
# Check hub status
verlihub-cli status

# List online users
verlihub-cli users

# Execute a hub command
verlihub-cli command "!help"

# Login and save token
verlihub-cli login admin password123
```

## API Endpoints

### Public Endpoints

| Endpoint | Description |
|----------|-------------|
| `GET /health` | Health check |
| `GET /api/v1/hub/stats` | Hub statistics |
| `GET /api/v1/hub/info` | Hub information |

### Authenticated Endpoints

| Endpoint | Min Class | Description |
|----------|-----------|-------------|
| `GET /api/v1/users/online` | 1 | List online users |
| `GET /api/v1/users/registered` | 3 | List registered users |
| `POST /api/v1/users/{nick}/kick` | 3 | Kick a user |
| `GET /api/v1/bans/` | 3 | List bans |
| `POST /api/v1/bans/` | 4 | Create a ban |
| `POST /api/v1/console/execute` | 3 | Execute hub command |
| `GET /api/v1/config/` | 10 | Get configuration |

### WebSocket Endpoints

| Endpoint | Description |
|----------|-------------|
| `/ws/hub` | Real-time hub events (joins, parts, chat) |
| `/ws/logs` | Real-time log streaming |

## Web Dashboard

Access the dashboard at `http://localhost:8000/dashboard/`

### Pages

- **Dashboard** - Hub overview with stats and quick actions
- **Users** - Online and registered user management
- **Bans** - Ban list and management
- **Logs** - Real-time log viewer
- **Console** - Command execution interface
- **Config** - Hub configuration (Master only)
- **Plugins** - Plugin management (Admin only)

## NMDCpb Protocol Extension

verlihub-py ships the **server side** of NMDCpb — a protobuf-based structured
messaging layer that extends classic NMDC with six integrated features. The hub
negotiates `NMDCpb` in `$Supports`, dispatches `$PB`/`$PBR` envelopes to a Python
plugin, and transparently translates to legacy NMDC (`$<nick>`, `$To:`, `$Search`)
for non-NMDCpb clients.

| Extension | Capability |
|-----------|------------|
| **NMDCpb** | Protobuf message dispatch, legacy translation, feature negotiation |
| **HubRelay** | Hub-brokered relay sessions for encrypted, NAT-friendly transfers |
| **E2EPM** | End-to-end encrypted private messages with key-exchange forwarding |
| **MediaShare** | Media storage (filesystem/S3), HTTP upload/download API, P2P routing |
| **Channels** | Channel lifecycle, membership, message routing, E2E sender keys |
| **VoiceVideo** | 1:1 and group call signaling, hub streams, SFU fan-out |

### Admin surface

- **Chat commands** (operator, class ≥ 5): `+nmdcpb stats`, `+nmdcpb users`,
  `+nmdcpb relay`, `+nmdcpb channel list|create|delete|info`
- **REST API** under `/dashboard/nmdcpb/api` (admin JWT, `user_class ≥ 5`):
  `GET /api/stats`, `GET /api/users`, `GET /api/relays`, `GET /api/relay/{id}`,
  `POST /api/relay/{id}/close`, `POST /api/relay/close-all`,
  `POST /api/relay/close-user/{nick}`
- **Media API** mounted at `/api/media/` (per-user HMAC bearer tokens):
  `POST /upload`, `GET /quota`, `GET /{id}`, `GET /{id}/thumb`,
  `GET /{id}/meta`, `DELETE /{id}`
- **WebSocket** `/ws/relay` streams `relay_created` / `relay_closed` events
- **Dashboard** at `/dashboard/nmdcpb/` with live stats, relay/user tables, and
  admin actions

### Client library

A high-level Python client for these extensions (E2E-encrypted PM, hub-relayed
transfers, media sharing, channels) ships in `verlihub.client.nmdcpb` — see
**[NMDCpb Client Library](#nmdcpb-client-library-e2epm--hubrelay--mediashare--channels)**
below.

### Detailed documentation

| Document | Contents |
|----------|----------|
| [NMDCPB_PROTOCOL.md](https://github.com/transfix/verlihub/blob/master/docs/NMDCPB_PROTOCOL.md) | Wire format, envelope types, feature negotiation |
| [NMDCPB_IMPLEMENTATION.md](https://github.com/transfix/verlihub/blob/master/docs/NMDCPB_IMPLEMENTATION.md) | Hub plugin architecture, message flow, storage backends |
| [NMDCPB_ADMIN_GUIDE.md](https://github.com/transfix/verlihub/blob/master/docs/NMDCPB_ADMIN_GUIDE.md) | Commands, REST/WebSocket API, dashboard, config, troubleshooting |
| [NMDCPB_PROTOCOL_WORKFLOWS.md](https://github.com/transfix/verlihub/blob/master/docs/NMDCPB_PROTOCOL_WORKFLOWS.md) | End-to-end sequence walkthroughs for every extension |

## LLM & MCP Integration

verlihub-py includes optional LLM integration that connects to any
**OpenAI-compatible backend** (Ollama, vLLM, llama.cpp, LiteLLM, OpenRouter, or a
hosted API):

- **AI Chat Assistant** — a dashboard chat tab (`POST /api/v1/llm/chat`,
  streaming over `/ws/llm-chat`) where admins ask natural-language questions and
  the LLM executes **hub tool-calls** (list users, kick, ban, read stats) and
  feeds results back for a final answer.
- **NMDC `Hub-Security` Bot** — hub users chat with an LLM-backed bot via PM or
  main chat, with session memory, a mood engine, web access (search/fetch/RSS),
  and persistent notes.
- **MCP Server** — a [Model Context Protocol](https://modelcontextprotocol.io/)
  server exposing the hub as tools/resources/prompts to AI editors (VS Code,
  Claude Desktop) over stdio or HTTP; ships the `verlihub-mcp` CLI.

Enable it in config and point `base_url` at your backend. See
**[LLM_INTEGRATION.md](https://github.com/transfix/verlihub/blob/master/python/docs/LLM_INTEGRATION.md)** for the full architecture,
configuration reference, setup guides (Ollama/vLLM/llama.cpp), the tool-calling
flow, bot features, and MCP server/client usage.

## Performance Benchmarks

The benchmark suite measures API performance including latency percentiles and throughput.

### Running Benchmarks

```bash
# Quick health check
verlihub-bench quick

# Full API benchmark suite
verlihub-bench api --requests 1000 --concurrency 20

# Stress test
verlihub-bench stress --requests 5000 --concurrency 50

# Detailed latency profile
verlihub-bench latency --endpoint /api/v1/hub/stats --samples 1000

# Full benchmark with all tests
verlihub-bench full --stress --websocket --output results.json
```

### Benchmark Options

```
--url, -u           API base URL (default: http://localhost:8000)
--requests, -n      Requests per benchmark (default: 100)
--concurrency, -c   Concurrent connections (default: 10)
--output, -o        Output file for results (JSON)
--token, -t         Authentication token
--username          Username for auth
--password          Password for auth
```

### Sample Output

```
======================================================================
Benchmark: GET /api/v1/hub/stats
======================================================================

Summary:
  Total Requests:    1,000
  Successful:        1,000 (100.0%)
  Failed:            0
  Total Time:        2.34s
  Throughput:        427.35 req/s

Latency (ms):
  Min:               1.234
  Max:               45.678
  Avg:               2.341
  Std Dev:           1.567
  p50 (median):      2.123
  p95:               4.567
  p99:               8.901
======================================================================
```

### Programmatic Usage

```python
import asyncio
from verlihub.benchmarks import BenchmarkRunner, BenchmarkSuite

async def run_benchmarks():
    # Create a custom benchmark suite
    suite = BenchmarkSuite("My Benchmarks")
    suite.add_endpoint("Health", "GET", "/health", num_requests=500)
    suite.add_endpoint("Stats", "GET", "/api/v1/hub/stats", num_requests=500)
    
    # Run benchmarks
    results = await suite.run(base_url="http://localhost:8000")
    
    # Print summary
    print(suite.summary())
    
    # Export to JSON
    with open("results.json", "w") as f:
        f.write(suite.to_json())

asyncio.run(run_benchmarks())
```

## Client Library

### Synchronous Client

```python
from verlihub.client import HubClient

client = HubClient("http://localhost:8000")
client.login("admin", "password")

# Get hub stats
stats = client.get_stats()
print(f"Users online: {stats['user_count']}")

# List online users
users = client.get_online_users()
for user in users:
    print(f"  {user['nick']} - {user['share']}")

# Kick a user
client.kick_user("baduser", reason="Spamming")
```

### Asynchronous Client

```python
import asyncio
from verlihub.client import AsyncHubClient

async def main():
    async with AsyncHubClient("http://localhost:8000") as client:
        await client.login("admin", "password")
        stats = await client.get_stats()
        print(stats)

asyncio.run(main())
```

### NMDC Protocol Client

```python
from verlihub.client import NMDCClient

# Connect directly to hub via NMDC protocol
client = NMDCClient("192.168.1.100", 4111)
client.connect("BotNick", "password")

# Send a message
client.send_chat("Hello from Python!")

# Get user list
users = client.get_users()

client.disconnect()
```

### NMDCpb Client Library (E2EPM · HubRelay · MediaShare · Channels)

Beyond the raw protocol, verlihub-py ships a high-level **NMDCpb client**
(`verlihub.client.nmdcpb`) that speaks the protobuf overlay and exposes
ergonomic, strongly-typed APIs for the extension features. It doubles as the
reference client that validates the hub-side implementation. Requires the
`protobuf` + `cryptography` extras.

```python
from verlihub.client import NMDCpbClient  # also: WireCodec, E2EPMSession, E2EPMManager

client = NMDCpbClient("mybot", "password")
await client.connect("nmdc://hub.example.com:411")

# Structured chat / PM (protobuf)
await client.send_pb_chat("Hello from protobuf!")
await client.send_pb_pm("Alice", "Hi Alice")
```

#### End-to-end encrypted PM (E2EPM)

X25519 key exchange + ChaCha20-Poly1305, with 4-emoji verification
fingerprints and Trust-On-First-Use key continuity — negotiated
automatically on first use:

```python
client.on_e2epm_established = lambda peer, fp: print(f"Secure with {peer}: {fp}")
client.on_encrypted_pm      = lambda frm, text, enc: print(f"[E2E] {frm}: {text}")

await client.send_encrypted_pm("Alice", "Secret message")
```

Lower-level session control is available via `E2EPMManager` / `E2EPMSession`
(`initiate_session`, `handle_key_exchange`, `encrypt_message`,
`decrypt_message`).

#### Hub-relayed transfers (HubRelay)

Hub-brokered, NAT-friendly, resumable file relay with SHA-256 verification:

```python
from verlihub.client.nmdcpb.relay import RelayFileTransfer

relay = RelayFileTransfer(client, download_dir="/downloads")
info  = await relay.send_file("Alice", "/path/to/file.bin")   # -> TransferInfo (progress, speed, state)

# …or drive the protocol directly:
client.on_relay_request = lambda frm, token, purpose, size: None
await client.accept_relay(token)
await client.send_relay_data(relay_id, chunk, offset)
await client.close_relay(relay_id)

client.relay_only_mode = True    # privacy: force all transfers through the hub relay
```

Admin REST surface (dashboard, `user_class ≥ 5`) at `/dashboard/nmdcpb/api`:
`GET /relays`, `GET /relay/{id}`, `POST /relay/{id}/close`,
`POST /relay/close-all`, `POST /relay/close-user/{nick}`; live events over
the `/ws/relay` WebSocket (`relay_created` / `relay_closed`).

#### Media sharing (MediaShare)

Server-side storage with per-user quota, TTL, thumbnails, and a REST surface:

```python
from verlihub.client.nmdcpb.media_storage import MediaStorage, MediaConfig

store = MediaStorage(MediaConfig())
meta  = store.store(data, "clip.mp4", "video/mp4", uploader="mybot")   # -> MediaMeta
quota = store.get_quota("mybot")
```

REST API (per-user HMAC bearer tokens), mounted at `/api/media`:

| Endpoint | Description |
|----------|-------------|
| `POST /api/media/upload` | Upload a file (multipart) |
| `GET /api/media/{id}` | Download the file |
| `GET /api/media/{id}/thumb` | Download the thumbnail |
| `GET /api/media/{id}/meta` | Metadata JSON |
| `GET /api/media/quota` | Per-user quota |
| `DELETE /api/media/{id}` | Delete (owner or admin) |

#### Channels

Server-managed public/private channels with member roles
(`MEMBER`/`ADMIN`/`OWNER`/`READONLY`), message history, and group
sender-key encryption. Managed by
`verlihub.client.nmdcpb.channel_manager.ChannelManager` (auto-creates and
auto-joins `#general`); driven over the protobuf protocol with actions:
list / create / delete / join / leave / set-topic / kick / set-role.

#### Protobuf message types

All wire types are importable for advanced/manual use:

```python
from verlihub.client.nmdcpb.nmdcpb_pb2 import (
    PbEnvelope,
    PbPMKeyExchange, PbEncryptedPM, PbPMPlaintext,        # E2EPM
    PbMediaUpload, PbMediaMeta, PbMediaRef,               # MediaShare
    PbRelayRequest, PbRelayAck, PbRelayData, PbRelayClosed,  # HubRelay
    PbChannel, PbChannelList, PbChannelMemberUpdate,      # Channels
)
```

## Configuration

### Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `VH_API_HOST` | API bind host | `0.0.0.0` |
| `VH_API_PORT` | API bind port | `8000` |
| `VH_DB_HOST` | Database host | `localhost` |
| `VH_DB_PORT` | Database port | `3306` |
| `VH_DB_NAME` | Database name | `verlihub` |
| `VH_DB_USER` | Database user | `verlihub` |
| `VH_DB_PASS` | Database password | - |
| `VH_JWT_SECRET` | JWT signing key | (auto-generated) |
| `VH_JWT_EXPIRE_MINUTES` | Token expiration | `60` |

### Database

The API supports both MySQL and SQLite:

```python
# MySQL (production)
from verlihub.models.database import DatabaseConfig

config = DatabaseConfig(
    driver="mysql",
    host="localhost",
    port=3306,
    database="verlihub",
    username="verlihub",
    password="secret",
)

# SQLite (testing)
config = DatabaseConfig(
    driver="sqlite",
    database=":memory:",  # or path to file
)
```

## Testing

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=verlihub --cov-report=html

# Run specific test file
pytest tests/test_api_endpoints.py -v

# Run benchmark tests
pytest tests/test_benchmarks.py -v
```

### Test Results

Current test status: **188 passed, 21 skipped**

Skipped tests require C++ SWIG bindings to be built.

## Development

### Project Structure

```
python/
├── verlihub/
│   ├── api/           # FastAPI routes and app
│   ├── dashboard/     # Web dashboard templates
│   ├── client/        # Remote client library
│   ├── models/        # SQLModel database models
│   ├── benchmarks/    # Performance testing
│   └── cli.py         # Command-line interface
├── tests/             # Test suite
└── pyproject.toml     # Project configuration
```

### Adding New Endpoints

1. Create route in `verlihub/api/routes/`
2. Add to router in `verlihub/api/__init__.py`
3. Add tests in `tests/test_api_endpoints.py`
4. Update API documentation

### Adding Dashboard Pages

1. Create template in `verlihub/dashboard/templates/`
2. Add route in `verlihub/dashboard/routes.py`
3. Add navigation link in `base.html`
4. Add tests in `tests/test_dashboard.py`

## License

GPL-3.0-or-later - See [LICENSE](https://github.com/transfix/verlihub/blob/master/License.md) for details.
