use std::io::Write as _;
use super::types::{ AccountQuota, SubprocessModel, SubprocessEffort };
use super::subprocess::{ resolve_model, effort_pre_args };
use super::fetch::{ read_token, parse_u64_from_str };
use super::format::{ five_hour_left, seven_day_left };
pub( crate ) fn apply_touch(
aq : &mut AccountQuota,
credential_store : &std::path::Path,
claude_paths : Option< &crate::ClaudePaths >,
trace : bool,
imodel : SubprocessModel,
effort : SubprocessEffort,
solo : bool,
)
{
if solo && !aq.is_current
{
if trace { let _ = writeln!( std::io::stderr(), "[trace] touch {} solo-skip", aq.name ); }
return;
}
if !aq.is_owned
{
if trace { let _ = writeln!( std::io::stderr(), "[trace] touch {} skipped (reason: not owned)", aq.name ); }
return;
}
if aq.is_occupied_elsewhere
{
if trace { let _ = writeln!( std::io::stderr(), "[trace] touch {} skipped (reason: occupied elsewhere)", aq.name ); }
return;
}
let Ok( ref data ) = aq.result else
{
if trace { let _ = writeln!( std::io::stderr(), "[trace] touch {} skipped (reason: error account)", aq.name ); }
return;
};
if let Some( cache ) = claude_profile_core::account::read_quota_cache( credential_store, &aq.name )
{
if cache.touch_idle == Some( false )
{
if trace { let _ = writeln!( std::io::stderr(), "[trace] touch {} skipped (reason: touch_idle=false)", aq.name ); }
return;
}
}
let five_h_running = data.five_hour.as_ref().and_then( |p| p.resets_at.as_deref() ).is_some();
let d7_running = data.seven_day.as_ref().map_or( true, |p| p.resets_at.is_some() );
let son_running = data.seven_day_sonnet.as_ref().map_or( true, |p| p.resets_at.is_some() );
let all_running = five_h_running && d7_running && son_running;
let h_left = five_hour_left( aq );
let d7_left = seven_day_left( aq );
if all_running || h_left <= 15.0 || d7_left <= 0.0
{
if trace
{
let reason = if all_running { "already active" }
else if h_left <= 15.0 { "h-exhausted" }
else { "7d-exhausted" };
let _ = writeln!( std::io::stderr(), "[trace] touch {} skipped (reason: {})", aq.name, reason );
}
return;
}
let model = resolve_model( aq, imodel );
let pre_args = effort_pre_args( &model, effort );
let new_creds = crate::account::refresh_account_token(
&aq.name, credential_store, claude_paths, trace, "touch", model, &pre_args,
);
if let Some( ref creds ) = new_creds
{
if let Some( exp_ms ) = crate::output::jwt_exp_ms( creds )
{
aq.expires_at_ms = exp_ms;
}
else if let Some( exp_ms ) = parse_u64_from_str( creds, "expiresAt" )
{
aq.expires_at_ms = exp_ms;
}
}
let Ok( token ) = read_token( credential_store, &aq.name ) else { return; };
if let Ok( new_data ) = claude_quota::fetch_oauth_usage( &token )
{
aq.result = Ok( new_data );
if let Ok( acct ) = claude_quota::fetch_oauth_account( &token )
{
aq.account = Some( acct );
}
}
}
#[ cfg( test ) ]
#[ path = "touch_tests.rs" ]
mod tests;