use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use smooth_operator::adapter::StorageAdapter;
use smooth_operator::auth::{AuthVerifier, NoAuthVerifier};
use smooth_operator::backplane::{Backplane, InMemoryBackplane};
use smooth_operator::connector_config::{ConnectorConfigStore, InMemoryConnectorConfigStore};
use smooth_operator::domain::Session;
use smooth_operator::settings::{InMemorySettingsStore, SettingsStore};
use smooth_operator::widget_auth::{PermissiveWidgetAuth, WidgetAuthProvider};
use smooth_operator_ingestion::indexing::{InMemoryIndexingStore, IndexingStore};
use crate::config::ServerConfig;
#[derive(Clone)]
pub struct AppState {
pub storage: Arc<dyn StorageAdapter>,
pub config: Arc<ServerConfig>,
pub auth: Arc<dyn AuthVerifier>,
pub indexing: Arc<dyn IndexingStore>,
pub connector_configs: Arc<dyn ConnectorConfigStore>,
pub settings: Arc<dyn SettingsStore>,
pub widget_auth: Arc<dyn WidgetAuthProvider>,
pub backplane: Arc<dyn Backplane>,
sessions: Arc<RwLock<HashMap<String, Session>>>,
doc_sets: Arc<RwLock<HashMap<String, HashMap<String, usize>>>>,
connectors: Arc<RwLock<HashMap<String, Vec<String>>>>,
}
#[must_use]
pub fn scoped_connector_key(org_id: &str, connector_name: &str) -> String {
format!("IXCONN#{org_id}\u{1}{connector_name}")
}
impl AppState {
#[must_use]
pub fn new(storage: Arc<dyn StorageAdapter>, config: ServerConfig) -> Self {
Self {
storage,
config: Arc::new(config),
auth: Arc::new(NoAuthVerifier::default()),
indexing: Arc::new(InMemoryIndexingStore::new()),
connector_configs: Arc::new(InMemoryConnectorConfigStore::new()),
settings: Arc::new(InMemorySettingsStore::new()),
widget_auth: Arc::new(PermissiveWidgetAuth),
backplane: Arc::new(InMemoryBackplane::new()),
sessions: Arc::new(RwLock::new(HashMap::new())),
doc_sets: Arc::new(RwLock::new(HashMap::new())),
connectors: Arc::new(RwLock::new(HashMap::new())),
}
}
#[must_use]
pub fn with_auth(mut self, auth: Arc<dyn AuthVerifier>) -> Self {
self.auth = auth;
self
}
#[must_use]
pub fn with_indexing(mut self, indexing: Arc<dyn IndexingStore>) -> Self {
self.indexing = indexing;
self
}
#[must_use]
pub fn with_connector_configs(mut self, store: Arc<dyn ConnectorConfigStore>) -> Self {
self.connector_configs = store;
self
}
#[must_use]
pub fn with_settings(mut self, store: Arc<dyn SettingsStore>) -> Self {
self.settings = store;
self
}
#[must_use]
pub fn with_widget_auth(mut self, provider: Arc<dyn WidgetAuthProvider>) -> Self {
self.widget_auth = provider;
self
}
#[must_use]
pub fn with_backplane(mut self, backplane: Arc<dyn Backplane>) -> Self {
self.backplane = backplane;
self
}
pub fn insert_session(&self, session: Session) {
if let Ok(mut map) = self.sessions.write() {
map.insert(session.session_id.clone(), session);
}
}
#[must_use]
pub fn get_session(&self, session_id: &str) -> Option<Session> {
self.sessions.read().ok()?.get(session_id).cloned()
}
pub fn record_document_set(&self, org_id: impl Into<String>, set: impl Into<String>) {
if let Ok(mut map) = self.doc_sets.write() {
*map.entry(org_id.into())
.or_default()
.entry(set.into())
.or_insert(0) += 1;
}
}
#[must_use]
pub fn document_sets(&self, org_id: &str) -> Vec<(String, usize)> {
let Ok(map) = self.doc_sets.read() else {
return Vec::new();
};
let Some(org_sets) = map.get(org_id) else {
return Vec::new();
};
let mut out: Vec<(String, usize)> = org_sets.iter().map(|(k, v)| (k.clone(), *v)).collect();
out.sort_by(|a, b| a.0.cmp(&b.0));
out
}
pub fn record_connector(&self, org_id: impl Into<String>, name: impl Into<String>) {
let name = name.into();
if let Ok(mut map) = self.connectors.write() {
let v = map.entry(org_id.into()).or_default();
if !v.iter().any(|c| c == &name) {
v.push(name);
}
}
}
#[must_use]
pub fn connectors(&self, org_id: &str) -> Vec<String> {
let Ok(map) = self.connectors.read() else {
return Vec::new();
};
let mut out = map.get(org_id).cloned().unwrap_or_default();
out.sort();
out
}
}