use crate::{
entity::{AccountEntity, ServerEntity, ServerRow},
Error,
};
use async_sqlite::Client;
use async_trait::async_trait;
use sos_core::{AccountId, Origin, RemoteOrigins};
use std::collections::HashSet;
pub struct ServerOrigins<E>
where
E: std::error::Error
+ std::fmt::Debug
+ From<Error>
+ Send
+ Sync
+ 'static,
{
client: Client,
account_id: AccountId,
marker: std::marker::PhantomData<E>,
}
impl<E> ServerOrigins<E>
where
E: std::error::Error
+ std::fmt::Debug
+ From<Error>
+ Send
+ Sync
+ 'static,
{
pub fn new(account_id: AccountId, client: Client) -> Self {
Self {
client,
account_id,
marker: std::marker::PhantomData,
}
}
async fn list_origins(&self) -> Result<HashSet<Origin>, E> {
let account_id = self.account_id;
let servers = self
.client
.conn_and_then(move |conn| {
let accounts = AccountEntity::new(&conn);
let account_row = accounts.find_one(&account_id)?;
let servers = ServerEntity::new(&conn);
servers.load_servers(account_row.row_id)
})
.await?;
let mut set = HashSet::new();
for server in servers {
set.insert(server.try_into()?);
}
Ok(set)
}
async fn insert_server(
&mut self,
origin: Origin,
remove: Option<&Origin>,
) -> Result<(), E> {
let account_id = self.account_id;
let remove = remove.cloned();
let server_row: ServerRow = origin.try_into()?;
self.client
.conn_mut(move |conn| {
let tx = conn.transaction()?;
let accounts = AccountEntity::new(&tx);
let account_row = accounts.find_one(&account_id)?;
let servers = ServerEntity::new(&tx);
if let Some(remove) = remove {
let server_row =
servers.find_one(account_row.row_id, remove.url())?;
servers.delete_server(server_row.row_id)?;
}
servers.insert_server(account_row.row_id, &server_row)?;
tx.commit()?;
Ok(())
})
.await
.map_err(Error::from)?;
Ok(())
}
}
#[async_trait]
impl<E> RemoteOrigins for ServerOrigins<E>
where
E: std::error::Error
+ std::fmt::Debug
+ From<Error>
+ Send
+ Sync
+ 'static,
{
type Error = E;
async fn list_servers(&self) -> Result<HashSet<Origin>, Self::Error> {
self.list_origins().await
}
async fn add_server(
&mut self,
origin: Origin,
) -> Result<(), Self::Error> {
let account_id = self.account_id;
let url = origin.url().clone();
let server_row = self
.client
.conn(move |conn| {
let accounts = AccountEntity::new(&conn);
let account_row = accounts.find_one(&account_id)?;
let servers = ServerEntity::new(&conn);
servers.find_optional(account_row.row_id, &url)
})
.await
.map_err(Error::from)?;
match server_row {
Some(row) => {
let old_origin: Origin = row.try_into()?;
self.insert_server(origin, Some(&old_origin)).await
}
None => self.insert_server(origin, None).await,
}
}
async fn replace_server(
&mut self,
old_origin: &Origin,
new_origin: Origin,
) -> Result<(), Self::Error> {
self.insert_server(new_origin, Some(old_origin)).await
}
async fn remove_server(
&mut self,
origin: &Origin,
) -> Result<(), Self::Error> {
let account_id = self.account_id;
let origin = origin.clone();
self.client
.conn_mut(move |conn| {
let tx = conn.transaction()?;
let accounts = AccountEntity::new(&tx);
let account_row = accounts.find_one(&account_id)?;
let servers = ServerEntity::new(&tx);
let server_row =
servers.find_one(account_row.row_id, origin.url())?;
servers.delete_server(server_row.row_id)?;
tx.commit()?;
Ok(())
})
.await
.map_err(Error::from)?;
Ok(())
}
}