1use std::{
5 hash::{Hash, Hasher},
6 io,
7 str::FromStr,
8};
9use thiserror::Error;
10
11#[derive(Debug, Error)]
12pub enum RequestError {
13 #[error("apt command failed")]
14 Command(#[from] io::Error),
15 #[error("uri not found in output: {0}")]
16 UriNotFound(String),
17 #[error("invalid URI value: {0}")]
18 UriInvalid(String),
19 #[error("name not found in output: {0}")]
20 NameNotFound(String),
21 #[error("size not found in output: {0}")]
22 SizeNotFound(String),
23 #[error("size in output could not be parsed as an integer: {0}")]
24 SizeParse(String),
25 #[error("checksum not found in output: {0}")]
26 ChecksumNotFound(String),
27 #[error("unknown checksum for print-uri output: {0}")]
28 UnknownChecksum(String),
29}
30
31#[derive(Debug, Clone, Eq, PartialEq)]
32pub enum RequestChecksum {
33 Md5(String),
34 Sha1(String),
35 Sha256(String),
36 Sha512(String),
37}
38
39#[derive(Debug, Clone, Eq)]
40pub struct Request {
41 pub uri: String,
42 pub name: String,
43 pub size: u64,
44 pub checksum: RequestChecksum,
45}
46
47impl PartialEq for Request {
48 fn eq(&self, other: &Self) -> bool {
49 self.uri == other.uri
50 }
51}
52
53impl Hash for Request {
54 fn hash<H: Hasher>(&self, state: &mut H) {
55 self.uri.hash(state);
56 }
57}
58
59impl FromStr for Request {
60 type Err = RequestError;
61
62 fn from_str(line: &str) -> Result<Self, Self::Err> {
63 let mut words = line.split_whitespace();
64
65 let mut uri = words
66 .next()
67 .ok_or_else(|| RequestError::UriNotFound(line.into()))?;
68
69 if uri.len() <= 3 {
71 return Err(RequestError::UriInvalid(uri.into()));
72 } else {
73 uri = &uri[1..uri.len() - 1];
74 }
75
76 let name = words
77 .next()
78 .ok_or_else(|| RequestError::NameNotFound(line.into()))?;
79 let size = words
80 .next()
81 .ok_or_else(|| RequestError::SizeNotFound(line.into()))?;
82 let size = size
83 .parse::<u64>()
84 .map_err(|_| RequestError::SizeParse(size.into()))?;
85
86 let checksum_string = words
87 .next()
88 .ok_or_else(|| RequestError::ChecksumNotFound(line.into()))?;
89
90 let checksum = if let Some(value) = checksum_string.strip_prefix("MD5Sum:") {
91 RequestChecksum::Md5(value.to_owned())
92 } else if let Some(value) = checksum_string.strip_prefix("SHA1:") {
93 RequestChecksum::Sha1(value.to_owned())
94 } else if let Some(value) = checksum_string.strip_prefix("SHA256:") {
95 RequestChecksum::Sha256(value.to_owned())
96 } else if let Some(value) = checksum_string.strip_prefix("SHA512:") {
97 RequestChecksum::Sha512(value.to_owned())
98 } else {
99 return Err(RequestError::UnknownChecksum(checksum_string.into()));
100 };
101
102 Ok(Request {
103 uri: uri.into(),
104 name: name.into(),
105 size,
106 checksum,
107 })
108 }
109}