backbone_bucket/application/service/
conversion_service.rs1use std::sync::Arc;
9
10use chrono::Utc;
11use uuid::Uuid;
12
13use super::error::{ServiceError, ServiceResult};
14use crate::domain::entity::{ConversionJob, ConversionStatus};
15use crate::infrastructure::persistence::ConversionJobRepository;
16use crate::infrastructure::persistence::StoredFileRepository;
17
18pub struct ConversionService {
20 conversion_repo: Arc<ConversionJobRepository>,
21 file_repo: Arc<StoredFileRepository>,
22}
23
24impl ConversionService {
25 pub fn new(
26 conversion_repo: Arc<ConversionJobRepository>,
27 file_repo: Arc<StoredFileRepository>,
28 ) -> Self {
29 Self { conversion_repo, file_repo }
30 }
31
32 pub async fn request_conversion(
34 &self,
35 source_file_id: Uuid,
36 target_format: &str,
37 options: Option<serde_json::Value>,
38 ) -> ServiceResult<ConversionJob> {
39 let _file = self.file_repo
40 .find_by_id(&source_file_id.to_string())
41 .await
42 .map_err(|e| ServiceError::Repository(backbone_core::RepositoryError::DatabaseError(e.to_string())))?
43 .ok_or(ServiceError::NotFound)?;
44
45 let mut builder = ConversionJob::builder()
46 .source_file_id(source_file_id)
47 .target_format(target_format.to_string())
48 .status(ConversionStatus::Pending)
49 .progress(0);
50
51 if let Some(opts) = options {
52 builder = builder.conversion_options(opts);
53 }
54
55 let job = builder.build()
56 .map_err(|e| ServiceError::Validation(e))?;
57
58 let created = self.conversion_repo
59 .create(&job)
60 .await
61 .map_err(|e| ServiceError::Repository(backbone_core::RepositoryError::DatabaseError(e.to_string())))?;
62
63 Ok(created)
64 }
65
66 pub async fn mark_started(&self, job_id: Uuid) -> ServiceResult<ConversionJob> {
68 let mut job = self.find_job(job_id).await?;
69
70 if job.status != ConversionStatus::Pending {
71 return Err(ServiceError::Validation(format!("Job {} is not in pending state", job_id)));
72 }
73
74 job.status = ConversionStatus::Processing;
75 job.started_at = Some(Utc::now());
76 job.metadata.touch();
77
78 let id_str = job.id.to_string();
79 self.conversion_repo
80 .update(&id_str, &job)
81 .await
82 .map_err(|e| ServiceError::Repository(backbone_core::RepositoryError::DatabaseError(e.to_string())))?
83 .ok_or(ServiceError::NotFound)
84 }
85
86 pub async fn update_progress(&self, job_id: Uuid, progress: i32) -> ServiceResult<ConversionJob> {
88 let mut job = self.find_job(job_id).await?;
89
90 if progress < 0 || progress > 100 {
91 return Err(ServiceError::Validation("Progress must be between 0 and 100".into()));
92 }
93
94 job.progress = progress;
95 job.metadata.touch();
96
97 let id_str = job.id.to_string();
98 self.conversion_repo
99 .update(&id_str, &job)
100 .await
101 .map_err(|e| ServiceError::Repository(backbone_core::RepositoryError::DatabaseError(e.to_string())))?
102 .ok_or(ServiceError::NotFound)
103 }
104
105 pub async fn mark_completed(
107 &self,
108 job_id: Uuid,
109 result_file_id: Uuid,
110 ) -> ServiceResult<ConversionJob> {
111 let mut job = self.find_job(job_id).await?;
112
113 job.status = ConversionStatus::Completed;
114 job.result_file_id = Some(result_file_id);
115 job.progress = 100;
116 job.completed_at = Some(Utc::now());
117 job.metadata.touch();
118
119 let id_str = job.id.to_string();
120 self.conversion_repo
121 .update(&id_str, &job)
122 .await
123 .map_err(|e| ServiceError::Repository(backbone_core::RepositoryError::DatabaseError(e.to_string())))?
124 .ok_or(ServiceError::NotFound)
125 }
126
127 pub async fn mark_failed(
129 &self,
130 job_id: Uuid,
131 error_message: &str,
132 ) -> ServiceResult<ConversionJob> {
133 let mut job = self.find_job(job_id).await?;
134
135 job.status = ConversionStatus::Failed;
136 job.error_message = Some(error_message.to_string());
137 job.completed_at = Some(Utc::now());
138 job.metadata.touch();
139
140 let id_str = job.id.to_string();
141 self.conversion_repo
142 .update(&id_str, &job)
143 .await
144 .map_err(|e| ServiceError::Repository(backbone_core::RepositoryError::DatabaseError(e.to_string())))?
145 .ok_or(ServiceError::NotFound)
146 }
147
148 async fn find_job(&self, job_id: Uuid) -> ServiceResult<ConversionJob> {
151 self.conversion_repo
152 .find_by_id(&job_id.to_string())
153 .await
154 .map_err(|e| ServiceError::Repository(backbone_core::RepositoryError::DatabaseError(e.to_string())))?
155 .ok_or(ServiceError::NotFound)
156 }
157}