use std::path::PathBuf;
use deadpool::Runtime;
use deadpool::managed::{Manager, Metrics, RecycleResult};
use rusqlite::Connection;
use rusqlite::vtab::array;
use super::errors::SqliteStoreError;
deadpool::managed_reexports!(
"miden-client-sqlite-store",
SqlitePoolManager,
deadpool::managed::Object<SqlitePoolManager>,
rusqlite::Error,
SqliteStoreError
);
const RUNTIME: Runtime = Runtime::Tokio1;
pub struct SqlitePoolManager {
database_path: PathBuf,
}
impl SqlitePoolManager {
pub fn new(database_path: PathBuf) -> Self {
Self { database_path }
}
fn new_connection(&self) -> rusqlite::Result<Connection> {
let conn = Connection::open(&self.database_path)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let perms = std::fs::Permissions::from_mode(0o600);
for suffix in &["", "-wal", "-shm"] {
let mut path = self.database_path.as_os_str().to_owned();
path.push(suffix);
let path = std::path::PathBuf::from(path);
if path.exists()
&& let Err(e) = std::fs::set_permissions(&path, perms.clone())
{
eprintln!("Warning: failed to set permissions on {}: {e}", path.display());
}
}
}
array::load_module(&conn)?;
conn.pragma_update(None, "foreign_keys", "ON")?;
Ok(conn)
}
}
impl Manager for SqlitePoolManager {
type Type = deadpool_sync::SyncWrapper<Connection>;
type Error = rusqlite::Error;
async fn create(&self) -> Result<Self::Type, Self::Error> {
let conn = self.new_connection();
deadpool_sync::SyncWrapper::new(RUNTIME, move || conn).await
}
async fn recycle(&self, _: &mut Self::Type, _: &Metrics) -> RecycleResult<Self::Error> {
Ok(())
}
}