use unilang::data::{ ErrorData, OutputData };
use super::types::UsageParams;
use super::fetch::fetch_all_quota;
use super::render::render_text;
static STOP_FLAG : core::sync::atomic::AtomicBool = core::sync::atomic::AtomicBool::new( false );
extern "C" fn on_sigint( _ : std::os::raw::c_int )
{
STOP_FLAG.store( true, core::sync::atomic::Ordering::Relaxed );
}
fn secs_to_hms_utc( unix_secs : u64 ) -> String
{
let sod = unix_secs % 86400;
let h = sod / 3600;
let m = ( sod % 3600 ) / 60;
let s = sod % 60;
format!( "{h:02}:{m:02}:{s:02}" )
}
#[ allow( unsafe_code ) ]
pub( crate ) fn execute_live_mode(
credential_store : &std::path::Path,
live_creds_file : &std::path::Path,
params : &UsageParams,
) -> Result< OutputData, ErrorData >
{
use std::os::raw::{ c_int, c_void };
use core::sync::atomic::Ordering;
use std::time::{ SystemTime, UNIX_EPOCH };
use std::io::Write;
type SignalFn = extern "C" fn( c_int );
extern "C"
{
fn signal ( signum : c_int, handler : SignalFn ) -> usize;
fn sigprocmask( how : c_int, set : *const c_void, oldset : *mut c_void ) -> c_int;
fn sigemptyset( set : *mut c_void ) -> c_int;
fn sigaddset ( set : *mut c_void, signum : c_int ) -> c_int;
}
STOP_FLAG.store( false, Ordering::Relaxed );
let mut sigset = [ 0u64; 16 ];
unsafe
{
sigemptyset( sigset.as_mut_ptr().cast::< c_void >() );
sigaddset ( sigset.as_mut_ptr().cast::< c_void >(), 2 ); sigprocmask( 1, sigset.as_ptr().cast::< c_void >(), core::ptr::null_mut() ); signal( 2, on_sigint );
}
loop
{
if STOP_FLAG.load( Ordering::Relaxed ) { break; }
print!( "\x1B[2J\x1B[H" );
let _ = std::io::stdout().flush();
let accounts = fetch_all_quota( credential_store, live_creds_file, true, params.trace, params.solo )?;
let text = render_text( &accounts, params.sort, params.desc, params.prefer, ¶ms.cols, None, None, None, None );
print!( "{text}" );
let now_secs = SystemTime::now().duration_since( UNIX_EPOCH ).unwrap_or_default().as_secs();
let jitter_extra = if params.jitter > 0
{
let nanos = u64::from( SystemTime::now().duration_since( UNIX_EPOCH ).unwrap_or_default().subsec_nanos() );
nanos % ( params.jitter + 1 ) }
else
{
0
};
let wait_secs = params.interval + jitter_extra;
let next_at = now_secs + wait_secs;
let mut remaining = wait_secs;
loop
{
if STOP_FLAG.load( Ordering::Relaxed ) { break; }
let next_hms = secs_to_hms_utc( next_at );
let m = remaining / 60;
let s = remaining % 60;
let line = format!( " Next update in {m}:{s:02} (at {next_hms} UTC) [Ctrl-C to exit]" );
print!( "\r{line:<80}" );
let _ = std::io::stdout().flush();
if remaining == 0 { break; }
remaining -= 1;
std::thread::sleep( core::time::Duration::from_secs( 1 ) );
}
println!();
if STOP_FLAG.load( Ordering::Relaxed ) { break; }
}
println!( "\nMonitor stopped." );
Ok( OutputData::new( String::new(), "text" ) )
}
#[ cfg( test ) ]
mod tests
{
use super::secs_to_hms_utc;
#[ test ]
fn test_secs_to_hms_utc_zero()
{
assert_eq!( secs_to_hms_utc( 0 ), "00:00:00" );
}
#[ test ]
fn test_secs_to_hms_utc_end_of_day()
{
assert_eq!( secs_to_hms_utc( 86399 ), "23:59:59" );
}
#[ test ]
fn test_secs_to_hms_utc_day_wrap()
{
assert_eq!( secs_to_hms_utc( 86400 ), "00:00:00" );
}
#[ test ]
fn test_secs_to_hms_utc_midday()
{
assert_eq!( secs_to_hms_utc( 45045 ), "12:30:45" );
}
}