use pubky_common::{
crypto::{Hash, Hasher},
timestamp::Timestamp,
};
const DEFAULT_CONTENT_TYPE: &str = "application/octet-stream";
#[derive(Debug, Clone)]
pub struct FileMetadata {
pub hash: Hash,
pub length: usize,
pub modified_at: Timestamp,
pub content_type: String,
}
#[derive(Debug, Clone, Default)]
pub struct FileMetadataBuilder {
hasher: Hasher,
length: usize,
path_content_type: Option<String>,
magic_bytes_content_type: Option<String>,
}
impl FileMetadataBuilder {
pub fn update(&mut self, chunk: &[u8]) {
let is_first_chunk = self.length == 0;
if is_first_chunk {
if let Some(ctype) = infer::get(chunk) {
self.magic_bytes_content_type = Some(ctype.mime_type().to_string());
}
}
self.hasher.update(chunk);
self.length += chunk.len();
}
pub fn guess_mime_type_from_path(&mut self, path: &str) {
let content_type = mime_guess::from_path(path)
.first_or_octet_stream()
.to_string();
self.path_content_type = Some(content_type);
}
fn derived_content_type(&self) -> String {
if let Some(magic_bytes_content_type) = &self.magic_bytes_content_type {
return magic_bytes_content_type.clone();
}
if let Some(path_content_type) = &self.path_content_type {
return path_content_type.clone();
}
DEFAULT_CONTENT_TYPE.to_string()
}
pub fn finalize(self) -> FileMetadata {
FileMetadata {
hash: self.hasher.finalize(),
length: self.length,
modified_at: Timestamp::now(),
content_type: self.derived_content_type(),
}
}
}