use anyhow::anyhow;
use base64::{Engine as _, engine::general_purpose as base64_engine};
use std::path::{Path, PathBuf};
use tempfile::TempDir;
use crate::cmd::dap_server::DebuggerError;
pub(crate) struct UploadedFiles {
temp_dir: TempDir,
}
impl UploadedFiles {
pub(crate) fn new() -> Result<Self, DebuggerError> {
let temp_dir = tempfile::Builder::new()
.prefix("probe-rs-dap-")
.tempdir()
.map_err(|err| {
DebuggerError::Other(anyhow!(
"Could not create temporary directory for client-uploaded files: {err}"
))
})?;
tracing::info!(
"Created temporary directory for client-uploaded files: {}",
temp_dir.path().display()
);
Ok(Self { temp_dir })
}
pub(crate) fn materialize(
&mut self,
role: &str,
client_path_hint: &Path,
data_base64: &str,
) -> Result<PathBuf, DebuggerError> {
let bytes = base64_engine::STANDARD.decode(data_base64).map_err(|err| {
DebuggerError::Other(anyhow!(
"Could not decode base64 for client-uploaded file (role `{role}`, originally `{}`): {err}",
client_path_hint.display()
))
})?;
let basename = client_path_hint
.file_name()
.map(|name| name.to_string_lossy().to_string())
.filter(|name| !name.is_empty());
let dest = match basename {
Some(basename) => self.temp_dir.path().join(format!("{role}-{basename}")),
None => self.temp_dir.path().join(role),
};
std::fs::write(&dest, &bytes).map_err(|err| {
DebuggerError::Other(anyhow!(
"Could not write client-uploaded file (role `{role}`, originally `{}`) to temporary location `{}`: {err}",
client_path_hint.display(),
dest.display()
))
})?;
tracing::info!(
"Materialized client-uploaded file (role `{role}`, originally `{}`, {} bytes) to `{}`",
client_path_hint.display(),
bytes.len(),
dest.display()
);
Ok(dest)
}
}