use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use serde_json::Value;
use crate::error::{AtmError, AtmErrorKind};
use crate::persistence;
use crate::schema::InboxMessage;
use crate::schema::inbox_message::{SharedAppendPolicy, to_shared_inbox_value_with_policy};
pub fn write_messages(
path: &Path,
messages: &[InboxMessage],
export_policy: SharedAppendPolicy,
) -> Result<(), AtmError> {
write_message_iter(path, messages.iter(), export_policy)
}
pub fn write_message_iter<'a, I>(
path: &Path,
messages: I,
export_policy: SharedAppendPolicy,
) -> Result<(), AtmError>
where
I: IntoIterator<Item = &'a InboxMessage>,
{
let iterator = messages.into_iter();
let mut encoded = Vec::<Value>::new();
for message in iterator {
encoded.push(to_shared_inbox_value_with_policy(message, export_policy)?);
}
let mut bytes = serde_json::to_vec(&encoded)?;
bytes.push(b'\n');
persistence::atomic_write_bytes(
path,
&bytes,
AtmErrorKind::MailboxWrite,
"mailbox file",
"Check that the mailbox directory is writable, has available disk space, and resides on a healthy filesystem before retrying the ATM command.",
)
}
#[cfg_attr(
not(test),
allow(
dead_code,
reason = "JSONL append helper remains test-only after compat retirement"
)
)]
pub fn append_message(
path: &Path,
message: &InboxMessage,
export_policy: SharedAppendPolicy,
) -> Result<(), AtmError> {
let encoded = to_shared_inbox_value_with_policy(message, export_policy)?;
append_jsonl_record(path, &encoded)
}
pub fn append_jsonl_record<T: serde::Serialize>(path: &Path, record: &T) -> Result<(), AtmError> {
let mut bytes = serde_json::to_vec(record)?;
bytes.push(b'\n');
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(path)
.map_err(|error| {
AtmError::new(
AtmErrorKind::MailboxWrite,
format!("failed to open mailbox file {} for append: {error}", path.display()),
)
.with_recovery(
"Check that the mailbox directory is writable, has available disk space, and resides on a healthy filesystem before retrying the ATM command.",
)
.with_source(error)
})?;
file.write_all(&bytes).map_err(|error| {
AtmError::new(
AtmErrorKind::MailboxWrite,
format!("failed to append mailbox record {}: {error}", path.display()),
)
.with_recovery(
"Check that the mailbox directory is writable, has available disk space, and resides on a healthy filesystem before retrying the ATM command.",
)
.with_source(error)
})?;
file.sync_data().map_err(|error| {
AtmError::new(
AtmErrorKind::MailboxWrite,
format!("failed to sync appended mailbox record {}: {error}", path.display()),
)
.with_recovery(
"Check that the mailbox directory is writable, has available disk space, and resides on a healthy filesystem before retrying the ATM command.",
)
.with_source(error)
})
}