use rag_rat_oplog::{
AccountId, ContentIngestOutcome, IngestOutcome, account_entries_for_sync, account_entry_ref,
account_ingest, account_signed_entry_exists, account_signed_hash, content_entries_for_sync,
content_entry_ref, content_ingest, content_signed_entry_exists, content_signed_hash,
sign_local_node_binding, verify_node_binding,
};
use rusqlite::Connection;
use crate::auth::NodeAuth;
use crate::session::{Ingested, SyncStore};
fn sign_binding(
conn: &Connection,
account_id: AccountId,
local_node: &[u8; 32],
now_ms: i64,
) -> anyhow::Result<Vec<u8>> {
match sign_local_node_binding(conn, account_id, local_node, now_ms)? {
Ok(bytes) => Ok(bytes),
Err(_no_local_device) => Ok(Vec::new()),
}
}
fn authorize_binding(
conn: &Connection,
account_id: AccountId,
binding: &[u8],
remote_node: &[u8; 32],
now_ms: i64,
) -> anyhow::Result<bool> {
Ok(verify_node_binding(conn, account_id, binding, remote_node, now_ms)?.is_ok())
}
pub struct OplogSyncStore<'a> {
conn: &'a Connection,
account_id: AccountId,
now_ms: i64,
}
impl<'a> OplogSyncStore<'a> {
pub fn new(conn: &'a Connection, account_id: AccountId, now_ms: i64) -> Self {
Self { conn, account_id, now_ms }
}
}
impl SyncStore for OplogSyncStore<'_> {
fn account_id(&self) -> [u8; 32] {
self.account_id.to_bytes()
}
fn snapshot(&self) -> anyhow::Result<Vec<([u8; 32], Vec<u8>)>> {
Ok(account_entries_for_sync(self.conn, self.account_id)?
.into_iter()
.map(|e| (account_signed_hash(&e.signed_bytes), e.signed_bytes))
.collect())
}
fn ingest(&mut self, signed_bytes: &[u8]) -> anyhow::Result<Ingested> {
let Ok((entry_account, _entry_hash)) = account_entry_ref(signed_bytes) else {
return Ok(Ingested::NoChange);
};
if entry_account != self.account_id {
return Ok(Ingested::NoChange);
}
if account_signed_entry_exists(self.conn, self.account_id, signed_bytes)? {
return Ok(Ingested::NoChange);
}
match account_ingest(self.conn, signed_bytes, self.now_ms)? {
IngestOutcome::PreVerify
| IngestOutcome::PreVerifyWithEviction { .. }
| IngestOutcome::Ingested { .. }
| IngestOutcome::IngestedWithRejectedPromotions { .. }
| IngestOutcome::IngestedWithRejectedContentPromotions { .. }
| IngestOutcome::IngestedWithRejectedAccountAndContentPromotions { .. } =>
Ok(Ingested::Stored),
IngestOutcome::Rejected(_) | IngestOutcome::CapacityReached { .. } =>
Ok(Ingested::NoChange),
}
}
}
pub struct OplogContentSyncStore<'a> {
conn: &'a Connection,
account_id: AccountId,
now_ms: i64,
}
impl<'a> OplogContentSyncStore<'a> {
pub fn new(conn: &'a Connection, account_id: AccountId, now_ms: i64) -> Self {
Self { conn, account_id, now_ms }
}
}
impl SyncStore for OplogContentSyncStore<'_> {
fn account_id(&self) -> [u8; 32] {
self.account_id.to_bytes()
}
fn snapshot(&self) -> anyhow::Result<Vec<([u8; 32], Vec<u8>)>> {
Ok(content_entries_for_sync(self.conn, self.account_id)?
.into_iter()
.map(|e| (content_signed_hash(&e.signed_bytes), e.signed_bytes))
.collect())
}
fn ingest(&mut self, signed_bytes: &[u8]) -> anyhow::Result<Ingested> {
let Ok((_stream, entry_account, _entry_hash)) = content_entry_ref(signed_bytes) else {
return Ok(Ingested::NoChange);
};
if entry_account != self.account_id {
return Ok(Ingested::NoChange);
}
if content_signed_entry_exists(self.conn, self.account_id, signed_bytes)? {
return Ok(Ingested::NoChange);
}
match content_ingest(self.conn, signed_bytes, self.now_ms)? {
ContentIngestOutcome::PreVerify
| ContentIngestOutcome::PreVerifyWithEviction { .. }
| ContentIngestOutcome::Ingested { .. } => Ok(Ingested::Stored),
ContentIngestOutcome::Rejected(_) | ContentIngestOutcome::CapacityReached { .. } =>
Ok(Ingested::NoChange),
}
}
}
impl NodeAuth for OplogSyncStore<'_> {
fn local_binding(&self, local_node: &[u8; 32], now_ms: i64) -> anyhow::Result<Vec<u8>> {
sign_binding(self.conn, self.account_id, local_node, now_ms)
}
fn authorize(
&self,
binding: &[u8],
remote_node: &[u8; 32],
now_ms: i64,
) -> anyhow::Result<bool> {
authorize_binding(self.conn, self.account_id, binding, remote_node, now_ms)
}
}
impl NodeAuth for OplogContentSyncStore<'_> {
fn local_binding(&self, local_node: &[u8; 32], now_ms: i64) -> anyhow::Result<Vec<u8>> {
sign_binding(self.conn, self.account_id, local_node, now_ms)
}
fn authorize(
&self,
binding: &[u8],
remote_node: &[u8; 32],
now_ms: i64,
) -> anyhow::Result<bool> {
authorize_binding(self.conn, self.account_id, binding, remote_node, now_ms)
}
}