"""Handles persistent state management and access control for the application.""" import datetime import os import threading from typing import Any, Dict, Tuple from src.config.constants import IS_DEMO_VERSION, MAX_DEMO_RUNS_PER_DAY, STATE_FILE from src.ui.formatting import get_server_timezone from src.utils.file_io import load_json, write_json from src.utils.logger import console state_lock = threading.Lock() def get_default_state() -> Dict[str, Any]: """Returns the default initial state dictionary.""" return {"date": datetime.datetime.now().strftime("%Y-%m-%d"), "run_count": 0} def get_state() -> Dict[str, Any]: """Get the current state from the JSON file, initializing if needed.""" if not os.path.exists(STATE_FILE): default_state = get_default_state() write_json(STATE_FILE, default_state) return default_state try: state = load_json(STATE_FILE) # Reset counter if it's a new day current_date = datetime.datetime.now().strftime("%Y-%m-%d") if state["date"] != current_date: state = get_default_state() write_json(STATE_FILE, state) return state except Exception as e: console.print(f"Error reading state file: {e}", style="red") return get_default_state() def update_state(state_updates: Dict[str, Any]) -> Dict[str, Any]: """Update the state file with new values.""" current_state = get_state() current_state.update(state_updates) write_json(STATE_FILE, current_state) return current_state def can_run_app() -> Tuple[bool, str]: """Check if the app can be run based on demo restrictions.""" # No restrictions if not running in demo mode if not IS_DEMO_VERSION: return True, "" # Get server timezone for both cases server_time = get_server_timezone() server_time = f"🌐 {server_time}" # Load current run state state = get_state() runs_left = MAX_DEMO_RUNS_PER_DAY - state["run_count"] # Block if daily limit reached if state["run_count"] >= MAX_DEMO_RUNS_PER_DAY: return ( False, f"⛔ Daily limit reached ({MAX_DEMO_RUNS_PER_DAY} runs per day " f"in demo mode). Please try again tomorrow!" f"
{server_time}", ) # Otherwise, allow and return runs remaining return ( True, f"🕒 Demo mode: {runs_left} run" f"{'s' if runs_left != 1 else ''} left today." f"
{server_time}", )