codetether_agent/tui/chat/sync/
s3_key.rs1use std::path::{Path, PathBuf};
4
5use super::config_types::ChatSyncConfig;
6
7pub fn sanitize_s3_key_segment(value: &str) -> String {
8 let mut out = String::with_capacity(value.len());
9 for ch in value.chars() {
10 if ch.is_ascii_alphanumeric() || matches!(ch, '-' | '_' | '.') {
11 out.push(ch);
12 } else {
13 out.push('-');
14 }
15 }
16 let cleaned = out.trim_matches('-').to_string();
17 if cleaned.is_empty() {
18 "unknown".into()
19 } else {
20 cleaned
21 }
22}
23
24pub fn chat_sync_checkpoint_path(archive_path: &Path, config: &ChatSyncConfig) -> PathBuf {
25 let e = sanitize_s3_key_segment(&config.endpoint.replace("://", "-"));
26 let b = sanitize_s3_key_segment(&config.bucket);
27 archive_path.with_file_name(format!("chat_events.minio-sync.{e}.{b}.offset"))
28}
29
30pub fn load_chat_sync_offset(checkpoint_path: &Path) -> u64 {
31 std::fs::read_to_string(checkpoint_path)
32 .ok()
33 .and_then(|v| v.trim().parse::<u64>().ok())
34 .unwrap_or(0)
35}
36
37pub fn store_chat_sync_offset(checkpoint_path: &Path, offset: u64) {
38 if let Err(err) = std::fs::write(checkpoint_path, offset.to_string()) {
39 tracing::warn!(error = %err, "Failed to store chat sync offset");
40 }
41}