1use std::str::FromStr;
6use std::collections::HashMap;
7
8use bytes::Bytes;
9use async_trait::async_trait;
10use futures::stream::StreamExt;
11
12use crate::hash::SHA1;
13use crate::internal::object::ObjectTrait;
14
15use crate::protocol::smart::SmartProtocol;
16use crate::protocol::types::{ProtocolError, ProtocolStream, ServiceType};
17
18#[async_trait]
23pub trait RepositoryAccess: Send + Sync + Clone {
24 async fn get_repository_refs(&self) -> Result<Vec<(String, String)>, ProtocolError>;
26
27 async fn has_object(&self, object_hash: &str) -> Result<bool, ProtocolError>;
29
30 async fn get_object(&self, object_hash: &str) -> Result<Vec<u8>, ProtocolError>;
32
33 async fn store_pack_data(&self, pack_data: &[u8]) -> Result<(), ProtocolError>;
35
36 async fn update_reference(
38 &self,
39 ref_name: &str,
40 old_hash: Option<&str>,
41 new_hash: &str,
42 ) -> Result<(), ProtocolError>;
43
44 async fn get_objects_for_pack(
46 &self,
47 wants: &[String],
48 haves: &[String],
49 ) -> Result<Vec<String>, ProtocolError>;
50
51 async fn has_default_branch(&self) -> Result<bool, ProtocolError>;
53
54 async fn post_receive_hook(&self) -> Result<(), ProtocolError>;
56
57 async fn get_blob(
62 &self,
63 object_hash: &str,
64 ) -> Result<crate::internal::object::blob::Blob, ProtocolError> {
65 let data = self.get_object(object_hash).await?;
66 let hash = SHA1::from_str(object_hash)
67 .map_err(|e| ProtocolError::repository_error(format!("Invalid hash format: {}", e)))?;
68
69 crate::internal::object::blob::Blob::from_bytes(&data, hash)
70 .map_err(|e| ProtocolError::repository_error(format!("Failed to parse blob: {}", e)))
71 }
72
73 async fn get_commit(
78 &self,
79 commit_hash: &str,
80 ) -> Result<crate::internal::object::commit::Commit, ProtocolError> {
81 let data = self.get_object(commit_hash).await?;
82 let hash = SHA1::from_str(commit_hash)
83 .map_err(|e| ProtocolError::repository_error(format!("Invalid hash format: {}", e)))?;
84
85 crate::internal::object::commit::Commit::from_bytes(&data, hash)
86 .map_err(|e| ProtocolError::repository_error(format!("Failed to parse commit: {}", e)))
87 }
88
89 async fn get_tree(
94 &self,
95 tree_hash: &str,
96 ) -> Result<crate::internal::object::tree::Tree, ProtocolError> {
97 let data = self.get_object(tree_hash).await?;
98 let hash = SHA1::from_str(tree_hash)
99 .map_err(|e| ProtocolError::repository_error(format!("Invalid hash format: {}", e)))?;
100
101 crate::internal::object::tree::Tree::from_bytes(&data, hash)
102 .map_err(|e| ProtocolError::repository_error(format!("Failed to parse tree: {}", e)))
103 }
104
105 async fn commit_exists(&self, commit_hash: &str) -> Result<bool, ProtocolError> {
110 match self.has_object(commit_hash).await {
111 Ok(exists) => {
112 if !exists {
113 return Ok(false);
114 }
115
116 match self.get_commit(commit_hash).await {
118 Ok(_) => Ok(true),
119 Err(_) => Ok(false), }
121 }
122 Err(e) => Err(e),
123 }
124 }
125
126 async fn handle_pack_objects(
131 &self,
132 commits: Vec<crate::internal::object::commit::Commit>,
133 trees: Vec<crate::internal::object::tree::Tree>,
134 blobs: Vec<crate::internal::object::blob::Blob>,
135 ) -> Result<(), ProtocolError> {
136 for blob in blobs {
138 let data = blob.to_data().map_err(|e| {
139 ProtocolError::repository_error(format!("Failed to serialize blob: {}", e))
140 })?;
141 self.store_pack_data(&data).await.map_err(|e| {
142 ProtocolError::repository_error(format!("Failed to store blob {}: {}", blob.id, e))
143 })?;
144 }
145
146 for tree in trees {
148 let data = tree.to_data().map_err(|e| {
149 ProtocolError::repository_error(format!("Failed to serialize tree: {}", e))
150 })?;
151 self.store_pack_data(&data).await.map_err(|e| {
152 ProtocolError::repository_error(format!("Failed to store tree {}: {}", tree.id, e))
153 })?;
154 }
155
156 for commit in commits {
158 let data = commit.to_data().map_err(|e| {
159 ProtocolError::repository_error(format!("Failed to serialize commit: {}", e))
160 })?;
161 self.store_pack_data(&data).await.map_err(|e| {
162 ProtocolError::repository_error(format!(
163 "Failed to store commit {}: {}",
164 commit.id, e
165 ))
166 })?;
167 }
168
169 Ok(())
170 }
171}
172
173#[async_trait]
175pub trait AuthenticationService: Send + Sync {
176 async fn authenticate_http(
178 &self,
179 headers: &std::collections::HashMap<String, String>,
180 ) -> Result<(), ProtocolError>;
181
182 async fn authenticate_ssh(
184 &self,
185 username: &str,
186 public_key: &[u8],
187 ) -> Result<(), ProtocolError>;
188}
189
190pub struct GitProtocol<R: RepositoryAccess, A: AuthenticationService> {
197 smart_protocol: SmartProtocol<R, A>,
198}
199
200impl<R: RepositoryAccess, A: AuthenticationService> GitProtocol<R, A> {
201 pub fn new(repo_access: R, auth_service: A) -> Self {
203 Self {
204 smart_protocol: SmartProtocol::new(
205 super::types::TransportProtocol::Http,
206 repo_access,
207 auth_service,
208 ),
209 }
210 }
211
212 pub async fn authenticate_http(
214 &self,
215 headers: &HashMap<String, String>,
216 ) -> Result<(), ProtocolError> {
217 self.smart_protocol.authenticate_http(headers).await
218 }
219
220 pub async fn authenticate_ssh(
222 &self,
223 username: &str,
224 public_key: &[u8],
225 ) -> Result<(), ProtocolError> {
226 self.smart_protocol
227 .authenticate_ssh(username, public_key)
228 .await
229 }
230
231 pub fn set_transport(&mut self, protocol: super::types::TransportProtocol) {
233 self.smart_protocol.set_transport_protocol(protocol);
234 }
235
236 pub async fn info_refs(&self, service: &str) -> Result<Vec<u8>, ProtocolError> {
238 let service_type = match service {
239 "git-upload-pack" => ServiceType::UploadPack,
240 "git-receive-pack" => ServiceType::ReceivePack,
241 _ => return Err(ProtocolError::invalid_service(service)),
242 };
243
244 let bytes = self.smart_protocol.git_info_refs(service_type).await?;
245 Ok(bytes.to_vec())
246 }
247
248 pub async fn upload_pack(
250 &mut self,
251 request_data: &[u8],
252 ) -> Result<ProtocolStream, ProtocolError> {
253 let request_bytes = bytes::Bytes::from(request_data.to_vec());
254 let (stream, _) = self.smart_protocol.git_upload_pack(request_bytes).await?;
255 Ok(Box::pin(stream.map(|data| Ok(Bytes::from(data)))))
256 }
257
258 pub async fn receive_pack(
260 &mut self,
261 request_stream: ProtocolStream,
262 ) -> Result<ProtocolStream, ProtocolError> {
263 let result_bytes = self
264 .smart_protocol
265 .git_receive_pack_stream(request_stream)
266 .await?;
267 Ok(Box::pin(futures::stream::once(async { Ok(result_bytes) })))
269 }
270}