ElixirTorrent
BitTorrent client engine for Elixir/OTP — embed downloads in your own app with a small, stable public API.
About
This is a fully functional BitTorrent client that actually downloads torrents — not a stub or protocol sketch. It started as a course project for Functional Programming with Elixir at Sofia University. After the course ended, development continued in spare time until it was ready to publish on Hex.
| Hex | hex.pm/packages/elixir_torrent |
| Docs | hexdocs.pm/elixir_torrent |
| Changelog | hexdocs.pm/elixir_torrent/changelog.html |
| Source | github.com/daniboybye/ElixirTorrent |
ElixirTorrent Web (desktop app)
Need a full client, not just the library? ElixirTorrent Web is the official Phoenix LiveView UI for this engine, shipped as a native macOS desktop app.
- Repository:github.com/daniboybye/ElixirTorrentWebUI
- Download (macOS Apple Silicon):Release 0.1.0
The sections below cover the engine API for Elixir developers embedding BitTorrent in their own apps.
Installation
Add elixir_torrent to your list of dependencies in mix.exs:
def deps do
[
{:elixir_torrent, "~> 0.2.0"}
]
end
Then fetch and start the application:
mix deps.get
# In your Application.start/2 or before first use:
Application.ensure_all_started(:elixir_torrent)
Requires Elixir 1.20+.
Quick start
Application.ensure_all_started(:elixir_torrent)
{:ok, pid} = ElixirTorrent.download("/path/to/file.torrent")
[hash] = ElixirTorrent.list()
{:ok, stats} =
ElixirTorrent.stats(pid, [:name, :speed, :downloaded, :bytes_size])
# stats.name, stats.speed.download, stats.speed.upload, …
files = ElixirTorrent.list_files(hash)
# Each entry has :path, :progress, :complete?, etc.
Poll stats/2 while the download runs. When you are done monitoring, call
stop_and_serialize/1 (see below) or remove/2 to drop the torrent from the active session.
Session persistence
The engine can save and restore download progress across process restarts.
On disk:{File.cwd!()}/.elixir_torrent/state/{hex_info_hash}.term
Each file stores the bitfield, byte counters, and peer status. When you call
download/1 with a .torrent that was previously saved, the engine loads the
session, verifies pieces against disk, and resumes from the saved bitfield.
Persist before exit:
ElixirTorrent.stop_and_serialize(hash)
# or, for every active torrent:
ElixirTorrent.stop_all_and_serialize()
Remove without keeping progress:
ElixirTorrent.remove(hash)
# also delete downloaded files:
ElixirTorrent.remove(hash, delete_data: true)
remove/2 deletes the session file. stop_and_serialize/1 writes a fresh snapshot and keeps the torrent removable on the next boot via the same .torrent path.
Graceful shutdown
stop_and_serialize/1 runs, in order:
- Stop active piece downloads
- Disconnect all peers (BEP 3 cancel / not interested / choke, then TCP close)
- Send tracker announce with
event=stopped - Write session state to
.elixir_torrent/state/ - Stop the torrent OTP process
Use this when your application shuts down and you want downloads to resume later.
stop_all_and_serialize/0 applies the same steps to every running torrent.
Public API
Full reference: hexdocs.pm/elixir_torrent/ElixirTorrent.html
| Function | Description |
|---|---|
download/1 | Start a download from a local .torrent path; returns {:ok, pid} |
stats/2 | Runtime stats map (:name, :speed, :downloaded, :bytes_size, …) |
list/0 | Info hashes for all active torrent processes |
list_files/1 | Per-file paths and download progress |
stop_and_serialize/1 | Graceful stop + persist session |
stop_all_and_serialize/0 | Graceful stop + persist for every torrent |
remove/2 | Stop and drop from session; optional delete_data: true |
get/2 | Low-level field access (prefer stats/2) |
version/0 | Client peer ID prefix (ET0-2-0, BEP 20) |
Supported BEPs
| BEP | Topic |
|---|---|
| BEP 3 | BitTorrent protocol |
| BEP 4 | Known number allocations |
| BEP 6 | Fast extension |
| BEP 7 | IPv6 tracker extension |
| BEP 12 | Multitracker metadata |
| BEP 15 | UDP tracker protocol |
| BEP 20 | Peer ID conventions |
| BEP 23 | Compact peer lists |
| BEP 24 | Tracker returns external IP |
| BEP 31 | Failure retry extension |
CLI (escript)
The package builds an escript for ad-hoc testing:
mix escript.build
./elixir_torrent
# then type: download /path/to/file.torrent
For production use, call the API from your OTP application instead.