# Dereth Tracker

Dereth Tracker is a real-time telemetry service for the world of Dereth. It collects player data, stores it in a SQLite database, and provides a live map interface along with a sample data generator for testing.

## Table of Contents
- [Overview](#overview)
- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [API Reference](#api-reference)
- [Frontend](#frontend)
- [Database Schema](#database-schema)
- [Contributing](#contributing)

## Overview

This project provides:
- A FastAPI backend with endpoints for receiving and querying telemetry data.
- SQLite-based storage for snapshots and live state.
- A live, interactive map using static HTML, CSS, and JavaScript.
- A sample data generator script (`generate_data.py`) for simulating telemetry snapshots.

## Features

- **WebSocket /ws/position**: Stream telemetry snapshots (protected by a shared secret).
- **GET /live**: Fetch active players seen in the last 30 seconds.
- **GET /history**: Retrieve historical telemetry data with optional time filtering.
- **GET /debug**: Health check endpoint.
- **Live Map**: Interactive map interface with panning, zooming, and sorting.
- **Sample Data Generator**: `generate_data.py` sends telemetry snapshots over WebSocket for testing.

## Requirements

- Python 3.9 or newer
- pip
- (Optional) virtual environment tool (venv)

Python packages:

- fastapi
- uvicorn
- pydantic
- pandas
- matplotlib
- websockets  # required for sample data generator

## Installation

1. Clone the repository:
   ```bash
   git clone https://github.com/yourusername/dereth-tracker.git
   cd dereth-tracker
   ```
2. Create and activate a virtual environment:
   ```bash
   python3 -m venv venv
   source venv/bin/activate  # Windows: venv\Scripts\activate
   ```
3. Install dependencies:
   ```bash
   pip install fastapi uvicorn pydantic pandas matplotlib websockets
   ```

## Configuration

- Update the `SHARED_SECRET` in `main.py` to match your plugin (default: `"your_shared_secret"`).
- The SQLite database file `dereth.db` is created in the project root. To change the path, edit `DB_FILE` in `db.py`.
- To limit the maximum database size, set the environment variable `DB_MAX_SIZE_MB` (default: 2048 MB).

## Usage

Start the server using Uvicorn:

```bash
uvicorn main:app --reload --host 0.0.0.0 --port 8000
```

## NGINX Proxy Configuration

If you cannot reassign the existing `/live` and `/trails` routes, you can namespace this service under `/api` (or any other prefix) and configure NGINX accordingly. Be sure to forward WebSocket upgrade headers so that `/ws/live` and `/ws/position` continue to work. Example:
```nginx
location /api/ {
  proxy_pass         http://127.0.0.1:8765/;
   proxy_http_version 1.1;
  proxy_set_header   Host              $host;
  proxy_set_header   X-Real-IP         $remote_addr;
  proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
  proxy_set_header   X-Forwarded-Proto $scheme;
  # WebSocket support
  proxy_set_header   Upgrade           $http_upgrade;
  proxy_set_header   Connection        "upgrade";
  proxy_cache_bypass $http_upgrade;
}
```
Then the browser client (static/script.js) will fetch `/api/live/` and `/api/trails/` to reach this new server.

- Live Map: `http://localhost:8000/` (or `http://<your-domain>/api/` if behind a prefix)

### Frontend Configuration

- In `static/script.js`, the constant `API_BASE` controls where live/trails data and WebSocket `/ws/live` are fetched. By default:
  ```js
  const API_BASE = '/api';
  ```
  Update `API_BASE` if you mount the service under a different path or serve it at root.

### Debugging WebSockets

- Server logs now print every incoming WebSocket frame in `main.py`:
  - `[WS-PLUGIN RX] <client>: <raw-payload>` for plugin messages on `/ws/position`
  - `[WS-LIVE RX]   <client>: <parsed-json>` for browser messages on `/ws/live`
- Use these logs to verify messages and troubleshoot handshake failures.

### Styling Adjustments

- Chat input bar is fixed at the bottom of the chat window (`.chat-form { position:absolute; bottom:0; }`).
- Input text and placeholder are white for readability (`.chat-input, .chat-input::placeholder { color:#fff; }`).
- Incoming chat messages forced white via `.chat-messages div { color:#fff !important; }`.

## API Reference

### WebSocket /ws/position
Stream telemetry snapshots over a WebSocket connection. Provide your shared secret either as a query parameter or WebSocket header:

```
ws://<host>:<port>/ws/position?secret=<shared_secret>
```
or
```
X-Plugin-Secret: <shared_secret>
```

After connecting, send JSON messages matching the `TelemetrySnapshot` schema. For example:

```json
{
  "type": "telemetry",
  "character_name": "Dunking Rares",
  "char_tag": "moss",
  "session_id": "dunk-20250422-xyz",
  "timestamp": "2025-04-22T13:45:00Z",
  "ew": 123.4,
  "ns": 567.8,
  "z": 10.2,
  "kills": 42,
  "deaths": 1,
  "rares_found": 2,
  "prismatic_taper_count": 17,
  "vt_state": "Combat",
  "kills_per_hour": "N/A",
  "onlinetime": "00:05:00"
}
```

### Chat messages
You can also send chat envelopes over the same WebSocket to display messages in the browser. Fields:
- `type`: must be "chat"
- `character_name`: target player name
- `text`: message content
- `color` (optional): CSS color string (e.g. "#ff8800"); if sent as an integer (0xRRGGBB), it will be converted to hex.

Example chat payload:
```json
{
  "type": "chat",
  "character_name": "MyCharacter",
  "text": "Hello world!",
  "color": "#88f"
}
```

### GET /live
Returns active players seen within the last 30 seconds:

```json
{
  "players": [ { ... } ]
}
```

### GET /history
Retrieve historical snapshots with optional `from` and `to` ISO8601 timestamps:

```
GET /history?from=2025-04-22T12:00:00Z&to=2025-04-22T13:00:00Z
```

Response:

```json
{
  "data": [ { ... } ]
}
```

## Frontend

- **Live Map**: `static/index.html` – Real-time player positions on a map.

## Database Schema

- **telemetry_log**: Stored history of snapshots.
- **live_state**: Current snapshot per character (upserted).

## Contributing

Contributions are welcome! Feel free to open issues or submit pull requests.
