|
| 1 | +# `src/` — Binary and Library Entry Points |
| 2 | + |
| 3 | +This directory contains only the top-level wiring of the application: the binary entry points, |
| 4 | +the bootstrap sequence, and the dependency-injection container. All domain logic lives in |
| 5 | +`packages/`; this directory merely assembles and launches it. |
| 6 | + |
| 7 | +## File Map |
| 8 | + |
| 9 | +| Path | Purpose | |
| 10 | +| --------------------------- | ------------------------------------------------------------------------------------------------------------------------- | |
| 11 | +| `main.rs` | Binary entry point. Calls `app::run()`, waits for Ctrl-C, then cancels jobs and waits for graceful shutdown. | |
| 12 | +| `lib.rs` | Library crate root and crate-level documentation. Re-exports the public API used by integration tests and other binaries. | |
| 13 | +| `app.rs` | `run()` and `start()` — orchestrates the full startup sequence (setup → load data from DB → start jobs). | |
| 14 | +| `container.rs` | `AppContainer` — dependency-injection struct that holds `Arc`-wrapped instances of every per-layer container. | |
| 15 | +| `bootstrap/app.rs` | `setup()` — loads config, validates it, initializes logging and global services, builds `AppContainer`. | |
| 16 | +| `bootstrap/config.rs` | `initialize_configuration()` — reads config from the environment / file. | |
| 17 | +| `bootstrap/jobs/` | One module per service: each module exposes a starter function called from `app::start_jobs`. | |
| 18 | +| `bootstrap/jobs/manager.rs` | `JobManager` — collects `JoinHandle`s, owns the `CancellationToken`, and drives graceful shutdown. | |
| 19 | +| `bin/e2e_tests_runner.rs` | Binary that runs E2E tests by delegating to `src/console/ci/`. | |
| 20 | +| `bin/http_health_check.rs` | Minimal HTTP health-check binary used inside containers (avoids curl/wget dependency). | |
| 21 | +| `bin/profiling.rs` | Binary for Valgrind / kcachegrind profiling sessions. | |
| 22 | +| `console/` | Internal console apps (`ci/e2e`, `profiling`) used by the extra binaries above. | |
| 23 | + |
| 24 | +## Bootstrap Flow |
| 25 | + |
| 26 | +```text |
| 27 | +main() |
| 28 | + └─ app::run() |
| 29 | + ├─ bootstrap::app::setup() |
| 30 | + │ ├─ bootstrap::config::initialize_configuration() ← reads TOML / env vars |
| 31 | + │ ├─ configuration.validate() ← panics on invalid config |
| 32 | + │ ├─ initialize_global_services() ← logging, crypto seed |
| 33 | + │ └─ AppContainer::initialize(&configuration) ← builds all containers |
| 34 | + │ |
| 35 | + └─ app::start(&config, &app_container) |
| 36 | + ├─ load_data_from_database() ← peer keys, whitelist, metrics |
| 37 | + └─ start_jobs() |
| 38 | + ├─ start_swarm_coordination_registry_event_listener |
| 39 | + ├─ start_tracker_core_event_listener |
| 40 | + ├─ start_http_core_event_listener |
| 41 | + ├─ start_udp_core_event_listener |
| 42 | + ├─ start_udp_server_stats_event_listener |
| 43 | + ├─ start_udp_server_banning_event_listener |
| 44 | + ├─ start_the_udp_instances ← one job per configured UDP bind address |
| 45 | + ├─ start_the_http_instances ← one job per configured HTTP bind address |
| 46 | + ├─ start_torrent_cleanup |
| 47 | + ├─ start_peers_inactivity_update |
| 48 | + ├─ start_the_http_api |
| 49 | + └─ start_health_check_api ← always started |
| 50 | +``` |
| 51 | + |
| 52 | +Shutdown (`main`): receives `Ctrl-C` → calls `jobs.cancel()` (fires the `CancellationToken`) → |
| 53 | +waits up to 10 seconds for all `JoinHandle`s to complete. |
| 54 | + |
| 55 | +## `AppContainer` |
| 56 | + |
| 57 | +`AppContainer` (`container.rs`) is a plain struct — not a framework, not a trait object tree. |
| 58 | +It holds one `Arc<…Container>` per architectural layer: |
| 59 | + |
| 60 | +| Field | Layer / Package | |
| 61 | +| ------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | |
| 62 | +| `registar` | `server-lib` — tracks active server socket registrations | |
| 63 | +| `swarm_coordination_registry_container` | `swarm-coordination-registry` | |
| 64 | +| `tracker_core_container` | `tracker-core` | |
| 65 | +| `http_tracker_core_services` / `http_tracker_instance_containers` | `http-tracker-core` | |
| 66 | +| `udp_tracker_core_services` / `udp_tracker_server_container` / `udp_tracker_instance_containers` | `udp-tracker-core` / `udp-tracker-server` | |
| 67 | + |
| 68 | +`AppContainer::initialize` is the only place where domain containers are constructed. |
| 69 | +Every `bootstrap/jobs/` starter receives an `&Arc<AppContainer>` and pulls out exactly what it |
| 70 | +needs — no globals, no lazy statics for domain objects. |
| 71 | + |
| 72 | +## `JobManager` |
| 73 | + |
| 74 | +`JobManager` (`bootstrap/jobs/manager.rs`) is a thin wrapper around a `Vec<Job>` (each `Job` |
| 75 | +holds a name + `JoinHandle<()>`) and a shared `CancellationToken`: |
| 76 | + |
| 77 | +- `push(name, handle)` — registers a job. |
| 78 | +- `push_opt(name, handle)` — convenience for jobs that may be disabled. |
| 79 | +- `cancel()` — fires the token; all jobs that own a clone of it will observe cancellation. |
| 80 | +- `wait_for_all(timeout)` — joins all handles with a timeout, logging warnings for any that |
| 81 | + exceed it. |
| 82 | + |
| 83 | +## Adding a New Service |
| 84 | + |
| 85 | +When wiring a new server or background task, follow this checklist in order: |
| 86 | + |
| 87 | +1. **Package** — add the new crate under `packages/` with the appropriate layer prefix. |
| 88 | +2. **Container field** — add an `Arc<NewServiceContainer>` field to `AppContainer` and |
| 89 | + initialize it inside `AppContainer::initialize`. |
| 90 | +3. **Job launcher** — create `src/bootstrap/jobs/new_service.rs` and register it in |
| 91 | + `src/bootstrap/jobs/mod.rs`. |
| 92 | +4. **Wire into `app::start_jobs`** — call the new starter function and push its handle to |
| 93 | + `job_manager`. |
| 94 | +5. **Graceful shutdown** — ensure the new service listens for the `CancellationToken` passed |
| 95 | + from `JobManager`. |
| 96 | +6. **Config guard** — if the service is optional, gate the starter behind the appropriate |
| 97 | + config field and use `push_opt`. |
| 98 | + |
| 99 | +## Key Rules for This Directory |
| 100 | + |
| 101 | +- **No domain logic here.** This directory is pure wiring. Business rules belong in `packages/`. |
| 102 | +- **No globals for domain objects.** All state flows through `AppContainer`. |
| 103 | +- **Startup errors panic.** `bootstrap::app::setup()` panics on invalid config or a bad crypto |
| 104 | + seed — this is intentional (fail fast before binding ports). |
| 105 | +- **Health check always starts.** The health-check API job is unconditional — do not gate it |
| 106 | + behind a config flag. |
| 107 | +- **`lib.rs` is the integration-test surface.** Integration tests import |
| 108 | + `torrust_tracker_lib::…`. Keep the public API in `lib.rs` stable; avoid leaking internal |
| 109 | + bootstrap details. |
0 commit comments