pub struct Monitor {
pub config: MonitorConfig,
pub pauses: Pauses,
pub workdays: Workdays,
pub last_activity: Arc<Mutex<Instant>>,
pub activity_start: Arc<Mutex<Option<Instant>>>,
/* private fields */
}Expand description
The core activity monitor responsible for tracking user presence and managing workday and pause records.
Orchestrates all aspects of activity monitoring, from low-level input detection to high-level workday management.
Β§Thread Safety
The monitor uses thread-safe primitives to coordinate between:
- Input Thread: Captures keyboard/mouse events via
rdev - Monitor Thread: Runs the main monitoring loop
- Shared State: Activity timestamps and workday tracking
Β§Configuration Impact
All timing behavior is controlled by the MonitorConfig:
- Responsiveness: Lower
poll_interval= more responsive state changes - Sensitivity: Lower
pause_threshold= more sensitive pause detection - Workday Logic: Higher
activity_threshold= more deliberate workday starts - Data Quality: Higher
min_*values = cleaner, less noisy data
FieldsΒ§
Β§config: MonitorConfigConfiguration settings for the monitor, such as thresholds.
This configuration controls all timing and behavior aspects of the monitor. Changes to this configuration require restarting the monitor to take effect, as the values are used throughout the monitoring loop.
pauses: PausesDatabase interface for managing pause records.
This interface handles all pause-related database operations:
- Recording pause start times when inactivity is detected
- Recording pause end times when activity resumes
- Querying existing pause data for validation and reporting
workdays: WorkdaysDatabase interface for managing workday records.
This interface handles workday lifecycle management:
- Creating new workday records when sustained activity is detected
- Updating workday end times as activity continues
- Querying workday status for duplicate prevention
last_activity: Arc<Mutex<Instant>>Timestamp of the last detected user activity (keyboard, mouse).
This timestamp is continuously updated by the input event listener running in a separate thread. Itβs protected by a Mutex for thread-safe access between the input thread and the monitoring loop.
The timestamp is used to:
- Calculate inactivity duration for pause detection
- Determine if activity is βrecentβ for state transitions
- Provide timing information for workday management
activity_start: Arc<Mutex<Option<Instant>>>Optional timestamp marking the beginning of a period of sustained activity.
This field implements a βsustained activityβ detection mechanism to prevent false workday starts from brief, accidental input events. The timestamp is:
- Set when activity begins after a period of inactivity
- Reset to None when a pause begins or workday is created
- Used to calculate activity duration for workday start logic
Β§Workday Start Logic
A workday is created when:
activity_startis set (continuous activity period began)- Duration since
activity_startexceedsactivity_threshold - No workday record exists for the current date
ImplementationsΒ§
SourceΒ§impl Monitor
impl Monitor
Sourcepub fn new(config: MonitorConfig) -> Result<Self>
pub fn new(config: MonitorConfig) -> Result<Self>
Creates a new Monitor instance.
This constructor initializes all monitor components and sets up the background input event listener. It performs several critical setup operations that are essential for proper monitoring functionality.
Β§Initialization Process
- Database Connections: Establishes connections to workday and pause databases
- Shared State: Creates thread-safe containers for activity tracking
- Input Listener: Spawns background thread for keyboard/mouse monitoring
- State Setup: Initializes monitor in Active state
Β§Input Event Handling
The constructor spawns a dedicated thread running rdev::listen() to capture:
- Keyboard Events: Key presses and releases
- Mouse Events: Button clicks, movements, and scroll wheel
- Timestamp Updates: Continuous activity timestamp maintenance
Β§Thread Architecture
Main Thread Input Thread
βββββββββββββββ βββββββββββββββββββ
β Monitor ββββββΆβ rdev::listen() β
β Loop β β (keyboard/ β
β βββββββ mouse) β
βββββββββββββββ βββββββββββββββββββ
β β
βββββ Shared State βββββ
(last_activity, activity_start)Β§Error Handling
The input listener includes error handling for:
- Input device access failures
- Platform-specific event capture issues
- Thread communication problems
Errors in the input thread are logged but donβt crash the main monitor, allowing for graceful degradation when input monitoring isnβt available.
Β§Arguments
config- TheMonitorConfigcontaining timing and behavior settings
Β§Returns
Returns Ok(Monitor) with a fully initialized monitor ready to start
the monitoring loop, or an error if database initialization fails.
Β§Error Scenarios
- Database Connection: Cannot connect to SQLite database files
- Database Schema: Database schema is incompatible or corrupted
- File Permissions: Cannot read/write database files
- Resource Exhaustion: System cannot create necessary threads or allocate memory
Β§Examples
use kasl::libs::config::MonitorConfig;
use kasl::libs::monitor::Monitor;
// Create monitor with default configuration
let config = MonitorConfig::default();
let mut monitor = Monitor::new(config)?;
// Start monitoring
monitor.run().await?;Sourcepub async fn run(&mut self) -> Result<()>
pub async fn run(&mut self) -> Result<()>
Runs the main monitoring loop.
This asynchronous function implements the core monitoring logic that runs continuously until the monitor is stopped. It orchestrates state management, activity detection, and database operations in a coordinated fashion.
Β§Loop Architecture
The monitoring loop operates on a fixed polling interval and performs these operations each cycle:
- Activity Detection: Check if recent input activity occurred
- State Evaluation: Determine appropriate state based on activity
- State Transitions: Handle transitions between Active and InPause
- Workday Management: Ensure workday records are properly maintained
- Sleep: Wait for the next polling interval
Β§State Machine Logic
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Monitor Loop β
β β
β βββββββββββββββ Activity? βββββββββββββββββββββββ β
β β Active ββββββββββNoββββββΆβ handle_inactivity β β
β β β β β β
β β βββββββββββββββββββ (start pause) β β
β βββββββββββββββ βββββββββββββββββββββββ β
β β β
β Activity β
β β β
β βΌ β
β βββββββββββββββββββββββ β
β β ensure_workday_ β β
β β started β β
β βββββββββββββββββββββββ β
β β
β βββββββββββββββ Activity? βββββββββββββββββββββββ β
β β InPause ββββββββββYesβββββΆβhandle_return_from_ β β
β β β βpause β β
β β βββββββββββββββββββ β β
β βββββββββββββββ β (end pause) β β
β βββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΒ§Configuration-Driven Behavior
The loop behavior is entirely controlled by the MonitorConfig:
poll_interval: Controls loop frequency and CPU usagepause_threshold: Determines when inactivity becomes a pauseactivity_threshold: Controls workday start detection sensitivity- Special Case: If
pause_thresholdis 0, monitoring is disabled
Β§Database Operations
The loop performs these database operations as needed:
- Workday Creation: When sustained activity is detected
- Pause Recording: When inactivity exceeds threshold
- Pause Completion: When activity resumes after pause
- Workday Updates: Continuous end time updates during activity
Β§Error Handling
Database errors during the monitoring loop are handled gracefully:
- Errors are logged with detailed information
- The loop continues running to avoid service interruption
- Critical errors are propagated to stop the monitor
Β§Performance Characteristics
- CPU Usage: Directly proportional to polling frequency (1/poll_interval)
- Memory Usage: Constant, no accumulation of historical data
- I/O Operations: Minimal, only database writes for state changes
- Network Usage: None during monitoring
Β§Returns
Returns Ok(()) when the monitoring loop is explicitly stopped,
or an error if a critical database operation fails that prevents
continued monitoring.
Β§Error Scenarios
- Database Connection Loss: SQLite database becomes unavailable
- Disk Space Exhaustion: Cannot write to database files
- Permission Changes: Database files become read-only
- System Resource Exhaustion: Cannot allocate memory for operations
Β§Examples
use kasl::libs::config::MonitorConfig;
use kasl::libs::monitor::Monitor;
// Start monitoring with custom configuration
let config = MonitorConfig {
poll_interval: 1000, // Check every second
pause_threshold: 120, // Pause after 2 minutes
activity_threshold: 30, // Workday starts after 30s
..Default::default()
};
let mut monitor = Monitor::new(config)?;
monitor.run().await?; // Runs indefinitelySourcepub fn detect_activity(&self) -> bool
pub fn detect_activity(&self) -> bool
Checks if any user activity has been detected within the last poll interval.
This method implements the core activity detection logic that drives the monitorβs state machine. It determines whether the user is currently active based on the recency of input events captured by the background input listener thread.
Β§Detection Logic
Activity is considered βdetectedβ when the time elapsed since the last input event is less than the polling interval. This approach ensures that activity detection is synchronized with the monitoring loopβs polling frequency.
Timeline: βββββββββββββββββββββββββββββββββββββΆ
input input poll now
β
elapsed < poll_interval
= Activity DetectedΒ§Sensitivity Tuning
The detection sensitivity can be adjusted through configuration:
- Lower
poll_interval: More sensitive, detects brief activity - Higher
poll_interval: Less sensitive, requires sustained activity
Β§Thread Safety
This method safely accesses the shared last_activity timestamp
that is continuously updated by the input listener thread. The mutex
protection ensures data consistency without blocking the input thread.
Β§Debug Logging
When debug mode is enabled (KASL_DEBUG=1), this method logs detailed
timing information to help with troubleshooting and configuration tuning:
- Elapsed time since last activity
- Activity detection result
- Timing relationship to poll interval
Β§Returns
Returns true if user activity was detected within the last poll interval,
false if the user appears to be inactive.
Β§Performance Considerations
This method is called once per polling cycle and performs minimal work:
- Single mutex lock/unlock operation
- Simple timestamp arithmetic
- Optional debug logging
The implementation is designed for frequent calling with minimal overhead.
Β§Examples
use kasl::libs::monitor::Monitor;
use kasl::libs::config::MonitorConfig;
let monitor = Monitor::new(MonitorConfig::default())?;
// Check for activity
if monitor.detect_activity() {
println!("User is active");
} else {
println!("User appears inactive");
}Sourcepub fn ensure_workday_started(&mut self, today: NaiveDate) -> Result<()>
pub fn ensure_workday_started(&mut self, today: NaiveDate) -> Result<()>
Ensures that a workday record has been started for the current day if sustained activity is detected.
This method implements intelligent workday start detection to automatically create workday records when the user begins sustained work activity. It prevents false workday starts from brief, accidental input while ensuring that genuine work sessions are properly captured.
Β§Sustained Activity Logic
The workday start detection uses a multi-stage process:
- Activity Initiation:
activity_starttimestamp is set by input events - Duration Check: Calculate time elapsed since activity started
- Threshold Validation: Compare duration against
activity_threshold - Workday Creation: Create workday record if threshold is exceeded
- Tracker Reset: Clear
activity_startto prevent duplicate creation
Timeline: ββββββββββββββββββββββββββββββββΆ
start threshold now
activity exceeded
β β
activity_start workday
is set createdΒ§Duplicate Prevention
The method includes multiple safeguards against duplicate workday creation:
- Existence Check: Verifies no workday record exists for the date
- Activity Validation: Requires valid
activity_starttimestamp - Threshold Enforcement: Demands sustained activity duration
- Reset Mechanism: Clears tracker after successful creation
Β§Configuration Impact
The activity_threshold setting controls workday start sensitivity:
- Lower Values (10-30s): Quick workday detection, good for focused work
- Higher Values (60-120s): Conservative detection, avoids false starts
- Very High Values (300s+): Only detects deliberate work sessions
Β§Database Operations
When creating a workday, the method:
- Queries for existing workday records on the target date
- Creates a new workday record with the current timestamp
- Handles any database errors gracefully
Β§Error Handling
Database errors during workday creation are logged but donβt crash the monitor. This ensures continuous monitoring even if individual database operations encounter issues.
Β§State Management
After successful workday creation:
activity_startis reset toNone- Monitor continues tracking for pause detection
- Future activity updates the workday end time
- No additional workday records are created for the date
Β§Arguments
today- The current date for workday record creation
Β§Returns
Returns Ok(()) if workday management completed successfully,
or an error if critical database operations fail.
Β§Error Scenarios
- Database Connection: Cannot connect to workdays database
- Database Query: Cannot check for existing workday records
- Database Insert: Cannot create new workday record
- Date Validation: Invalid date format or system clock issues
Β§Database Schema Impact
This method may create records in the workdays table:
INSERT INTO workdays (date, start_time) VALUES (?, ?);Β§Examples
// This method is called automatically during the monitoring loop
// when the user is active and no workday exists for the current date
// Example: User starts work at 9:00 AM
// - First input at 9:00:00 sets activity_start
// - Continued input until 9:00:30
// - If activity_threshold = 30s, workday is created at 9:00:30
// - Workday start_time is recorded as current timestamp