[package]
name = "freenet"
version = "0.2.94"
edition = "2024"
rust-version = "1.85"
publish = true
description = "Freenet core software"
license-file = "LICENSE.md"
repository = "https://github.com/freenet/freenet-core"
readme = "README.md"

[package.metadata.freenet]
# Minimum compatible protocol version. Peers older than this are rejected.
# Updated by scripts/release.sh during releases. The env var
# FREENET_MIN_COMPATIBLE_VERSION overrides this at build time.
min-compatible-version = "0.2.64"

[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/v{ version }/freenet-{ target }.tar.gz"
pkg-fmt = "tgz"
bin-dir = "freenet"

[package.metadata.binstall.overrides.x86_64-pc-windows-msvc]
pkg-url = "{ repo }/releases/download/v{ version }/freenet-{ target }.zip"
pkg-fmt = "zip"
bin-dir = "freenet.exe"

[[bin]]
name = "freenet"
path = "src/bin/freenet.rs"

[dependencies]
ahash = { workspace = true }
anyhow = { workspace = true }
aes-gcm = { workspace = true }
# Argon2id for passphrase-derived bundle keys in `freenet secrets export/import`
# (P3 of #4381). `zeroize` wipes the derived output buffer; we use the low-level
# `Argon2::hash_password_into` API (not the PHC-string `password_hash` path) so
# the feature set is minimal.
argon2 = { version = "0.5", features = ["zeroize"] }
axum = { default-features = false, features = ["http1", "matched-path", "query", "tower-log", "ws", "json"], workspace = true }
bincode = { workspace = true }
blake3 = { workspace = true }
boot-time = { workspace = true }
bs58 = { workspace = true }
byteorder = { workspace = true }
bytes = { workspace = true }
chacha20poly1305 = { workspace = true }
chrono = { workspace = true }
# CBOR (de)serialization of the self-describing secret-export bundle payload
# (P3 of #4381). Already a transitive dep via fdev/website-contract; pulled in
# here directly for the export/import module.
ciborium = "0.2"
clap = { features = ["derive", "env"], workspace = true }
cookie = "0.18"
ctrlc = { features = ["termination"], workspace = true }
dashmap = { workspace = true }
delegate = { workspace = true }
directories = { workspace = true }
dirs = { workspace = true }
either = { features = ["serde"], workspace = true }
event-listener = { workspace = true }
flate2 = { workspace = true }
flatbuffers = { workspace = true }
futures = { workspace = true }
semver = { workspace = true }
headers = { workspace = true }
hex = { workspace = true }
hickory-resolver = { workspace = true }
hostname = "0.4"
ipnet = { version = "2", features = ["serde"] }
notify = { workspace = true }
pav_regression = { workspace = true }
parking_lot = { workspace = true }
renegade-ml = { workspace = true }
pin-project = { workspace = true }
rand = { features = ["small_rng"], workspace = true }
redb = { workspace = true, optional = true }
serde = { features = ["derive", "rc"], workspace = true }
serde_json = { workspace = true }
socket2 = { workspace = true }
toml = { workspace = true }
serde_with = { workspace = true }
sqlx = { workspace = true, features = ["runtime-tokio", "tls-rustls-ring", "sqlite"], optional = true }
moka = { workspace = true }
tar = { workspace = true }
tempfile = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["fs", "macros", "rt-multi-thread", "signal", "sync", "process", "tracing", "time", "test-util"] }
tokio-tungstenite = { workspace = true }
tokio-util = { workspace = true, features = ["rt"] }
tower-http = { workspace = true }
ulid = { workspace = true }
zeroize = { workspace = true }
wasmtime = { workspace = true, optional = true }
# Always enabled (not gated on wasmtime-backend): debug-section rejection at
# PUT time must run regardless of which WASM execution backend is compiled in.
wasmparser = { workspace = true }
xz2 = { workspace = true }
reqwest = { workspace = true }
# Hidden (no-echo) prompt for the `freenet secrets export/import` passphrase, so
# secrets don't have to be passed on argv (where they leak via `ps`/history).
rpassword = "7"
x25519-dalek = { workspace = true }
# Verifies the ed25519 signature over the release SHA256SUMS.txt manifest in
# the auto-update path (commands/update.rs). Default features (native std) are
# sufficient — only verification (and test-only signing) is needed here.
ed25519-dalek = "2"
sha2 = { workspace = true }

# Tracing deps
opentelemetry = { workspace = true }
opentelemetry-jaeger = { workspace = true, features = ["collector_client", "isahc", "rt-tokio"], optional = true }
# In release builds, TRACE/DEBUG spans are compiled out entirely via
# release_max_level_info, reducing the number of spans EnvFilter must evaluate.
# Debug builds retain all levels. RUST_LOG can filter among compiled-in levels.
tracing = { workspace = true, features = ["release_max_level_info"] }
tracing-core = { workspace = true }
tracing-opentelemetry = { workspace = true, optional = true }
tracing-subscriber = { workspace = true, features = ["json"], optional = true }
tracing-appender = { workspace = true, optional = true }
opentelemetry-otlp = { workspace = true, optional = true }
opentelemetry_sdk = { workspace = true, optional = true }

hkdf = { workspace = true }
keyring = { workspace = true }

# internal deps
freenet-stdlib = { features = ["net"], workspace = true }
console-subscriber = { workspace = true, optional = true }
tokio-stream = { workspace = true, features = ["sync"] }
freenet-test-network = { workspace = true, optional = true }
turmoil = { workspace = true }  # Deterministic simulation scheduling (always enabled for SimNetwork)
lru = { workspace = true }

