use crate::core::error::{BraidError, Result};
use crate::core::protocol;
use crate::core::types::{Version, Patch};
use axum::extract::Request;
use bytes::Bytes;
#[derive(Clone, Debug)]
pub struct ParsedUpdate {
pub version: Vec<Version>,
pub parents: Vec<Version>,
pub patches: Vec<Patch>,
pub body: Option<Bytes>,
}
impl ParsedUpdate {
pub async fn from_request(req: &Request) -> Result<Self> {
let version_header = req
.headers()
.get("version")
.and_then(|v| v.to_str().ok())
.unwrap_or("");
let parents_header = req
.headers()
.get("parents")
.and_then(|v| v.to_str().ok())
.unwrap_or("");
let version = protocol::parse_version_header(version_header)?;
let parents = protocol::parse_version_header(parents_header)?;
Ok(ParsedUpdate {
version,
parents,
patches: Vec::new(),
body: None,
})
}
}
pub trait ParseUpdateExt {
fn get_version(&self) -> Result<Vec<Version>>;
fn get_parents(&self) -> Result<Vec<Version>>;
fn get_patches(&self) -> Result<Vec<Patch>>;
fn parse_update(&self) -> Result<ParsedUpdate>;
}
#[allow(dead_code)]
pub fn parse_content_range(value: &str) -> Result<(String, String)> {
let parts: Vec<&str> = value.splitn(2, ' ').collect();
if parts.len() != 2 {
return Err(BraidError::HeaderParse(format!(
"Invalid Content-Range: {}",
value
)));
}
Ok((parts[0].to_string(), parts[1].to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_version_header() {
let result = protocol::parse_version_header("\"v1\", \"v2\", \"v3\"").unwrap();
assert_eq!(result.len(), 3);
}
#[test]
fn test_parse_version_header_empty() {
let result = protocol::parse_version_header("").unwrap();
assert_eq!(result.len(), 0);
}
#[test]
fn test_parse_content_range() {
let (unit, range) = protocol::parse_content_range("json .field").unwrap();
assert_eq!(unit, "json");
assert_eq!(range, ".field");
}
}