| use std::sync::Arc; |
|
|
| use chrono::Utc; |
| use reqwest::Client; |
| use tokio::sync::{broadcast, RwLock}; |
|
|
| use crate::models::{AgentEvent, TriageRecord}; |
|
|
| #[derive(Debug, Clone)] |
| pub struct AppSettings { |
| pub vllm_url: String, |
| pub vllm_api_key: Option<String>, |
| pub pubmed_email: Option<String>, |
| pub base_sepolia_rpc: String, |
| pub private_key: Option<String>, |
| pub contract_address: Option<String>, |
| pub app_name: String, |
| } |
|
|
| #[derive(Debug, Clone)] |
| pub struct AppState { |
| pub settings: AppSettings, |
| pub client: Client, |
| pub history: Arc<RwLock<Vec<TriageRecord>>>, |
| pub agent_bus: broadcast::Sender<AgentEvent>, |
| pub last_event: Arc<RwLock<Option<AgentEvent>>>, |
| } |
|
|
| impl AppState { |
| pub fn from_env() -> anyhow::Result<Self> { |
| let vllm_url = std::env::var("VLLM_URL") |
| .unwrap_or_else(|_| "http://127.0.0.1:8000/v1/chat/completions".to_string()); |
| let vllm_api_key = std::env::var("VLLM_API_KEY").ok(); |
| let pubmed_email = std::env::var("PUBMED_EMAIL").ok(); |
| let base_sepolia_rpc = std::env::var("BASE_SEPOLIA_RPC") |
| .unwrap_or_else(|_| "https://sepolia.base.org".to_string()); |
| let private_key = std::env::var("PRIVATE_KEY").ok(); |
| let contract_address = std::env::var("AUDIT_CONTRACT_ADDRESS").ok(); |
|
|
| let client = Client::builder() |
| .timeout(std::time::Duration::from_secs(25)) |
| .build()?; |
| let (agent_bus, _) = broadcast::channel(128); |
|
|
| Ok(Self { |
| settings: AppSettings { |
| vllm_url, |
| vllm_api_key, |
| pubmed_email, |
| base_sepolia_rpc, |
| private_key, |
| contract_address, |
| app_name: "RustVital-AMD".to_string(), |
| }, |
| client, |
| history: Arc::new(RwLock::new(Vec::new())), |
| agent_bus, |
| last_event: Arc::new(RwLock::new(None)), |
| }) |
| } |
|
|
| pub async fn push_record(&self, record: TriageRecord) { |
| self.history.write().await.push(record); |
| } |
|
|
| pub async fn records(&self) -> Vec<TriageRecord> { |
| self.history.read().await.clone() |
| } |
|
|
| pub async fn latest_record_id(&self) -> Option<String> { |
| self.history |
| .read() |
| .await |
| .last() |
| .map(|record| record.record_id.as_str().to_string()) |
| } |
|
|
| pub fn emit(&self, event: AgentEvent) { |
| let _ = self.agent_bus.send(event.clone()); |
| let last_event = self.last_event.clone(); |
| tokio::spawn(async move { |
| *last_event.write().await = Some(event); |
| }); |
| } |
|
|
| pub fn now_rfc3339() -> String { |
| Utc::now().to_rfc3339() |
| } |
| } |
|
|