[target.'cfg(unix)'.dependencies]
libc = { workspace = true }  # For sendmmsg syscall batching on Linux

# jemalloc replaces glibc malloc to prevent memory fragmentation in long-running processes.
# Only for linux-gnu targets — musl has its own allocator and jemalloc doesn't build on musl.
[target.'cfg(all(target_os = "linux", target_env = "gnu"))'.dependencies]
tikv-jemallocator = { workspace = true }
tikv-jemalloc-ctl = { workspace = true, optional = true }

[target.'cfg(windows)'.dependencies]
winapi = { workspace = true, features = ["shellapi", "sysinfoapi", "wincon", "winuser"] }
serde = { workspace = true }
zip = { workspace = true }
tray-icon = { workspace = true }
muda = { workspace = true }
tao = { workspace = true }
wry = { workspace = true }
winreg = { workspace = true }

[target.'cfg(target_os = "macos")'.dependencies]
tray-icon = { workspace = true }
muda = { workspace = true }
tao = { workspace = true }

[dev-dependencies]
arbitrary = { workspace = true }
proptest = { workspace = true }
chrono = { features = ["arbitrary"], workspace = true }
criterion = { workspace = true }
freenet-stdlib = { features = ["net", "testing"], workspace = true }
freenet-macros = { path = "../freenet-macros" }
httptest = { workspace = true }
libc = { workspace = true }  # For sendmmsg syscall batching benchmarks
parking_lot = { workspace = true, features = ["deadlock_detection"] }
# Used by tests/in_process_restart.rs to directly probe the redb file lock as a
# negative control (issue #4401).
redb = { workspace = true }
rstest = { workspace = true }
statrs = { workspace = true }
tempfile = { workspace = true }
test-log = { workspace = true }
testresult = { workspace = true }
tokio-tungstenite = { workspace = true }
# console-subscriber = { version = "0.4" }
which = { workspace = true }
regex = { workspace = true }
serial_test = { workspace = true }
url = "2"
tower = { version = "0.5", features = ["util"] }

# CI-optimized benchmark suite (~5 min, deterministic)
[[bench]]
name = "transport_ci"
harness = false
required-features = ["bench"]

# Extended benchmark suite (~30-45 min, nightly)
# Includes high-latency paths, packet loss, large transfers, and micro-benchmarks
[[bench]]
name = "transport_extended"
harness = false
required-features = ["bench"]

# LEDBAT validation benchmarks (manual, ~3-5 min)
[[bench]]
name = "transport_ledbat"
harness = false
required-features = ["bench"]

# Manual throughput benchmarks (test harness, no criterion, ~3 sec)
[[bench]]
name = "transport_manual"
required-features = ["bench"]

# Full benchmark suite (manual, ~78 min, requires bench_full feature)
[[bench]]
name = "transport_full"
harness = false
required-features = ["bench", "bench_full"]

[build-dependencies]
chrono = { workspace = true }

[target.'cfg(windows)'.build-dependencies]
winres = "0.1"

[features]
default = ["redb", "trace", "websocket", "wasmtime-backend"]
sqlite = ["sqlx"]
trace = ["tracing-subscriber", "tracing-appender"]
trace-ot = ["opentelemetry-jaeger", "trace", "tracing-opentelemetry", "opentelemetry-otlp"]
websocket = ["axum/ws"]
testing = ["freenet-stdlib/testing", "parking_lot/deadlock_detection"]
console-subscriber = ["dep:console-subscriber"]
test-network = ["dep:freenet-test-network"]
bench = []  # Exposes internal test infrastructure for benchmarking
bench_full = []  # Enables full benchmark suite (slow, ~78 min)
# Feature to enable simulation integration tests (run separately with --test-threads=1)
simulation_tests = []
# Feature to enable nightly-only tests (long-running, resource-intensive)
nightly_tests = []
# jemalloc heap profiling (unix only). Adds profiling support on top of the always-enabled jemalloc allocator.
# Enable with MALLOC_CONF="prof:true,lg_prof_sample:19" and send SIGUSR1 to dump heap profiles.
jemalloc-prof = ["tikv-jemallocator/profiling", "dep:tikv-jemalloc-ctl"]
# WASM runtime backend
wasmtime-backend = ["dep:wasmtime"]

# ==============================================================================
# Lint Configuration
#
# These lints move runtime failure classes to compile-time errors.
# See: https://github.com/freenet/freenet-core/issues/3141
# ==============================================================================

[lints.rust]
# Catch discarded Results/Options on #[must_use] types and functions.
# This is the single highest-value lint: it turns silent failures into
# compile errors (e.g., ignored channel send results, dropped operation outcomes).
unused_must_use = "deny"

# Require `unsafe` blocks to carry a `// SAFETY: ...` comment explaining
# the invariant that makes the code sound. Prevents cargo-cult unsafe.
unsafe_op_in_unsafe_fn = "deny"

[lints.clippy]
# Disallow `let _ = expr` when `expr` is #[must_use].
# Forces explicit handling or an intentional `drop()` call.
let_underscore_must_use = "deny"

# Flag `_ =>` catch-all arms on non-exhaustive enums.
# New variants added to an enum should trigger a compile error at every
# match site, not silently fall through a wildcard.
wildcard_enum_match_arm = "warn"

# Require `// SAFETY:` comments on every `unsafe` block.
undocumented_unsafe_blocks = "deny"
