holger_rust_repository/
lib.rs1use sha2::{Sha256, Digest};
2use std::any::Any;
3use anyhow::anyhow;
4use holger_traits::{ArtifactFormat, ArtifactId, RepositoryBackendTrait};
5
6pub struct RustRepo {
8 pub name: String,
9pub artifacts: Vec<ArtifactId>, }
12
13impl RustRepo {
14 pub fn new(name: String) -> Self {
15 RustRepo {
16
17 name,
21 artifacts: vec![],
22 }
23 }
24
25 pub fn sparse_path(crate_name: &str) -> (String, String, String) {
27 let mut chars = crate_name.chars();
28
29 let p1: String = chars.by_ref().take(2).collect();
30 let mut p2: String = chars.by_ref().take(2).collect();
31
32 if p2.is_empty() {
34 p2.push('_');
35 }
36
37 (p1, p2, crate_name.to_string())
38 }
39
40 #[inline]
42 pub fn sparse_crate_from_parts<'a>(parts: &'a [&'a str]) -> Option<&'a str> {
43 if parts.len() == 3 {
44 Some(parts[2])
45 } else {
46 None
47 }
48 }
49 #[inline]
50 pub fn crate_sha256_hex(data: &[u8]) -> String {
51 use sha2::{Sha256, Digest};
52 use hex::encode; let mut hasher = Sha256::new();
55 hasher.update(data);
56 let hash = hasher.finalize(); encode(hash) }
59}
60
61
62impl RepositoryBackendTrait for RustRepo {
63 fn name(&self) -> &str {
64 &self.name
65 }
66
67 fn handle_http2_request(
68 &self,
69 suburl: &str,
70 body: &[u8],
71 ) -> anyhow::Result<(u16, Vec<(String, String)>, Vec<u8>)> {
72 let _ = body;
73 println!("Rust repo handle_http2_request.suburl={}", suburl);
74
75 let parts: Vec<&str> = suburl.trim_start_matches('/').split('/').collect();
76
77 match parts.as_slice() {
78 [repo, "index", "config.json"] if *repo == self.name() => {
80 println!("Sparse config.json requested");
81 let json = format!(
82 r#"{{
83 "dl": "https://127.0.0.1:8443/{}/crates",
84 "api": null
85 }}"#,
86 self.name()
87 );
88 return Ok((
89 200,
90 vec![("Content-Type".into(), "application/json".into())],
91 json.as_bytes().to_vec(),
92 ));
93 }
94
95 [repo, "index", p1, p2, crate_name] if *repo == self.name() => {
97 if let Some(actual_name) = RustRepo::sparse_crate_from_parts(&[p1, p2, crate_name]) {
98 println!("Sparse crate metadata request: {}/{}/{}", p1, p2, actual_name);
99
100 let fake_crate_data = b"FAKE_CRATE_CONTENT";
101 let checksum_hex = RustRepo::crate_sha256_hex(fake_crate_data);
102
103 let json = format!(
104 r#"[{{"vers":"1.0.0","deps":[],"cksum":"{}"}}]"#,
105 checksum_hex
106 );
107
108 return Ok((
109 200,
110 vec![("Content-Type".into(), "application/json".into())],
111 json.into_bytes(),
112 ));
113 } else {
114 return Ok((404, Vec::new(), b"Not found".to_vec()));
115 }
116 }
117
118 ["crates", crate_name, version, "download"] => {
120 println!("Download request: crate={} version={}", crate_name, version);
121 return Ok((
122 200,
123 vec![("Content-Type".into(), "application/octet-stream".into())],
124 b"FAKE_CRATE_CONTENT".to_vec(),
125 ));
126 }
127
128 _ => {
129 println!("Unhandled path: {}", suburl);
130 Ok((404, Vec::new(), b"Not found".to_vec()))
131 }
132 }
133 }
134 fn format(&self) -> ArtifactFormat {
135 ArtifactFormat::Rust
136 }
137
138
139 fn is_writable(&self) -> bool {
140 todo!()
141 }
142
143 fn fetch(&self, id: &ArtifactId) -> anyhow::Result<Option<Vec<u8>>> {
144 todo!()
145 }
146
147 fn put(&self, id: &ArtifactId, data: &[u8]) -> anyhow::Result<()> {
148 todo!()
149 }
150}
151
152