torrust-actix 4.2.15

A rich, fast and efficient Bittorrent Tracker.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
# Torrust-Actix Tracker
![Test](https://github.com/Power2All/torrust-actix/actions/workflows/rust.yml/badge.svg)
[<img src="https://img.shields.io/badge/DockerHub-link-blue.svg">](<https://hub.docker.com/r/power2all/torrust-actix>)
[<img src="https://img.shields.io/discord/1476196704163201059?label=Discord">](<https://discord.gg/zMyZJz4U2D>)

## Project Description
Torrust-Actix Tracker is a lightweight but incredibly powerful and feature-rich BitTorrent Tracker made using Rust.

Currently, it's being actively used at https://www.gbitt.info/.

This project originated from Torrust-Tracker code originally developed by Mick van Dijke, further developed by Power2All as alternative for OpenTracker and other tracker code available on GitHub.

## Features
* [X] Block array for TCP tracking (HTTP/HTTPS), UDP tracking and API (HTTP/HTTPS)
* [X] Full IPv4 and IPv6 support
* [X] Persistence saving supported using SQLite3, MySQL or PostgresSQL database
* [X] Customize table and database structure in the configuration
* [X] Whitelist system for private tracking
* [X] Blacklist system for blocking unwelcome hashes
* [X] Torrent key support for locking access to announcement through keys as info_hash with a timeout
* [X] User account support, configurable for also database support
* [X] Swagger UI built-in in the API (toggleable), useful both for testing API and documentation for API
* [X] Sentry SaaS and self-hosted support
* [X] Full Stand-Alone/Master/Slave cluster mode
* [X] Optional Redis/Memcache Caching for peers data (can be used to show on a website for instance, to less burden SQL)
* [X] Cloudflare's "Simple Proxy Protocol" support added (https://developers.cloudflare.com/spectrum/how-to/enable-proxy-protocol/#enable-simple-proxy-protocol-for-udp)
* [X] RtcTorrent implementation (as alternative/replacement for WebTorrent)
* [X] Configurable LZ4/Zstd compression for RTC SDP data (lz4 default, enabled by default)
* [X] Adding UDP receive method with recvmmsg or io_uring

## Implemented BEPs
* [BEP 3](https://www.bittorrent.org/beps/bep_0003.html): The BitTorrent Protocol
* [BEP 7](https://www.bittorrent.org/beps/bep_0007.html): IPv6 Support
* [BEP 15](https://www.bittorrent.org/beps/bep_0015.html): UDP Tracker Protocol for BitTorrent
* [BEP 23](https://www.bittorrent.org/beps/bep_0023.html): Tracker Returns Compact Peer Lists
* [BEP 41](https://www.bittorrent.org/beps/bep_0041.html): UDP Tracker Protocol Extensions
* [BEP 48](https://www.bittorrent.org/beps/bep_0048.html): Tracker Protocol Extension: Scrape

## Getting Started
You can get the latest binaries from [releases](https://github.com/Power2All/torrust-actix/releases) or follow the installation from scratch instructions below.

### Install From Scratch
1. Clone the repository:
```bash
git clone https://github.com/Power2All/torrust-actix.git
cd torrust-actix
```

2. Build the source code using Rust (make sure you have installed rustup with stable branch)
#### Using build script
```bash
cargo build --release
```

> **Note:** `lib/torrust-client` (the optional desktop GUI) is **excluded from the default build**.
> It requires the `fontconfig` system library and a graphical environment (Slint UI framework).
> See [lib/torrust-client — Optional GUI](#optional-gui-torrust-client) below for details.

### Optional GUI: torrust-client

`lib/torrust-client` is a desktop GUI front-end built with the [Slint](https://slint.dev/) UI framework.
It is a workspace member but is **not compiled by default** (`default-members` excludes it).

#### System requirements (Linux)

```bash
# Debian / Ubuntu
sudo apt-get install libfontconfig1-dev

# Fedora / RHEL
sudo dnf install fontconfig-devel

# Arch
sudo pacman -S fontconfig
```

#### Building

```bash
# Build only the GUI client
cargo build --release -p torrust-client

# Or build the entire workspace including the GUI
cargo build --release --workspace
```

### Usage
Run the code using `--help` argument for using in your environment:
```bash
./target/release/torrust-actix --help
```
Before you can run the server, you need to either have persistence turned off, and when enabled, make sure your database is created and working. See the help argument above how to fix your setup as you wish.

Swagger UI is introduced, and when enabled in the configuration, is accessible through the API via `/swagger-ui/`.

Sentry.io support is introduced, you can enable it in the configuration and the URL where to push the data to.

### Run on Docker
To run this application in Docker, we provided a Docker Compose file that you can use to run it locally or remotely.

You can find it in the "docker" folder called "docker-compose.yml", and in order to deploy it, use the following commands:

```
docker compose build .
docker compose start
```

### Environment Variable Overrides

Use environment variables to override the configuration settings.

```
LOG_LEVEL <off | trace | debug | info | warn | error>
LOG_CONSOLE_INTERVAL <UINT64>

TRACKER__API_KEY <STRING>
TRACKER__WHITELIST_ENABLED <true | false>
TRACKER__BLACKLIST_ENABLED <true | false>
TRACKER__KEYS_ENABLED <true | false>
TRACKER__USERS_ENABLED <true | false>
TRACKER__SWAGGER <true | false>
TRACKER__KEYS_CLEANUP_INTERVAL <UINT64>
TRACKER__REQUEST_INTERVAL <UINT64>
TRACKER__REQUEST_INTERVAL_MINIMUM <UINT64>
TRACKER__PEERS_TIMEOUT <UINT64>
TRACKER__PEERS_CLEANUP_INTERVAL <UINT64>
TRACKER__PEERS_CLEANUP_THREADS <UINT64>
TRACKER__PROMETHEUS_ID <STRING>
TRACKER__RTC_INTERVAL <UINT64>
TRACKER__RTC_PEERS_TIMEOUT <UINT64>
TRACKER__TOTAL_DOWNLOADS <UINT64>
TRACKER__RTC_COMPRESSION_ENABLED <true | false>
TRACKER__RTC_COMPRESSION_ALGORITHM <lz4 | zstd>
TRACKER__RTC_COMPRESSION_LEVEL <UINT64>

TRACKER__CLUSTER <standalone | master | slave>
TRACKER__CLUSTER_ENCODING <binary | json | msgpack>
TRACKER__CLUSTER_TOKEN <STRING>
TRACKER__CLUSTER_BIND_ADDRESS <STRING>
TRACKER__CLUSTER_MASTER_ADDRESS <STRING>
TRACKER__CLUSTER_KEEP_ALIVE <UINT64>
TRACKER__CLUSTER_REQUEST_TIMEOUT <UINT64>
TRACKER__CLUSTER_DISCONNECT_TIMEOUT <UINT64>
TRACKER__CLUSTER_RECONNECT_INTERVAL <UINT64>
TRACKER__CLUSTER_MAX_CONNECTIONS <UINT64>
TRACKER__CLUSTER_THREADS <UINT64>
TRACKER__CLUSTER_SSL <true | false>
TRACKER__CLUSTER_SSL_KEY <STRING>
TRACKER__CLUSTER_SSL_CERT <STRING>
TRACKER__CLUSTER_TLS_CONNECTION_RATE <UINT64>

CACHE__ENABLED <true | false>
CACHE__ENGINE <redis | memcache>
CACHE__ADDRESS <STRING>
CACHE__PREFIX <STRING>
CACHE__TTL <UINT64>
CACHE__SPLIT_PEERS <true | false>

SENTRY__ENABLED <true | false>
SENTRY__DEBUG <true | false>
SENTRY__ATTACH_STACKTRACE <true | false>
SENTRY__SEND_DEFAULT_PII <true | false>
SENTRY__DSN <STRING>
SENTRY__MAX_BREADCRUMBS <UINT64>
SENTRY__SAMPLE_RATE <F32>
SENTRY__TRACES_SAMPLE_RATE <F32>

DATABASE__PERSISTENT <true | false>
DATABASE__INSERT_VACANT <true | false>
DATABASE__REMOVE_ACTION <true | false>
DATABASE__UPDATE_COMPLETED <true | false>
DATABASE__UPDATE_PEERS <true | false>
DATABASE__PATH <STRING>
DATABASE__ENGINE <sqlite3 | mysql | pgsql>
DATABASE__PERSISTENT_INTERVAL <UINT64>
DATABASE__CHUNK_SIZE <UINT64>

DATABASE_STRUCTURE__TORRENTS__BIN_TYPE_INFOHASH <true | false>
DATABASE_STRUCTURE__TORRENTS__TABLE_NAME <STRING>
DATABASE_STRUCTURE__TORRENTS__COLUMN_INFOHASH <STRING>
DATABASE_STRUCTURE__TORRENTS__COLUMN_SEEDS <STRING>
DATABASE_STRUCTURE__TORRENTS__COLUMN_PEERS <STRING>
DATABASE_STRUCTURE__TORRENTS__COLUMN_COMPLETED <STRING>
DATABASE_STRUCTURE__TORRENTS__PERSISTENT <true | false>

DATABASE_STRUCTURE__WHITELIST__BIN_TYPE_INFOHASH <true | false>
DATABASE_STRUCTURE__WHITELIST__TABLE_NAME <STRING>
DATABASE_STRUCTURE__WHITELIST__COLUMN_INFOHASH <STRING>
DATABASE_STRUCTURE__WHITELIST__PERSISTENT <true | false>

DATABASE_STRUCTURE__BLACKLIST__BIN_TYPE_INFOHASH <true | false>
DATABASE_STRUCTURE__BLACKLIST__TABLE_NAME <STRING>
DATABASE_STRUCTURE__BLACKLIST__COLUMN_INFOHASH <STRING>
DATABASE_STRUCTURE__BLACKLIST__PERSISTENT <true | false>

DATABASE_STRUCTURE__KEYS__BIN_TYPE_HASH <true | false>
DATABASE_STRUCTURE__KEYS__TABLE_NAME <STRING>
DATABASE_STRUCTURE__KEYS__COLUMN_HASH <STRING>
DATABASE_STRUCTURE__KEYS__COLUMN_TIMEOUT <STRING>
DATABASE_STRUCTURE__KEYS__PERSISTENT <true | false>

DATABASE_STRUCTURE__USERS__ID_UUID <true | false>
DATABASE_STRUCTURE__USERS__BIN_TYPE_KEY <true | false>
DATABASE_STRUCTURE__USERS__TABLE_NAME <STRING>
DATABASE_STRUCTURE__USERS__COLUMN_UUID <STRING>
DATABASE_STRUCTURE__USERS__COLUMN_ID <STRING>
DATABASE_STRUCTURE__USERS__COLUMN_ACTIVE <STRING>
DATABASE_STRUCTURE__USERS__COLUMN_KEY <STRING>
DATABASE_STRUCTURE__USERS__COLUMN_UPLOADED <STRING>
DATABASE_STRUCTURE__USERS__COLUMN_DOWNLOADED <STRING>
DATABASE_STRUCTURE__USERS__COLUMN_COMPLETED <STRING>
DATABASE_STRUCTURE__USERS__COLUMN_UPDATED <STRING>
DATABASE_STRUCTURE__USERS__PERSISTENT <true | false>

API_0_ENABLED <true | false>
API_0_SSL <true | false>
API_0_BIND_ADDRESS <STRING>
API_0_REAL_IP <STRING>
API_0_SSL_KEY <STRING>
API_0_SSL_CERT <STRING>
API_0_KEEP_ALIVE <UINT64>
API_0_REQUEST_TIMEOUT <UINT64>
API_0_DISCONNECT_TIMEOUT <UINT64>
API_0_MAX_CONNECTIONS <UINT64>
API_0_THREADS <UINT64>
API_0_TLS_CONNECTION_RATE <UINT64>

HTTP_0_ENABLED <true | false>
HTTP_0_SSL <true | false>
HTTP_0_BIND_ADDRESS <STRING>
HTTP_0_REAL_IP <STRING>
HTTP_0_SSL_KEY <STRING>
HTTP_0_SSL_CERT <STRING>
HTTP_0_KEEP_ALIVE <UINT64>
HTTP_0_REQUEST_TIMEOUT <UINT64>
HTTP_0_DISCONNECT_TIMEOUT <UINT64>
HTTP_0_MAX_CONNECTIONS <UINT64>
HTTP_0_THREADS <UINT64>
HTTP_0_TLS_CONNECTION_RATE <UINT64>
HTTP_0_RTCTORRENT = <true | false>

UDP_0_ENABLED <true | false>
UDP_0_BIND_ADDRESS <STRING>
UDP_0_UDP_THREADS <UINT64>
UDP_0_WORKER_THREADS <UINT64>
UDP_0_RECEIVE_BUFFER_SIZE <UINT64>
UDP_0_SEND_BUFFER_SIZE <UINT64>
UDP_0_REUSE_ADDRESS <true | false>
UDP_0_USE_PAYLOAD_IP <true | false>
UDP_0_SIMPLE_PROXY_PROTOCOL <true | false>
UDP_0_RECEIVE_METHOD <auto | recvmmsg | io_uring | rio>
```

#### Database commit chunk size

`database.chunk_size` controls how many rows the tracker writes per SQL transaction when it flushes torrent/user updates to the database (once per `persistent_interval`). Instead of committing the whole sync batch in a single long-running transaction — which holds row/foreign-key locks for the entire batch and can block other applications writing to the same database (e.g. a website doing `DELETE`/`UPDATE`, leading to lock-wait timeouts) — the tracker commits every `chunk_size` rows, releasing locks frequently.

```toml
[database]
chunk_size = 1000   # rows per transaction (default: 1000; 0 = commit the whole batch in one transaction)
```

Lower the value (e.g. `500` or `250`) if another application sharing the database still experiences lock contention; raise it (or set `0`) for maximum write throughput when the tracker owns the database exclusively. Applies to the high-volume `torrents` and `users` sync tables on MySQL, PostgreSQL, and SQLite.

---

## API Authentication

Every `/api/...` endpoint (and `/stats`, `/metrics`) is protected by the API key configured in `tracker.api_key` (or the `TRACKER__API_KEY` environment variable). The key can be supplied in two ways:

1. **`Authorization` header (recommended)** — keeps the secret out of URLs, access logs and browser history:

   ```
   Authorization: Bearer <api_key>
   ```

   The `Bearer ` prefix is optional; a bare `Authorization: <api_key>` is also accepted.

2. **`token` query-string parameter (legacy)** — kept for backwards compatibility:

   ```
   GET /api/torrents?token=<api_key>
   ```

If both are present, the `Authorization` header takes precedence. The key is compared in constant time. Example:

```bash
# Preferred — token in the header
curl -H "Authorization: Bearer <api_key>" http://127.0.0.1:8080/api/torrents

# Legacy — token in the query string
curl "http://127.0.0.1:8080/api/torrents?token=<api_key>"
```

---

## RtcTorrent — WebRTC BitTorrent in the Browser

RtcTorrent is the built-in WebRTC peer-to-peer library that lets a browser (or Node.js process) act as a BitTorrent seeder or leecher **without any browser plugin or native binary**. It uses the standard HTTP announce endpoint with additional query parameters for WebRTC signalling.

A full protocol white paper is available in [RtcTorrent.md](./RtcTorrent.md).

### How It Works

```
Browser (leecher) ──announce + rtctorrent=1──► Tracker (Torrust-Actix)
                   ◄── SDP offer from seeder ──
Browser ──answer + rtcanswerfor=<peer_id>────► Tracker
Seeder  ──poll (announce) ───────────────────► Tracker
        ◄── SDP answer ──
WebRTC Data Channel established directly between Browser ↔ Seeder
```

### Building the Browser Bundle

```bash
cd lib/rtctorrent
npm install
npm run build          # produces dist/rtctorrent.browser.js (minified)
npm run dev            # watch mode for development
```

The build outputs two bundles:

| File | Target | Use |
|------|--------|-----|
| `dist/rtctorrent.browser.js` | Browser (`<script>`) | Website player/downloader |
| `dist/rtctorrent.node.js` | Node.js (`require`) | CLI seeder, server-side |

### Using the Library on a Website

Copy `dist/rtctorrent.browser.js` to your web server's static assets, then include it in your HTML:

```html
<script src="/assets/rtctorrent.browser.js"></script>
```

#### Downloading a Torrent (Leecher)

```html
<!DOCTYPE html>
<html>
<head><title>RtcTorrent Demo</title></head>
<body>
  <video id="player" controls autoplay style="width:100%"></video>
  <script src="/assets/rtctorrent.browser.js"></script>
  <script>
    const client = new RtcTorrent({
      trackerUrl: 'http://your-tracker.example.com/announce',
      // Optional: override ICE/STUN servers
      iceServers: [
        { urls: 'stun:stun.l.google.com:19302' }
      ]
    });

    // Download via .torrent URL, magnet URI, or parsed torrent object
    client.download('magnet:?xt=urn:btih:INFOHASH&dn=MyVideo&tr=http://your-tracker.example.com/announce')
      .then(torrent => {
        console.log('Started downloading:', torrent.name);
      });

    // Stream a video file directly into a <video> element
    client.streamVideo('INFOHASH_HEX', 0, document.getElementById('player'));
  </script>
</body>
</html>
```

#### Seeding a File from the Browser

```html
<input type="file" id="filePicker">
<script src="/assets/rtctorrent.browser.js"></script>
<script>
  const client = new RtcTorrent({
    trackerUrl: 'http://your-tracker.example.com/announce'
  });

  document.getElementById('filePicker').addEventListener('change', async (e) => {
    const file = e.target.files[0];

    // Create a torrent from the selected file
    const { torrent, magnetUri, infoHash } = await client.create([file], {
      version: 'v1',   // or 'v2' / 'hybrid'
      name: file.name
    });

    console.log('Magnet URI:', magnetUri);
    console.log('Info Hash:', infoHash);

    // Start seeding — the tracker handles WebRTC signalling
    await client.seed(torrent, [file]);
  });
</script>
```

#### Constructor Options

| Option | Default | Description |
|--------|---------|-------------|
| `trackerUrl` | `''` | HTTP announce URL of the Torrust-Actix tracker |
| `announceInterval` | `30000` | Re-announce interval in milliseconds |
| `rtcInterval` | `10000` | WebRTC signalling poll interval in milliseconds |
| `maxPeers` | `50` | Maximum simultaneous WebRTC peers |
| `iceServers` | Google STUN | Array of ICE server objects |

#### Key Methods

| Method | Description |
|--------|-------------|
| `create(files, options)` | Create a torrent from File objects (browser) or file paths (Node) |
| `download(torrentData)` | Download via magnet URI, `.torrent` URL, or parsed torrent object |
| `seed(torrentData, files)` | Seed an existing torrent |
| `streamVideo(infoHash, fileIndex, videoEl)` | Stream a video piece-by-piece into a `<video>` element |
| `stop()` | Stop all torrents and close connections |
| `parseMagnet(uri)` | Parse a magnet URI into a torrent object |
| `parseTorrentFile(buffer)` | Parse a `.torrent` file buffer |
| `calculateInfoHash(info)` | Calculate the SHA-1 info hash of a torrent info dictionary |

### Tracker Configuration for RtcTorrent

Enable RtcTorrent support on the HTTP listener in `config.toml`:

```toml
[[http_trackers]]
enabled = true
bind_address = "0.0.0.0:6969"
rtctorrent = true          # Enable WebRTC signalling endpoint
```

Or via environment variable:
```
HTTP_0_RTCTORRENT=true
```

### CLI Seeder (Node.js)

The `bin/seed.js` script seeds files from the command line:

```bash
# Install dependencies
cd lib/rtctorrent && npm install

# Single file
node bin/seed.js --tracker http://your-tracker.example.com/announce \
                 --name "My Movie" \
                 --out movie.torrent \
                 /path/to/movie.mp4

# Re-seed from an existing .torrent (no re-hashing)
node bin/seed.js --torrent-file movie.torrent /path/to/movie.mp4

# Seed from a magnet URI
node bin/seed.js --magnet "magnet:?xt=urn:btih:..." /path/to/movie.mp4

# Multi-torrent mode via YAML config
node bin/seed.js --torrents torrents.yaml
```

**YAML multi-torrent config example:**

```yaml
torrents:
  - name: "My Movie"
    file:
      - "/data/movie.mp4"
    trackers:
      - "http://your-tracker.example.com/announce"
    out: "/data/movie.torrent"
    version: v1          # v1 | v2 | hybrid
    webseed:
      - "https://cdn.example.com/movie.mp4"
```

Reload the YAML config without restarting by sending `SIGHUP` (Linux/macOS) or simply saving the file (polled every 2 seconds on all platforms).

### Demo

Run the built-in demo server to test locally:

```bash
cd lib/rtctorrent
npm install && npm run build
npm run serve    # serves demo at http://localhost:8080/demo/
```

---

## Caching — Redis & Memcache

The tracker can optionally push live torrent peer statistics to a Redis or Memcache instance after every database sync cycle.  This lets websites and dashboards read seeder/leecher counts at high speed without querying the SQL database directly.

### Configuration

Add a `[cache]` section to `config.toml`:

```toml
[cache]
enabled     = true
engine      = "redis"       # "redis" or "memcache"
address     = "127.0.0.1:6379"
prefix      = "tracker:"    # key namespace prefix
ttl         = 300           # seconds until a key expires (0 = no expiry)
split_peers = false         # see "Key format" below
```

The tracker connects to Redis/Memcache **only when it writes** (once per `persistent_interval` seconds).  No persistent connection is kept open between sync cycles.

> The cache is updated independently of `database.persistent`.  Setting `persistent = false` disables SQL writes but the cache is still updated on every sync cycle.

### Key Format

Every torrent is stored under the key:

```
<prefix>t:<info_hash_hex>
```

For example, with the default prefix `tracker:` and a 40-character hex info hash:

```
tracker:t:a1b2c3d4e5f6...
```

#### Aggregated mode (`split_peers = false`, default)

The key is a Redis hash (or colon-delimited string in Memcache) with **three fields**:

| Field | Type | Description |
|-------|------|-------------|
| `s`   | u64  | Total seeders (BitTorrent IPv4 + IPv6 + WebRTC) |
| `p`   | u64  | Total leechers (BitTorrent IPv4 + IPv6 + WebRTC) |
| `c`   | u64  | Total completed downloads |

**Redis — reading aggregated data:**
```bash
HMGET tracker:t:<info_hash_hex> s p c
# returns: [seeds, peers, completed]
```

**Memcache — reading aggregated data:**
```
GET tracker:t:<info_hash_hex>
# returns: "seeds:peers:completed"  e.g. "42:100:500"
```

#### Split mode (`split_peers = true`)

Each pool and IP version is stored as a separate field, giving a full breakdown:

| Field          | Type | Description |
|----------------|------|-------------|
| `bt_seeds_ipv4` | u64 | BitTorrent IPv4 seeders |
| `bt_seeds_ipv6` | u64 | BitTorrent IPv6 seeders |
| `rtc_seeds`     | u64 | WebRTC seeders |
| `bt_peers_ipv4` | u64 | BitTorrent IPv4 leechers |
| `bt_peers_ipv6` | u64 | BitTorrent IPv6 leechers |
| `rtc_peers`     | u64 | WebRTC leechers |
| `c`             | u64 | Total completed downloads |

**Redis — reading split data:**
```bash
HGETALL tracker:t:<info_hash_hex>
# returns all seven fields as a flat key/value list

# Or fetch specific fields:
HMGET tracker:t:<info_hash_hex> bt_seeds_ipv4 bt_seeds_ipv6 rtc_seeds bt_peers_ipv4 bt_peers_ipv6 rtc_peers c
```

**Memcache — reading split data:**
```
GET tracker:t:<info_hash_hex>
# returns: "bt_seeds_ipv4:bt_seeds_ipv6:rtc_seeds:bt_peers_ipv4:bt_peers_ipv6:rtc_peers:completed"
# e.g.  "30:5:7:80:15:5:500"
#        bt4   bt6 rtc bt4  bt6 rtc completed
```

### PHP example (Redis, aggregated mode)

```php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$infoHash = bin2hex($rawInfoHashBytes); // 40-char hex
$key      = 'tracker:t:' . $infoHash;

[$seeds, $peers, $completed] = $redis->hMGet($key, ['s', 'p', 'c']);

echo "Seeders: $seeds, Leechers: $peers, Completed: $completed";
```

### PHP example (Redis, split mode)

```php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$key  = 'tracker:t:' . $infoHash;
$data = $redis->hGetAll($key);

$totalSeeders  = $data['bt_seeds_ipv4'] + $data['bt_seeds_ipv6'] + $data['rtc_seeds'];
$totalLeechers = $data['bt_peers_ipv4'] + $data['bt_peers_ipv6'] + $data['rtc_peers'];

echo "BT IPv4 seeds: {$data['bt_seeds_ipv4']}";
echo "BT IPv6 seeds: {$data['bt_seeds_ipv6']}";
echo "WebRTC seeds:  {$data['rtc_seeds']}";
```

---

### ChangeLog

#### v4.2.15
* Did some further performance tweaking
* Bumped versions
* Added full doc blocks

#### v4.2.14
* Hotfix in regard to database handling
* A full audit and security scan of the code, shown some possible vulnerabilities
* Small little performance tweaks
* Adding a better token usage by recommending a header bearer, legacy still works

#### v4.2.13
* Applied a fix for Windows, implemented RIO for Windows
* Further optimization and some refactor work to improve performance and efficiency
* Minimum Rust version is 1.88.0

#### v4.2.12
* Applied UDP traffic control performance and improvements
* Introduced a new optional config for further optimization: receive_method. This can be "auto", "recvmmsg" or "io_uring". By default, "recvmmsg" is used, but io_uring can be used when you received a lot of traffic

#### v4.2.11
* Fixing a database (PostgreSQL) implementation code (Thanks zmiguel)
* Bumping version of SQLx, needed to modify the code to use the newer SQLx functions properly

#### v4.2.10
* Various audit findings and performance fixes

#### v4.2.9
* Bumping versions
* Locking versions, cause of chain attacks, making sure we use "safe" libs

#### v4.2.8
* Hotfix for the loading of data in memory, a SQL query issue

#### v4.2.7
* Added optional "persistent" override for each table
* Did another full audit scan and fixed possible issues

#### v4.2.6
* Hot Fix for the redis/memcache system, instead of having a persistent connection, only connect when needed
* Updated the readme for some information how to use the Cache system

#### v4.2.5
* Fixing the caching mechanism, it wasn't working as expected
* Added an option (it's optional, so it won't break anything) to either split up the seeds/peers list as 2 numbers or as separate numbers in BitTorrent IPv4, IPv6 and RtcTorrent.

#### v4.2.4
* Fixing a TLS/SSL bug where more than 1 provider was available, and server didn't know what to use

#### v4.2.3
* Changed some informative data
* Bug-fix needed for the peer/torrent cleanup thread

#### v4.2.2
* Fixing versioning, added back healthcheck for Docker and fixed some other small bugs
* Added `///` / `//!` doc comments throughout the codebase for docs.rs / crates.io publishing
* Made a large set of `[tracker_config]`, `[sentry_config]`, and `[database_structure.*]` keys optional in `config.toml` — sensible defaults are applied automatically when the keys are absent
  * Optional tracker fields: `whitelist_enabled`, `blacklist_enabled`, `keys_enabled`, `keys_cleanup_interval`, `users_enabled`, `swagger`, `prometheus_id`, all `cluster_*` fields, and all `rtc_*` fields
  * The entire `[sentry_config]` section can now be omitted (defaults to disable)
  * All `[database_structure.*]` subsections can be omitted (default table/column names are used)
* `--create-config` now annotates every optional key with an inline `# Optional: defaults to …` comment so new users can see at a glance what can be left out
* Refactored `impl RtcData` out of the struct file into `src/tracker/impls/rtc_data.rs`, consistent with the rest of the project structure

#### v4.2.1
* Adding LZ4/ZSTD compression for memory objects for the RtcTorrent peer data, enabled by default, disablable through config
* Memory optimization for the peer data
* Some small bug fixes

#### v4.2.0
* Refactoring the whole project structure
* Adding security and anti-malicious validation and checks
* Adding RtcTorrent library and support to the tracker, for web streaming and downloading of BitTorrent. This is a major change from v4.1.0. It uses the default HTTP BitTorrent announce endpoint, with additional parameters

#### v4.1.1
* Added hot reloading of SSL certificates for renewal
* API has an extra endpoint to run the hot reloading
* Some more code optimizations

#### v4.1.0
* Added a full Cluster first version through WebSockets
* Option to run the app in Stand-Alone (which is default, as single server), or using the cluster mode
* When set to Master, it still functions as if being Stand-Alone, but with WebSocket support for clustering
* When set to Slave, it will forward all the requests to the Master server to be handled
* Added configurations to be applied in config.toml and the environment variables
* Added statistics, also showing cluster statistics next to the rest. Slave will only show active requests
* WebSocket data can be sent in 3 different ways, but Master server is the leading what way to talk
* This is a very early version of the WebSocket cluster implementation, and needs thorough testing
* Moved the more database engines additions to another version (and MeiliSearch/ElasticSearch support for v4.2)
* Refactored the database engine to be less massive, more logical and less redundancy
* Implemented a Redis and Memcache cache optionally to push peer data to, for usage on websites (without burdening SQL)
* Added UDP support for Cloudflare's "Simple Proxy Protocol" (https://developers.cloudflare.com/spectrum/how-to/enable-proxy-protocol/#enable-simple-proxy-protocol-for-udp)

#### v4.0.17
* Another little overhaul, changing some memory tools for enhancement and performance
* Less CPU cycles applied when requests are handled
* Preparing for v4.1 to add some more database engines to the mix apart from SQLx

#### v4.0.16
* Small debug and hotfixes
* Fixed the unit test that somehow failed
* Updated this readme file

#### v4.0.15
* More code optimizations thanks to AI scanning further
* UDP performance tweaks (some new config options added)
* Added an initial unit testing for checking if all functions and features work as expected

#### v4.0.14
* Code optimizations thanks to AI scanning
* Huge memory and CPU consumption improvement for UDP, using offloading

#### v4.0.13
* Added further UDP improvement by adding customization, also added to the config:
  * Receive Buffer Size
  * Send Buffer Size
  * Reuse of Address

#### v4.0.12
* Updating libraries and cleanup code

#### v4.0.11
* Updating libraries
* Adding healthcheck for Docker through Python check script

#### v4.0.10
* Updating libraries
* Adding full environment support to override configurations (Thanks tachyon3000 for the idea)

#### v4.0.9
* Updating libraries (Actix 4.9 to 4.10)
* Some critical exploit in ZIP fixed
* Some faulty v4.0.8 deployments fixed with GitHub

#### v4.0.8
* Updating libraries
* Fixing threading for UDP
* Removed a feature from Parking Lot, cause of an unfixed vulnerability
* Update Swagger UI to version v4.0.0 and OpenAPI version v3.1.1

#### v4.0.7
* Cleanup was still broken, did a big rewrite, after testing it works now as expected
* Did some tokio threading correctly for core threads
* Added a new configuration key, to set the threads, default for each shard (256), but can be changed

#### v4.0.6
* Fixed some clippy issues
* Found a performance issue on peers cleanup
* Switched peers cleanup from Tokio spawn to Thread spawn for speedup
* Bumped version of Tokio

#### v4.0.5
* Library bump

#### v4.0.4
* Further implementation of Sentry (trace logging)

#### v4.0.3
* Fixing announce and scrape paths, since it is the wrong way.
* Fixing various smaller bugs that isn't app-breaking, but should be handled better.
* Added support for Sentry.io SaaS and self-hosted setup.
* Preparing work for version v4.1.0, which will introduce LUA support for middleware.

#### v4.0.2
* Added option that the system will remove data from database.
* Added updates variables for the white/black list and keys tables.
* Renaming the "database" naming which should be "tables".
* A lot of fixes and bugs I stumbled upon.

#### v4.0.0
* Completely rebuilt of the tracker code, for readability.
* Moved to Actix v4, thus versioning this software to v4.0.0 as well.
* Rebuilt and remade the way configuration file is created (you need to give the command as argument for it).
* Redone the whole database system, is tested with the latest versions available at this time.
* API has gone through a lot of work and tested.
* Introduced Swagger UI as testing and documentation.
* A lot of improvements in speed and performance applied further.
* Import and Export function added, will dump or import from JSON files, handy for when making a backup from your existing database, or when migrating to an other database engine.
* Removed WebGUI, was outdated and not really useful.

#### v3.2.2
* Bumped library versions significantly, including security patches.
* Fixed changes in libraries to work properly.
* Tuned the non-persistence code to use less memory.

#### v3.2.1
* Bumped library versions, including security patches.
* Fixed a bug in the PostgreSQL handler.
* Some forgotten naming from Torrust-Axum to Torrust-Actix.

#### v3.2.0
* Bumped library versions.
* Modified the way scheduling was done through threads, it could lock up and slow down public trackers with heavy activity.
* Tweaking the SQLite3 database usage and database space consumption.
* Full overhaul on how torrents and peers are used in memory. Using crossbeam skipmap for thread safe non-locking memory sharing.
* Some various improvement on coding performance, readability and linting the files.
* Replaced Tokio Axum web framework for Actix, reason: Missing critical things like a timeout on connect, disconnect, read and write, and support was lackluster.
* Renamed the GitHub repository from torrust-axum to torrust-actix.
* Adding user tracking support with an extra key.

#### v3.1.2
* Bumped library versions.
* Added a Code of Conduct file, as some open source projects need this.
* Added a Maintenance toggle function to API and WebGUI.
* Configuration file is not generated when it doesn't exist, or has invalid data, unless forced with a '--create-config' argument.
* Fixed various small bugs.

#### v3.1.1
* Bumped library versions.
* Database for SQLite3, MySQL and PostgreSQL now works properly with all the tables, and will be used if enabled.
* UDP had a problem in IPv4, fixed the code for correctly parsing byte array.
* Cleanup and refactoring of some redundant code.
* Added some small checks where needed to prevent errors.

#### v3.1.0
* Whitelist System: You can enable this to only allow torrent hashes to be used you specify in the database, or add them through the API.
* Blacklist System: You can enable this to disallow torrent hashes to be used you specify in the database, or add them through the API.
* Keys System: You can enable this to only allow tracking when an activated "key" hash (same as an info_hash, 20 bytes or 40 characters hex) is given. Keys with a timeout of zero "0" will be permanent and won't be purged by the cleanup.
* WebGUI: The API has an available web interface, which can be accessed through https://your.api:8080/webgui/ and giving the correct API Key, which you configure in the configuration file.
* Customizable database structure can be given in the configuration file.
* The system is also now available through Docker Hub at https://hub.docker.com/r/power2all/torrust-axum

#### v3.0.1
* Bugfixes
* SQLite3 support added
* MySQL support added
* PostgresSQL support added

#### v3.0.0
Initial version of Torrust-Axum.

### Credits
This Torrust-Tracker was a joint effort by [Nautilus Cyberneering GmbH](https://nautilus-cyberneering.de/), [Dutch Bits](https://dutchbits.nl) and [Power2All](https://power2all.com).
Also thanks to [Naim A.](https://github.com/naim94a/udpt) and [greatest-ape](https://github.com/greatest-ape/aquatic) for some parts in the Torrust-Tracker code.
This project (Torrust-Actix) is built from scratch by [Power2All](https://power2all.com).