use crate::goal::types::SessionGoal;
use std::sync::{
Mutex,
atomic::{AtomicI64, AtomicU64, Ordering},
};
pub struct GoalAccountingState {
tokens_this_turn: AtomicI64,
turn_start_time: AtomicU64,
goal: Mutex<SessionGoal>,
}
impl GoalAccountingState {
pub fn new(goal: SessionGoal) -> Self {
Self {
tokens_this_turn: AtomicI64::new(0),
turn_start_time: AtomicU64::new(0),
goal: Mutex::new(goal),
}
}
pub fn start_turn(&self) {
let now = crate::session::current_unix_timestamp();
{
let mut goal = self.goal.lock().unwrap_or_else(|e| e.into_inner());
goal.record_time_since_last_accounted();
}
self.turn_start_time.store(now, Ordering::SeqCst);
self.tokens_this_turn.store(0, Ordering::SeqCst);
}
pub fn record_token_usage(&self, delta: i64) -> bool {
self.tokens_this_turn.fetch_add(delta, Ordering::SeqCst);
let mut goal = self.goal.lock().unwrap_or_else(|e| e.into_inner());
goal.record_tokens(delta)
}
pub fn finish_turn(&self) -> Option<SessionGoal> {
let turn_start = self.turn_start_time.load(Ordering::SeqCst);
if turn_start > 0 {
let now = crate::session::current_unix_timestamp();
let seconds = (now.saturating_sub(turn_start)) as i64;
let mut goal = self.goal.lock().unwrap_or_else(|e| e.into_inner());
goal.record_time(seconds);
}
self.turn_start_time.store(0, Ordering::SeqCst);
self.tokens_this_turn.store(0, Ordering::SeqCst);
self.snapshot()
}
pub fn snapshot(&self) -> Option<SessionGoal> {
let goal = self.goal.lock().unwrap_or_else(|e| e.into_inner());
Some(goal.clone())
}
pub fn replace_goal(&self, goal: SessionGoal) {
*self.goal.lock().unwrap_or_else(|e| e.into_inner()) = goal;
}
pub fn is_active(&self) -> bool {
let goal = self.goal.lock().unwrap_or_else(|e| e.into_inner());
goal.status.should_auto_continue()
}
}