use std::collections::HashMap;
use std::sync::{Arc, RwLock};
struct ChatIds;
struct UserIds;
fn chat_id_cache() -> Arc<RwLock<HashMap<String, i64>>> {
crate::db::current_session().scoped::<ChatIds, _>()
}
fn user_id_cache() -> Arc<RwLock<HashMap<String, i64>>> {
crate::db::current_session().scoped::<UserIds, _>()
}
pub fn forget_chat_id(chat_identifier: &str) {
chat_id_cache().write().unwrap().remove(chat_identifier);
}
pub fn get_chat_id_by_identifier(chat_identifier: &str) -> Result<i64, String> {
{
let owner = chat_id_cache();
let cache = owner.read().unwrap();
if let Some(&id) = cache.get(chat_identifier) {
return Ok(id);
}
}
let conn = super::get_db_connection_guard_static()?;
let id: i64 = conn.query_row(
"SELECT id FROM chats WHERE chat_identifier = ?1",
rusqlite::params![chat_identifier],
|row| row.get(0)
).map_err(|_| format!("Chat not found: {}", chat_identifier))?;
{
let owner = chat_id_cache();
let mut cache = owner.write().unwrap();
cache.insert(chat_identifier.to_string(), id);
}
Ok(id)
}
pub fn get_or_create_chat_id(chat_identifier: &str) -> Result<i64, String> {
{
let owner = chat_id_cache();
let cache = owner.read().unwrap();
if let Some(&id) = cache.get(chat_identifier) {
return Ok(id);
}
}
let conn = super::get_db_connection_guard_static()?;
let existing: Option<i64> = conn.query_row(
"SELECT id FROM chats WHERE chat_identifier = ?1",
rusqlite::params![chat_identifier],
|row| row.get(0)
).ok();
let id = if let Some(id) = existing {
id
} else {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH).unwrap()
.as_secs() as i64;
let chat_type: i32 = if chat_identifier.starts_with("npub1") { 0 } else { 2 };
let participants = if chat_type == 0 {
format!("[\"{}\"]", chat_identifier)
} else {
"[]".to_string()
};
conn.execute(
"INSERT INTO chats (chat_identifier, chat_type, participants, created_at) VALUES (?1, ?2, ?3, ?4)",
rusqlite::params![chat_identifier, chat_type, participants, now],
).map_err(|e| format!("Failed to create chat stub: {}", e))?;
conn.last_insert_rowid()
};
{
let owner = chat_id_cache();
let mut cache = owner.write().unwrap();
cache.insert(chat_identifier.to_string(), id);
}
Ok(id)
}
pub fn get_or_create_user_id(npub: &str) -> Result<Option<i64>, String> {
if npub.is_empty() {
return Ok(None);
}
{
let owner = user_id_cache();
let cache = owner.read().unwrap();
if let Some(&id) = cache.get(npub) {
return Ok(Some(id));
}
}
let conn = super::get_db_connection_guard_static()?;
let existing: Option<i64> = conn.query_row(
"SELECT id FROM profiles WHERE npub = ?1",
rusqlite::params![npub],
|row| row.get(0)
).ok();
let id = if let Some(id) = existing {
id
} else {
conn.execute(
"INSERT INTO profiles (npub, name, display_name) VALUES (?1, '', '')",
rusqlite::params![npub],
).map_err(|e| format!("Failed to create profile stub: {}", e))?;
conn.last_insert_rowid()
};
{
let owner = user_id_cache();
let mut cache = owner.write().unwrap();
cache.insert(npub.to_string(), id);
}
Ok(Some(id))
}
pub fn preload_id_caches() -> Result<(), String> {
let conn = match super::get_db_connection_guard_static() {
Ok(c) => c,
Err(_) => return Ok(()), };
{
let mut stmt = conn.prepare("SELECT chat_identifier, id FROM chats")
.map_err(|e| format!("Failed to prepare chat query: {}", e))?;
let rows = stmt.query_map([], |row| {
Ok((row.get::<_, String>(0)?, row.get::<_, i64>(1)?))
}).map_err(|e| format!("Failed to query chats: {}", e))?;
let owner = chat_id_cache();
let mut cache = owner.write().unwrap();
for row in rows.flatten() {
cache.insert(row.0, row.1);
}
}
{
let mut stmt = conn.prepare("SELECT npub, id FROM profiles")
.map_err(|e| format!("Failed to prepare user query: {}", e))?;
let rows = stmt.query_map([], |row| {
Ok((row.get::<_, String>(0)?, row.get::<_, i64>(1)?))
}).map_err(|e| format!("Failed to query profiles: {}", e))?;
let owner = user_id_cache();
let mut cache = owner.write().unwrap();
for row in rows.flatten() {
cache.insert(row.0, row.1);
}
}
Ok(())
}
pub fn clear_id_caches() {
chat_id_cache().write().unwrap().clear();
user_id_cache().write().unwrap().clear();
}