use super::engine::{handle_frame_full, HandleOutput};
use super::transport::AtomicTransport;
use crate::agents::ForAgent;
use crate::errors::AtomicResult;
use crate::Db;
pub struct SyncSession {
store: Db,
agent: ForAgent,
}
impl SyncSession {
pub fn new(store: Db) -> Self {
Self {
store,
agent: ForAgent::Public,
}
}
pub fn agent(&self) -> &ForAgent {
&self.agent
}
pub async fn handle(&mut self, frame: &[u8]) -> HandleOutput {
handle_frame_full(frame, &self.store, &mut self.agent).await
}
pub async fn serve<T: AtomicTransport>(&mut self, transport: &mut T) -> AtomicResult<()> {
loop {
let Some(frame) = transport.recv().await? else {
return Ok(());
};
let out = self.handle(&frame).await;
for reply in out.frames {
transport.send(reply).await?;
}
}
}
}
#[cfg(all(test, feature = "db-redb"))]
mod tests {
use super::*;
use crate::sync::protocol::{self, tag};
use crate::sync::transport::ChannelTransport;
#[tokio::test]
async fn session_holds_auth_across_frames() {
let db = Db::init_temp("sync_session_auth").await.unwrap();
let (alice, drive) = db.setup("Alice").await.unwrap();
let (mut client, mut server_end) = ChannelTransport::pair();
let mut session = SyncSession::new(db);
let serve = tokio::spawn(async move { session.serve(&mut server_end).await });
client.send(protocol::encode_get(1, &drive)).await.unwrap();
let reply = client.recv().await.unwrap().expect("GET answer");
assert_eq!(
reply.first(),
Some(&tag::ERROR),
"Public GET of a private drive must ERROR"
);
let auth = protocol::encode_auth(&alice, &drive).unwrap();
client.send(auth).await.unwrap();
let reply = client.recv().await.unwrap().expect("AUTH answer");
assert_eq!(reply.first(), Some(&tag::AUTH_OK));
client.send(protocol::encode_get(2, &drive)).await.unwrap();
let reply = client.recv().await.unwrap().expect("GET answer after AUTH");
assert_eq!(
reply.first(),
Some(&tag::UPDATE),
"Alice's GET after AUTH must return the drive snapshot"
);
drop(client);
serve.await.unwrap().unwrap();
}
}