converted incoming mail
Some checks reported errors
Albatros default

This commit is contained in:
Quentin 2023-11-02 17:25:56 +01:00
parent bf67935c54
commit 652da6efd3
Signed by: quentin
GPG key ID: E9602264D639FF68
2 changed files with 32 additions and 88 deletions

View file

@ -1,11 +1,5 @@
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
use k2v_client::K2vClient;
use k2v_client::{BatchReadOp, Filter, K2vValue};
use rusoto_s3::{
CopyObjectRequest, DeleteObjectRequest, GetObjectRequest, PutObjectRequest, S3Client, S3,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::io::AsyncReadExt;
use tokio::sync::RwLock; use tokio::sync::RwLock;
use crate::bayou::Bayou; use crate::bayou::Bayou;
@ -206,35 +200,18 @@ impl MailboxInternal {
async fn fetch_meta(&self, ids: &[UniqueIdent]) -> Result<Vec<MailMeta>> { async fn fetch_meta(&self, ids: &[UniqueIdent]) -> Result<Vec<MailMeta>> {
let ids = ids.iter().map(|x| x.to_string()).collect::<Vec<_>>(); let ids = ids.iter().map(|x| x.to_string()).collect::<Vec<_>>();
let ops = ids let ops = ids.iter().map(|id| (self.mail_path.as_str(), id.as_str())).collect::<Vec<_>>();
.iter() let res_vec = self.k2v.select(storage::Selector::List(ops)).await?;
.map(|id| BatchReadOp {
partition_key: &self.mail_path,
filter: Filter {
start: Some(id),
end: None,
prefix: None,
limit: None,
reverse: false,
},
single_item: true,
conflicts_only: false,
tombstones: false,
})
.collect::<Vec<_>>();
let res_vec = self.k2v.read_batch(&ops).await?;
let mut meta_vec = vec![]; let mut meta_vec = vec![];
for (op, res) in ops.iter().zip(res_vec.into_iter()) { for res in res_vec.into_iter() {
if res.items.len() != 1 {
bail!("Expected 1 item, got {}", res.items.len());
}
let (_, cv) = res.items.iter().next().unwrap();
let mut meta_opt = None; let mut meta_opt = None;
for v in cv.value.iter() {
// Resolve conflicts
for v in res.content().iter() {
match v { match v {
K2vValue::Tombstone => (), storage::Alternative::Tombstone => (),
K2vValue::Value(v) => { storage::Alternative::Value(v) => {
let meta = open_deserialize::<MailMeta>(v, &self.encryption_key)?; let meta = open_deserialize::<MailMeta>(v, &self.encryption_key)?;
match meta_opt.as_mut() { match meta_opt.as_mut() {
None => { None => {
@ -250,7 +227,7 @@ impl MailboxInternal {
if let Some(meta) = meta_opt { if let Some(meta) = meta_opt {
meta_vec.push(meta); meta_vec.push(meta);
} else { } else {
bail!("No valid meta value in k2v for {:?}", op.filter.start); bail!("No valid meta value in k2v for {:?}", res.to_ref().sk());
} }
} }
@ -258,19 +235,9 @@ impl MailboxInternal {
} }
async fn fetch_full(&self, id: UniqueIdent, message_key: &Key) -> Result<Vec<u8>> { async fn fetch_full(&self, id: UniqueIdent, message_key: &Key) -> Result<Vec<u8>> {
let gor = GetObjectRequest { let obj_res = self.s3.blob(&format!("{}/{}", self.mail_path, id)).fetch().await?;
bucket: self.bucket.clone(), let body = obj_res.content().ok_or(anyhow!("missing body"))?;
key: format!("{}/{}", self.mail_path, id), cryptoblob::open(body, message_key)
..Default::default()
};
let obj_res = self.s3.get_object(gor).await?;
let obj_body = obj_res.body.ok_or(anyhow!("Missing object body"))?;
let mut buf = Vec::with_capacity(obj_res.content_length.unwrap_or(128) as usize);
obj_body.into_async_read().read_to_end(&mut buf).await?;
cryptoblob::open(&buf, message_key)
} }
// ---- Functions for changing the mailbox ---- // ---- Functions for changing the mailbox ----
@ -303,13 +270,7 @@ impl MailboxInternal {
async { async {
// Encrypt and save mail body // Encrypt and save mail body
let message_blob = cryptoblob::seal(mail.raw, &message_key)?; let message_blob = cryptoblob::seal(mail.raw, &message_key)?;
let por = PutObjectRequest { self.s3.blob(&format!("{}/{}", self.mail_path, ident)).set_value(message_blob).push().await?;
bucket: self.bucket.clone(),
key: format!("{}/{}", self.mail_path, ident),
body: Some(message_blob.into()),
..Default::default()
};
self.s3.put_object(por).await?;
Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())
}, },
async { async {
@ -321,9 +282,7 @@ impl MailboxInternal {
rfc822_size: mail.raw.len(), rfc822_size: mail.raw.len(),
}; };
let meta_blob = seal_serialize(&meta, &self.encryption_key)?; let meta_blob = seal_serialize(&meta, &self.encryption_key)?;
self.k2v self.k2v.row(&self.mail_path, &ident.to_string()).set_value(meta_blob).push().await?;
.insert_item(&self.mail_path, &ident.to_string(), meta_blob, None)
.await?;
Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())
}, },
self.uid_index.opportunistic_sync() self.uid_index.opportunistic_sync()
@ -354,8 +313,8 @@ impl MailboxInternal {
futures::try_join!( futures::try_join!(
async { async {
// Copy mail body from previous location // Copy mail body from previous location
let dst = self.s3.blob(format!("{}/{}", self.mail_path, ident)); let dst = self.s3.blob(&format!("{}/{}", self.mail_path, ident));
blob_ref.copy(dst).await?; blob_ref.copy(&dst).await?;
Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())
}, },
async { async {
@ -367,9 +326,7 @@ impl MailboxInternal {
rfc822_size: mail.raw.len(), rfc822_size: mail.raw.len(),
}; };
let meta_blob = seal_serialize(&meta, &self.encryption_key)?; let meta_blob = seal_serialize(&meta, &self.encryption_key)?;
self.k2v self.k2v.row(&self.mail_path, &ident.to_string()).set_value(meta_blob).push().await?;
.insert_item(&self.mail_path, &ident.to_string(), meta_blob, None)
.await?;
Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())
}, },
self.uid_index.opportunistic_sync() self.uid_index.opportunistic_sync()
@ -393,21 +350,13 @@ impl MailboxInternal {
futures::try_join!( futures::try_join!(
async { async {
// Delete mail body from S3 // Delete mail body from S3
let dor = DeleteObjectRequest { self.s3.blob(&format!("{}/{}", self.mail_path, ident)).rm().await?;
bucket: self.bucket.clone(),
key: format!("{}/{}", self.mail_path, ident),
..Default::default()
};
self.s3.delete_object(dor).await?;
Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())
}, },
async { async {
// Delete mail meta from K2V // Delete mail meta from K2V
let sk = ident.to_string(); let sk = ident.to_string();
let v = self.k2v.read_item(&self.mail_path, &sk).await?; self.k2v.row(&self.mail_path, &sk).fetch().await?.to_ref().rm().await?;
self.k2v
.delete_item(&self.mail_path, &sk, v.causality)
.await?;
Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())
} }
)?; )?;
@ -438,7 +387,7 @@ impl MailboxInternal {
source_id: UniqueIdent, source_id: UniqueIdent,
new_id: UniqueIdent, new_id: UniqueIdent,
) -> Result<()> { ) -> Result<()> {
if self.bucket != from.bucket || self.encryption_key != from.encryption_key { if self.encryption_key != from.encryption_key {
bail!("Message to be copied/moved does not belong to same account."); bail!("Message to be copied/moved does not belong to same account.");
} }
@ -453,24 +402,15 @@ impl MailboxInternal {
futures::try_join!( futures::try_join!(
async { async {
// Copy mail body from S3 let dst = self.s3.blob(&format!("{}/{}", self.mail_path, new_id));
let cor = CopyObjectRequest { self.s3.blob(&format!("{}/{}", from.mail_path, source_id)).copy(&dst).await?;
bucket: self.bucket.clone(),
key: format!("{}/{}", self.mail_path, new_id),
copy_source: format!("{}/{}/{}", from.bucket, from.mail_path, source_id),
..Default::default()
};
self.s3.copy_object(cor).await?;
Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())
}, },
async { async {
// Copy mail meta in K2V // Copy mail meta in K2V
let meta = &from.fetch_meta(&[source_id]).await?[0]; let meta = &from.fetch_meta(&[source_id]).await?[0];
let meta_blob = seal_serialize(meta, &self.encryption_key)?; let meta_blob = seal_serialize(meta, &self.encryption_key)?;
self.k2v self.k2v.row(&self.mail_path, &new_id.to_string()).set_value(meta_blob).push().await?;
.insert_item(&self.mail_path, &new_id.to_string(), meta_blob, None)
.await?;
Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())
}, },
self.uid_index.opportunistic_sync(), self.uid_index.opportunistic_sync(),

View file

@ -14,17 +14,18 @@ use futures::future::BoxFuture;
pub mod in_memory; pub mod in_memory;
pub mod garage; pub mod garage;
pub enum Selector<'a> {
Range{ begin: &'a str, end: &'a str },
Filter(u64),
}
pub enum Alternative { pub enum Alternative {
Tombstone, Tombstone,
Value(Vec<u8>), Value(Vec<u8>),
} }
type ConcurrentValues = Vec<Alternative>; type ConcurrentValues = Vec<Alternative>;
pub enum Selector<'a> {
Range { begin: &'a str, end: &'a str },
List (Vec<(&'a str, &'a str)>),
Prefix (&'a str),
}
#[derive(Debug)] #[derive(Debug)]
pub enum StorageError { pub enum StorageError {
NotFound, NotFound,
@ -78,12 +79,15 @@ impl Hash for Builders {
pub trait IRowStore pub trait IRowStore
{ {
fn row(&self, partition: &str, sort: &str) -> RowRef; fn row(&self, partition: &str, sort: &str) -> RowRef;
fn select(&self, selector: Selector) -> AsyncResult<Vec<RowValue>>;
} }
pub type RowStore = Box<dyn IRowStore + Sync + Send>; pub type RowStore = Box<dyn IRowStore + Sync + Send>;
pub trait IRowRef pub trait IRowRef
{ {
fn clone_boxed(&self) -> RowRef; fn clone_boxed(&self) -> RowRef;
fn pk(&self) -> &str;
fn sk(&self) -> &str;
fn set_value(&self, content: Vec<u8>) -> RowValue; fn set_value(&self, content: Vec<u8>) -> RowValue;
fn fetch(&self) -> AsyncResult<RowValue>; fn fetch(&self) -> AsyncResult<RowValue>;
fn rm(&self) -> AsyncResult<()>; fn rm(&self) -> AsyncResult<()>;