How SpeedLimitController Manages Upload and Download Speed Limits in Motrix
The SpeedLimitController orchestrates bandwidth regulation by computing effective caps from user settings, schedule windows, and adaptive network conditions, then applies them to the download engine every 60 seconds.
The SpeedLimitController in the Motrix download manager provides a rule-driven system for regulating network bandwidth. Located in src/core/speed-limit/speed-limit-controller.ts, this TypeScript class aggregates multiple speed limit sources—base configurations, scheduled alternatives, turtle mode, and adaptive network sensing—into a single effective profile applied to the underlying aria2 engine.
Architecture of the Speed Limit System
Core Dependencies and Settings Retrieval
The controller initializes with a getSettings callback that returns user-defined SpeedLimitSettings containing base, alt, auto, and turtle configurations. These settings define the raw bandwidth caps before any runtime logic is applied.
const controller = new SpeedLimitController({
getSettings: () => speedLimitStore.get(),
applyLimits: async (profile) => engine.setSpeedLimits(profile),
getEngineState: () => engine.state,
emit: (ch, payload) => ipc.send(ch, payload),
isVideoAppRunning: () => videoProbe.isRunning(),
})
Computing Effective Upload and Download Caps
The controller delegates limit calculation to computeEffectiveLimits in src/core/speed-limit/effective-limits.ts. This function evaluates multiple candidate caps and returns the most restrictive non-zero value.
The Limit Selection Algorithm
The algorithm builds a list of candidate download and upload caps:
- Base limits are always included as the default ceiling.
- Turtle mode caps both directions to the minimum of base and alt limits when enabled.
- Auto mode adds alt limits when the current time falls within a schedule window (
withinWindow) or when a video application is detected running. - Adaptive mode inserts a head-room-adjusted cap derived from real-time network link speed measurements.
The helper function minCap selects the smallest non-zero value from this collection, treating 0 as "unlimited". This ensures the most restrictive active rule always takes precedence.
const currentLimits = controller.getEffective()
console.log(`Download ≤ ${currentLimits.download} KiB/s, Upload ≤ ${currentLimits.upload} KiB/s`)
Applying Limits to the Download Engine
When the engine reports EngineState.Ready, the controller invokes applyLimits with the computed SpeedLimitProfile. The controller tracks the last pushed profile in a lastPushed variable to avoid redundant updates.
If the new profile differs from the previous state, the controller emits a SpeedLimitChanged event containing the complete SpeedLimitState. This payload includes the turtle status, effective profile values, and the active reason for the limit, allowing UI components to display real-time feedback.
Lifecycle Management and Periodic Enforcement
Timer-Based Recomputation
The start() method creates a periodic timer using SCHEDULE_TICK_MS = 60000 (60 seconds). This ensures schedule-based speed limit changes take effect without requiring user interaction, even if the system clock crosses a schedule boundary.
// Start periodic enforcement
controller.start()
// Force recompute when engine becomes ready
engine.on('ready', () => controller.onEngineReady())
Graceful Shutdown and State Invalidation
The stop() method halts the recomputation timer and increments an internal generation counter. This counter invalidates any pending asynchronous work, preventing race conditions when the controller shuts down or restarts.
The onEngineReady() hook forces an immediate limit push when the engine transitions to the Ready state, ensuring bandwidth restrictions apply as soon as the download backend becomes available.
Determining the Active Limit Reason
For debugging and transparency, the private reasonFor method determines why a specific limit is active. It analyzes the current settings, time, and video application status to return one of the following reasons: base, turtle, schedule, videoApp, adaptive, or none.
This reason string becomes part of the emitted SpeedLimitState, allowing the Motrix interface to display informative labels like "Limited by video detection" or "Turtle mode active" alongside the current speed cap values.
Summary
- Centralized calculation: The
SpeedLimitControllerinsrc/core/speed-limit/speed-limit-controller.tsaggregates settings and delegates computation tocomputeEffectiveLimits. - Multi-source logic: Effective caps derive from base settings, turtle mode, scheduled windows, video-app detection, and adaptive network sensing.
- Conservative application: The
minCaphelper enforces the most restrictive non-zero limit, treating zero as unlimited bandwidth. - Periodic enforcement: A 60-second timer ensures schedule-based limits update automatically without user intervention.
- State transparency: The
reasonFormethod provides UI-friendly explanations for why specific limits are active.
Frequently Asked Questions
How often does SpeedLimitController update speed limits in Motrix?
The controller recomputes and applies limits every 60 seconds via a periodic timer initialized in the start() method with SCHEDULE_TICK_MS = 60000. Additionally, onEngineReady() forces an immediate update whenever the engine transitions to the Ready state.
What happens when turtle mode is enabled?
When turtle mode is active, the controller caps both download and upload speeds to the minimum of the base and alternative (alt) limits. This is calculated in computeEffectiveLimits by comparing the two values and selecting the smaller non-zero cap.
Why does my speed limit show as "unlimited" when I set it to zero?
The minCap helper function in src/core/speed-limit/effective-limits.ts treats 0 as representing unlimited bandwidth. When collecting candidate caps, zero values are excluded from the minimum calculation, allowing higher non-zero limits or truly unlimited speeds to take effect.
How does Motrix detect when to apply schedule-based speed limits?
The computeEffectiveLimits function checks if the current time falls within a defined schedule window using the withinWindow predicate. When auto mode is enabled and the time matches a scheduled window—or when a video application is running—the alternative (alt) limits are added to the candidate pool for consideration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →