use crate::util::now_ms;
pub use crate::util::{datetime_to_ms, ms_to_display};
use map_core::client::MapClient;
use map_core::folders::Folder;
use store::{Direction, FolderSyncStatus, NewMessage, Store};
use tokio::io::{AsyncRead, AsyncWrite};
use crate::fetch::{fetch_folder, FetchedMessage};
fn to_new_message(msg: FetchedMessage, synced_at: i64) -> NewMessage {
NewMessage {
map_handle: msg.handle,
timestamp_ms: msg.timestamp_ms,
folder: msg.folder,
direction: if msg.sent { Direction::Sent } else { Direction::Received },
address: msg.address,
status: i32::from(msg.read),
synced_at,
text: msg.text,
outgoing_status: None,
}
}
async fn backfill_folder<T: AsyncRead + AsyncWrite + Unpin>(
client: &mut MapClient<T>,
store: &Store,
folder: Folder,
now: i64,
) -> anyhow::Result<()> {
let cursor = store.get_cursor(folder.as_str()).await?;
let since_ms = cursor.as_ref().map(|c| c.highest_ts);
let mut highest_ts_seen = cursor.as_ref().map_or(0, |c| c.highest_ts);
let folder_str = folder.as_str();
let is_sent = folder == Folder::Sent;
for msg in fetch_folder(client, folder, since_ms, now).await? {
if msg.timestamp_ms > highest_ts_seen {
highest_ts_seen = msg.timestamp_ms;
}
let handle = msg.handle.clone();
store.upsert(to_new_message(msg, now)).await?;
if is_sent {
store.reconcile_outgoing(&handle).await?;
}
}
store.set_cursor(folder_str, now, highest_ts_seen, FolderSyncStatus::Complete).await?;
Ok(())
}
pub async fn backfill<T: AsyncRead + AsyncWrite + Unpin>(
client: &mut MapClient<T>,
store: &Store,
folder_scope: Option<Folder>,
) -> anyhow::Result<()> {
let all_folders = [Folder::Inbox, Folder::Sent, Folder::Deleted, Folder::Outbox];
let single;
let folders: &[Folder] = if let Some(f) = folder_scope {
single = [f];
&single
} else {
&all_folders
};
let now = now_ms();
let mut first_err: Option<anyhow::Error> = None;
for &folder in folders {
if let Err(e) = backfill_folder(client, store, folder, now).await {
tracing::warn!("backfill: {} failed — {e:#}", folder.as_str());
if first_err.is_none() {
first_err = Some(e);
}
}
}
first_err.map_or(Ok(()), Err)
}
pub async fn backfill_catch_up<T: AsyncRead + AsyncWrite + Unpin>(
client: &mut MapClient<T>,
store: &Store,
) -> anyhow::Result<()> {
backfill(client, store, None).await
}