Architecture
mirror.py maintains local copies of remote package repositories on Linux. Its normal service mode separates scheduling and state management from subprocess execution. It also offers foreground commands for one-off synchronization.
Runtime modes
master.sock
mirror tui/push/reload ───────────────▶ MasterServer
│
mirror daemon │ schedules and tracks
├─ MasterServer ▼
└─ WorkerClientSupervisor ─────────▶ sync plug-in
▲ │ execute_command RPC
│ job_finished ▼
└────────────────────── WorkerServer ──▶ subprocess
mirror worker
mirror standalone ──▶ sync plug-in ──▶ foreground subprocess
mirror worker-execute ubuntu/jigdo ──▶ specialized foreground workflow
The master owns configuration, scheduling, package state, per-run logging, and
the client-facing RPC API. The worker owns subprocess lifetimes. If the master
restarts, a running subprocess remains under the worker. A supervised
WorkerClient reconnects with exponential backoff, and the worker retries
completion notifications for finished jobs.
mirror standalone activates the same sync plug-ins without either socket
server. Calls that would normally delegate to the worker instead use the
foreground process runner, and completion is returned to the CLI without
persisting daemon status files.
The worker-execute commands are another foreground path. They expose the
specialized Ubuntu and jigdo workflows used as subprocess entry points by those
daemon sync methods. The apt-mirror2 and debmirror methods use private Python
wrapper entry points instead, allowing repository discovery and native tool
execution to happen under the worker’s identity and environment.
Master-worker flow
The daemon loads the main configuration and runtime state, registers enabled plug-ins, initializes logging, and starts
MasterServer.Starting the master also starts
WorkerClientSupervisor, which maintains a persistent connection toworker.sock.Once per second, the daemon skips disabled and running packages, then checks
lastsync,syncrate, and the error retry interval to decide what is due.mirror.sync.start()records the running log andSYNCstatus, then invokes the selected sync plug-in in a daemon thread.The plug-in validates settings, builds its command, and calls
mirror.socket.worker.execute_command(). The worker starts the process with the configured UID, GID, environment, and log destination.When the process exits, the worker broadcasts
job_finished. The master callsmirror.sync.on_sync_done(), runs the plug-in completion hook when present, finalizes the log, changes the status toACTIVEorERROR, and persists state.
The daemon also reconciles package state with worker jobs. It repairs a package
whose worker job is running but whose status is stale, and eventually marks a
stale SYNC package as ERROR when the worker no longer has its job. An
optional global maximum runtime watchdog stops overlong worker jobs.
Client-facing master RPC
The master socket serves the TUI and command-line control clients. Its handlers
provide health and runtime information, package listing, manual start and stop,
push-triggered synchronization, and configuration reload. The daemon writes the
active master socket path to /var/run/mirror/master.sock.path; clients prefer
that metadata when --socket is omitted.
The TUI keeps one MasterClient connection, polls package state once per
second, and performs manual start/stop RPCs outside the UI event loop. Its log
reader accepts only regular non-symlink files under the configured package log
root, supports plain and gzip files, and keeps bounded disk-backed windows while
paging large logs.
Socket protocol
Master and worker IPC uses length-prefixed JSON frames over Unix domain sockets. Every connection completes a three-step handshake—server information, client information, then confirmation—before application messages are handled. The framing supports request/response RPCs and asynchronous notifications on the same persistent connection.
The two sockets have distinct roles:
master.sockaccepts control and status RPCs from CLI clients.worker.sockaccepts process-management RPCs from the master and sendsjob_finishednotifications back over connected clients.
Plug-in lifecycle
The plug-in framework is active and has two loading phases:
Package import registers the built-in sync plug-ins so package validation knows every built-in method.
Configuration loading applies built-in enable/disable settings and discovers third-party entry points from
mirror.sync,mirror.event, andmirror.status.
External plug-ins declare a (major, minor) API version. Incompatible major
versions and plug-ins that require a newer minor version are skipped. Sync
plug-ins supply execution hooks, event plug-ins register event handlers, and
status plug-ins can extend or transform status payloads or write additional
status outputs.
Per-plug-in JSON configuration is stored beside the main configuration and is
read lazily. A plug-in may expose a create_config callback, invoked explicitly
with mirror plugin config create; normal daemon startup never creates or
rewrites plug-in configuration.
Module map
Module |
Responsibility |
|---|---|
|
Click entry point and top-level command registration. |
|
Service, control, TUI, plug-in, standalone, and worker-workflow commands. |
|
Main JSON loading, safe runtime reload, state persistence, and web status output. |
|
Configuration, package, settings, and status data structures. |
|
Framed Unix socket protocol plus master and worker clients and servers. |
|
Built-in sync plug-ins, scheduling state, and completion handling. |
|
Foreground and background subprocess lifecycle, log merging, and pruning. |
|
Built-in registration, external entry-point loading, API compatibility, and status hooks. |
|
Priority-based event publication and subscription. |
|
Daemon and package logging, rotation, compression, and ownership. |
|
Duration parsing, command lookup, and other shared utilities. |
Persistence and paths
Path |
Purpose |
Written during daemon runtime? |
|---|---|---|
|
Operator-supplied main configuration |
No |
|
Persistent package runtime state |
Yes, by atomic replacement |
|
PID, socket, and active socket-path metadata |
Yes |
|
Daemon and per-package logs |
Yes |
|
Web-facing package status |
Yes, by atomic replacement |
The main configuration is read-only after provisioning. mirror setup creates
it only when it is absent. Runtime status, error counts, log paths, and
timestamps belong in stat.json; web-facing state belongs in status.json.
Plug-in status outputs are separate files owned by their plug-ins.
Built-in sync methods
Method |
Execution model |
|---|---|
|
Validates rsync options, optionally checks FFTS metadata, then delegates rsync to the worker. |
|
Creates a temporary archvsync environment, preferring a git clone and falling back to the bundled archive, then delegates |
|
Builds a validated lftp mirror script and delegates it to the worker. |
|
Runs the PyPI mirror command through the worker. |
|
Verifies that the authoritative local destination exists; no subprocess is needed. |
|
Delegates the |
|
Delegates the |
|
Builds a native debmirror command, discovers omitted distributions, sections, and architectures inside the worker wrapper, and runs with isolated debmirror configuration. |
|
Resolves one or more APT repositories inside the worker wrapper, generates a temporary apt-mirror2 configuration, and runs the optional |