use anyhow::Result;
use std::sync::Arc;
use tokio::sync::{broadcast, Mutex};
use super::db::SessionDb;
use super::github::GitHubClient;
use super::sync::SyncEngine;
#[derive(Clone)]
pub struct WebState {
pub db: SessionDb,
pub sync_engine: Arc<Mutex<SyncEngine>>,
pub github: Arc<Mutex<Option<GitHubClient>>>,
pub sync_progress_tx: broadcast::Sender<SyncProgress>,
pub debug: bool,
pub port: u16,
}
impl WebState {
pub async fn new(debug: bool, port: u16) -> Result<Self> {
let db = SessionDb::open().await?;
let mut sync_engine = SyncEngine::new(db.clone());
sync_engine.load_skip_cache().await?;
let (sync_progress_tx, _) = broadcast::channel(256);
let github = match load_github_token() {
Some(token) => Some(GitHubClient::new(&token)),
None => None,
};
Ok(Self {
db,
sync_engine: Arc::new(Mutex::new(sync_engine)),
github: Arc::new(Mutex::new(github)),
sync_progress_tx,
debug,
port,
})
}
}
#[derive(Clone, Debug, serde::Serialize)]
pub struct SyncProgress {
pub phase: SyncPhase,
#[serde(skip_serializing_if = "Option::is_none")]
pub current_project: Option<String>,
pub sessions_total: usize,
pub sessions_done: usize,
pub messages_indexed: usize,
}
#[derive(Clone, Debug, serde::Serialize)]
#[serde(rename_all = "snake_case")]
pub enum SyncPhase {
Idle,
Discovering,
Syncing,
Done,
}
pub fn load_github_token_exists() -> bool {
load_github_token().is_some()
}
pub fn load_github_token() -> Option<String> {
let config_path = dirs::home_dir()?.join(".wsb").join("config.toml");
let content = std::fs::read_to_string(&config_path).ok()?;
let table: toml::Table = content.parse().ok()?;
let github = table.get("github")?.as_table()?;
let token = github.get("token")?.as_str()?;
if token.is_empty() {
None
} else {
Some(token.to_string())
}
}