Skip to main content

codetether_agent/tui/chat/sync/
batch_upload.rs

1//! Single batch upload logic.
2
3use std::path::PathBuf;
4
5use anyhow::Result;
6use minio::s3::builders::ObjectContent;
7use minio::s3::client::MinioClient;
8
9use super::archive_reader::read_chat_archive_batch;
10use super::config_types::ChatSyncConfig;
11use super::minio_client::ensure_minio_bucket;
12
13pub struct ChatSyncBatch {
14    pub bytes: u64,
15    pub records: usize,
16    pub object_key: String,
17    pub next_offset: u64,
18}
19
20pub async fn sync_batch(
21    client: &MinioClient,
22    archive_path: &PathBuf,
23    config: &ChatSyncConfig,
24    host_tag: &str,
25    offset: u64,
26) -> Result<Option<ChatSyncBatch>> {
27    if !archive_path.exists() {
28        return Ok(None);
29    }
30    ensure_minio_bucket(client, &config.bucket).await?;
31    let (payload, next_offset, records) = read_chat_archive_batch(archive_path, offset)?;
32    if payload.is_empty() {
33        return Ok(None);
34    }
35    let ts = chrono::Utc::now().format("%Y%m%dT%H%M%SZ");
36    let pfx = config.prefix.trim_matches('/');
37    let key = if pfx.is_empty() {
38        format!("{host_tag}/{ts}-chat-evts-{offset:020}-{next_offset:020}.jsonl")
39    } else {
40        format!("{pfx}/{host_tag}/{ts}-chat-evts-{offset:020}-{next_offset:020}.jsonl")
41    };
42    let bytes = payload.len() as u64;
43    client
44        .put_object_content(&config.bucket, &key, ObjectContent::from(payload))?
45        .build()
46        .send()
47        .await?;
48    Ok(Some(ChatSyncBatch {
49        bytes,
50        records,
51        object_key: key,
52        next_offset,
53    }))
54}