129 lines
3.8 KiB
Rust
129 lines
3.8 KiB
Rust
use std::path::{Path, PathBuf};
|
|
|
|
use crank_core::{DescriptorId, OperationId, SampleId};
|
|
use crank_registry::{DescriptorKind, SampleKind};
|
|
use serde_json::Value;
|
|
use thiserror::Error;
|
|
use tokio::fs;
|
|
|
|
#[derive(Clone)]
|
|
pub struct LocalArtifactStorage {
|
|
root: PathBuf,
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum StorageError {
|
|
#[error(transparent)]
|
|
Io(#[from] std::io::Error),
|
|
#[error(transparent)]
|
|
Serialization(#[from] serde_json::Error),
|
|
#[error("invalid storage reference: {details}")]
|
|
InvalidStorageRef { details: String },
|
|
}
|
|
|
|
impl LocalArtifactStorage {
|
|
pub fn new(root: PathBuf) -> Self {
|
|
Self { root }
|
|
}
|
|
|
|
pub async fn write_json_sample(
|
|
&self,
|
|
operation_id: &OperationId,
|
|
version: u32,
|
|
sample_kind: SampleKind,
|
|
sample_id: &SampleId,
|
|
payload: &Value,
|
|
) -> Result<String, StorageError> {
|
|
let file_name = match sample_kind {
|
|
SampleKind::InputJson => "input.json",
|
|
SampleKind::OutputJson => "output.json",
|
|
SampleKind::YamlImportSource => "source.json",
|
|
};
|
|
let path = self
|
|
.root
|
|
.join("samples")
|
|
.join(operation_id.as_str())
|
|
.join(format!("v{version}"))
|
|
.join(format!("{}_{}", sample_id.as_str(), file_name));
|
|
|
|
write_json_file(&path, payload).await?;
|
|
|
|
Ok(to_storage_ref(&path))
|
|
}
|
|
|
|
pub async fn read_json(&self, storage_ref: &str) -> Result<Value, StorageError> {
|
|
let path = from_storage_ref(storage_ref)?;
|
|
let bytes = fs::read(path).await?;
|
|
|
|
Ok(serde_json::from_slice(&bytes)?)
|
|
}
|
|
|
|
pub async fn write_descriptor(
|
|
&self,
|
|
operation_id: &OperationId,
|
|
version: u32,
|
|
descriptor_kind: DescriptorKind,
|
|
descriptor_id: &DescriptorId,
|
|
source_name: Option<&str>,
|
|
payload: &[u8],
|
|
) -> Result<String, StorageError> {
|
|
let file_name = match descriptor_kind {
|
|
DescriptorKind::ProtoUpload => source_name.unwrap_or("schema.proto").to_owned(),
|
|
DescriptorKind::DescriptorSet => source_name.unwrap_or("descriptor-set.bin").to_owned(),
|
|
DescriptorKind::ReflectionSnapshot => {
|
|
source_name.unwrap_or("reflection.bin").to_owned()
|
|
}
|
|
DescriptorKind::WsdlUpload => source_name.unwrap_or("service.wsdl").to_owned(),
|
|
DescriptorKind::XsdUpload => source_name.unwrap_or("schema.xsd").to_owned(),
|
|
};
|
|
let path = self
|
|
.root
|
|
.join("descriptors")
|
|
.join(operation_id.as_str())
|
|
.join(format!("v{version}"))
|
|
.join(format!("{}_{}", descriptor_id.as_str(), file_name));
|
|
|
|
write_bytes(&path, payload).await?;
|
|
|
|
Ok(to_storage_ref(&path))
|
|
}
|
|
|
|
pub async fn read_bytes(&self, storage_ref: &str) -> Result<Vec<u8>, StorageError> {
|
|
let path = from_storage_ref(storage_ref)?;
|
|
Ok(fs::read(path).await?)
|
|
}
|
|
}
|
|
|
|
async fn write_json_file(path: &Path, payload: &Value) -> Result<(), StorageError> {
|
|
if let Some(parent) = path.parent() {
|
|
fs::create_dir_all(parent).await?;
|
|
}
|
|
|
|
let bytes = serde_json::to_vec_pretty(payload)?;
|
|
fs::write(path, bytes).await?;
|
|
Ok(())
|
|
}
|
|
|
|
async fn write_bytes(path: &Path, payload: &[u8]) -> Result<(), StorageError> {
|
|
if let Some(parent) = path.parent() {
|
|
fs::create_dir_all(parent).await?;
|
|
}
|
|
|
|
fs::write(path, payload).await?;
|
|
Ok(())
|
|
}
|
|
|
|
fn to_storage_ref(path: &Path) -> String {
|
|
format!("file://{}", path.display())
|
|
}
|
|
|
|
fn from_storage_ref(storage_ref: &str) -> Result<PathBuf, StorageError> {
|
|
let Some(path) = storage_ref.strip_prefix("file://") else {
|
|
return Err(StorageError::InvalidStorageRef {
|
|
details: storage_ref.to_owned(),
|
|
});
|
|
};
|
|
|
|
Ok(PathBuf::from(path))
|
|
}
|