kitab

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs | LICENSE

commit 0d5bb2ccf50e0818596c23ddd4419d73875f4a48
parent 755845681c413745261faf953320c806e4e35aa7
Author: lash <dev@holbrook.no>
Date:   Tue, 26 Jul 2022 18:19:22 +0000

WIP module documentation

Diffstat:
Msrc/digest.rs | 11+++++++++++
Msrc/error.rs | 1+
Msrc/meta.rs | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/rdf.rs | 25+++++++++++++++++++++++++
4 files changed, 108 insertions(+), 23 deletions(-)

diff --git a/src/digest.rs b/src/digest.rs @@ -8,6 +8,7 @@ use sha2::{ use log::error; +/// Encapsulations of supported digests for digest data. pub enum RecordDigest { Sha512(Vec<u8>), Sha256(Vec<u8>), @@ -17,6 +18,9 @@ pub enum RecordDigest { +/// Create a [RecordDigest::Sha512](RecordDigest::Sha512) instance from the raw digest data. +/// +/// Will fail if digest has incorrect length. pub fn from_vec(v: Vec<u8>) -> Result<RecordDigest, ParseError> { let sz = Sha512::output_size(); if v.len() != sz { @@ -25,6 +29,13 @@ pub fn from_vec(v: Vec<u8>) -> Result<RecordDigest, ParseError> { Ok(RecordDigest::Sha512(v)) } +/// Create a [RecordDigest](RecordDigest) instance corresponding to the URN digest scheme. +/// +/// Valid URN schemes and their corresponding enumerated values are: +/// +/// * `sha512` -> [RecordDigest::Sha512](RecordDigest::Sha512]) +/// * `sha256` -> [RecordDigest::Sha256](RecordDigest::Sha256]) +/// * `bzz` -> [RecordDigest::SwarmHash](RecordDigest::SwarmHash]) pub fn from_urn(urn: &str) -> Result<RecordDigest, ParseError> { let mut v = urn.split(":"); let r = match v.next() { diff --git a/src/error.rs b/src/error.rs @@ -1,2 +1,3 @@ +/// Used for any parsing error for any supported format. #[derive(Debug)] pub struct ParseError; diff --git a/src/meta.rs b/src/meta.rs @@ -43,114 +43,147 @@ use log::{ debug, }; +/// Date elements as d/m/Y tuple. pub type PublishDate = (u8, u8, u32); +/// Alias for file name (basename). pub type FileName = String; +/// Alias for absolute file path. pub type FilePath = String; +/// Represents the full metadata for a media file. pub struct MetaData { + /// The Dublin Core vocabulary parts of the metadata. dc: DCMetaData, + /// The digest of the file that the metadata is keyed to. digest: digest::RecordDigest, + /// Optional local filename, e.g. to use for HTTP `Content-Disposition` header, rename matching files to client's original name, etc. local_name: Option<FileName>, - comment: String, + /// Publication date of the content that the media represents. publish_date: PublishDate, - retrieval_timestamp: u32, } -pub fn check_xattr() { +//pub fn check_xattr() { -} +//} +/// Generates the native `sha512` digest of a file. +/// +/// # Arguments +/// +/// * `filepath` - Absolute path to file to calculate digest for. pub fn digest_from_path(filepath: &path::Path) -> Vec<u8> { - let mut h = Sha512::new(); - let st = metadata(filepath).unwrap(); - let bs: u64 = st.st_blksize(); - let sz: u64 = st.st_size(); - let mut b: Vec<u8> = vec!(0; bs as usize); - let mut f = File::open(filepath).unwrap(); - let mut i: usize = 0; - while i < sz as usize { - let c = f.read(&mut b).unwrap(); - h.update(&b[..c]); - i += c; - } - h.finalize().to_vec() + let mut h = Sha512::new(); + let st = metadata(filepath).unwrap(); + let bs: u64 = st.st_blksize(); + let sz: u64 = st.st_size(); + let mut b: Vec<u8> = vec!(0; bs as usize); + let mut f = File::open(filepath).unwrap(); + let mut i: usize = 0; + while i < sz as usize { + let c = f.read(&mut b).unwrap(); + h.update(&b[..c]); + i += c; } + h.finalize().to_vec() +} + impl MetaData { - pub fn new(title: &str, author: &str, typ: EntryType, digest: Vec<u8>, filename: Option<FileName>) -> MetaData { - let dc = DCMetaData::new(title, author, typ); + /// Create a new MetaData instance with basic data. + /// + /// # Arguments + /// + /// * `title` - Maps to the [DCMetaData::title] field. + /// * `author` - Maps to the [DCMetaData::author] field. + /// * `entry_type` - Maps to the [DCMetaData::typ] field. + /// * `digest` - The digest of the media file. + /// * `filename` - The client's optional local file name for the media. + pub fn new(title: &str, author: &str, entry_type: EntryType, digest: Vec<u8>, filename: Option<FileName>) -> MetaData { + let dc = DCMetaData::new(title, author, entry_type); let mut m = MetaData{ dc: dc, digest: digest::RecordDigest::Empty, - comment: String::new(), local_name: filename, publish_date: (0, 0, 0), - retrieval_timestamp: 0, }; m.set_fingerprint(digest); m } + /// Create an empty MetaData instance. pub fn empty() -> MetaData { let dc = DCMetaData::new("", "", EntryType::Unknown(String::new())); MetaData{ dc: dc, digest: digest::RecordDigest::Empty, - comment: String::new(), //local_name: filepath.to_str().unwrap().to_string(), local_name: None, publish_date: (0, 0, 0), - retrieval_timestamp: 0, } } + /// Set the [DCMetaData::title](DCMetaData::title) value. pub fn set_title(&mut self, title: &str) { self.dc.title = String::from(title); } + /// Set the [DCMetaData::author](DCMetaData::author) value. pub fn set_author(&mut self, author: &str) { self.dc.author = String::from(author); } + /// Set the digest as [digest::RecordDigest::Sha512](digest::RecordDigest::Sha512) instance of the provided + /// fingerprint. pub fn set_fingerprint(&mut self, fingerprint: Vec<u8>) { self.digest = digest::from_vec(fingerprint).unwrap(); } + /// Set the digest from the given URN string. + /// + /// The URN must specify a valid supported [digest](digest::from_urn) scheme. pub fn set_fingerprint_urn(&mut self, urn: &str) { self.digest = digest::from_urn(urn).unwrap(); } + /// Returns the current [DCMetaData::title](DCMetaData::title) value. pub fn title(&self) -> String { self.dc.title.clone() } + /// Returns the current [DCMetaData::author](DCMetaData::author) value. pub fn author(&self) -> String { self.dc.author.clone() } + /// Set the [DCMetaData::typ](DCMetaData::typ) value. pub fn set_typ(&mut self, typ: &str) { self.dc.typ = EntryType::from_str(typ).unwrap(); } + /// Returns the current [DCMetaData::typ](DCMetaData::typ) value. pub fn typ(&self) -> EntryType { self.dc.typ.clone() } + /// Set the current [DCMetaData::subject](DCMetaData::subject) value. pub fn set_subject(&mut self, v: &str) { self.dc.subject = Some(String::from(v)); } + /// Returns the current [DCMetaData::subject](DCMetaData::subject) value. pub fn subject(&self) -> Option<String> { return self.dc.subject.clone(); } + /// Set the current [DCMetaData::mime](DCMetaData::mime) value. pub fn set_mime(&mut self, m: Mime) { self.dc.mime = Some(m); } + /// Set the current [DCMetaData::mime](DCMetaData::mime) value from the given MIME identifier string. pub fn set_mime_str(&mut self, s: &str) { match Mime::from_str(s) { Ok(v) => { @@ -162,19 +195,23 @@ impl MetaData { }; } + /// Returns the current [DCMetaData::mime](DCMetaData::mime) value. pub fn mime(&self) -> Option<Mime> { self.dc.mime.clone() } + /// Set the current [DCMetaData::language](DCMetaData::language) value. pub fn set_language(&mut self, s: &str) { let v = s.parse().unwrap(); self.dc.language = Some(v); } + /// Returns the current [DCMetaData::language](DCMetaData::language) value. pub fn language(&self) -> Option<LanguageIdentifier> { self.dc.language.clone() } + /// Returns the digest value of the media as a hex-encoded string. pub fn fingerprint(&self) -> String { match &self.digest { digest::RecordDigest::Empty => { @@ -192,6 +229,7 @@ impl MetaData { } } + /// Instantiate metadata from the extended attributes of the file in `filepath`. pub fn from_xattr(filepath: &path::Path) -> MetaData { let mut title: String = String::new(); @@ -283,6 +321,9 @@ impl MetaData { } + /// Applies the metadata as extended file attributes of the file in `filepath`. + /// + /// pub fn to_xattr(&self, filepath: &path::Path) -> Result<(), std::io::Error> { let filename = filepath.file_name() .unwrap() @@ -363,6 +404,7 @@ impl MetaData { } #[cfg(feature = "magic")] + /// Automatically detect media type of file in `path`. pub fn set_mime_magic(&mut self, path: &path::Path) { if self.mime() == None { let mime = tree_magic::from_filepath(path); @@ -371,6 +413,9 @@ impl MetaData { } } + /// Parse metadata from simplified metadata format contained in file in `path`. + /// + /// see [MetaData::from_file](MetaData::from_file) pub fn from_path(p: &path::Path) -> Result<MetaData, std::io::Error> { let f = File::open(&p).unwrap(); debug!("openning {}", p.display()); @@ -378,6 +423,9 @@ impl MetaData { Ok(m) } + /// Parse metadata from simplified metadata format contained in the given file instance `f`. + /// + /// TODO: describe format. pub fn from_file(f: File) -> Result<MetaData, std::io::Error> { let mut m = MetaData::empty(); //let f = File::open(path).unwrap(); diff --git a/src/rdf.rs b/src/rdf.rs @@ -45,11 +45,23 @@ use crate::dc::{ }; #[derive(Debug)] +/// Error states when processing RDF data. pub enum RdfError { + /// Invalid URN string or digest scheme. UrnError(UrnError), + /// Hash does not match hash in current [crate::meta::MetaData](crate::meta::MetaData) + /// instance. HashMismatchError, } +/// Write metadata entry in the native rdf-turtle format. +/// +/// On success, returns the number of bytes written. +/// +/// # Arguments +/// +/// * `entry` - metadata to write. +/// * `w` - writer implementation providing the destination. pub fn write(entry: &MetaData, w: impl Write) -> Result<usize, std::io::Error> { let mut tfmt = TurtleFormatter::new(w); @@ -186,6 +198,13 @@ fn handle_parse_match(metadata: &mut MetaData, triple: Triple) -> Result<(), Rdf Ok(()) } +/// Read one or more metadata entries from the rdf-turtle source. +/// +/// Will return `ParseError` if any of the records are invalid. +/// +/// # Arguments +/// +/// * `r` - reader implementation providing the source. pub fn read_all(r: impl Read) -> Result<Vec<MetaData>, ParseError> { let mut rr: Vec<MetaData> = vec!(); let bf = BufReader::new(r); @@ -218,6 +237,12 @@ pub fn read_all(r: impl Read) -> Result<Vec<MetaData>, ParseError> { } Ok(rr) } + +/// Read a single metadata entry from the rdf-turtle source. +/// +/// # Arguments +/// +/// * `r` - reader implementation providing the source. pub fn read(r: impl Read) -> MetaData { let mut rr: Vec<MetaData> = vec!(); let mut metadata = MetaData::empty();