use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Mutex as StdMutex;
use rusqlite::Connection;
use crate::audit;
use crate::world;
pub(crate) struct AuditAppendJob {
pub(crate) ledger_world: &'static str,
pub(crate) event_type: &'static str,
pub(crate) target: String,
pub(crate) body_sha256: String,
pub(crate) size: i64,
pub(crate) content_type: String,
pub(crate) headers: Vec<(String, String)>,
pub(crate) key: Vec<u8>,
}
#[derive(Debug)]
pub(crate) enum BlockingSqliteError {
Sqlite(rusqlite::Error),
Worker,
}
pub(crate) struct LedgerWriter {
conn: StdMutex<Option<Connection>>,
pub(crate) inits: AtomicUsize,
}
impl LedgerWriter {
pub(crate) fn new() -> Self {
Self {
conn: StdMutex::new(None),
inits: AtomicUsize::new(0),
}
}
pub(crate) fn append(
&self,
data: &Path,
job: AuditAppendJob,
) -> Result<String, BlockingSqliteError> {
let mut guard = self.conn.lock().unwrap_or_else(|p| p.into_inner());
if guard.is_none() {
let conn = world::open(data, job.ledger_world).map_err(BlockingSqliteError::Sqlite)?;
*guard = Some(conn);
self.inits.fetch_add(1, Ordering::Relaxed);
}
let conn = guard.as_mut().expect("ledger connection initialized above");
audit::append_with_conn(
conn,
job.event_type,
&job.target,
&job.body_sha256,
job.size,
&job.content_type,
&job.headers,
&job.key,
)
.map_err(BlockingSqliteError::Sqlite)
}
}