1use std::sync::Arc;
2
3use anyhow::anyhow;
4use async_trait::async_trait;
5use log::debug;
6use simpledi_rs::di::{DIContainer, DIContainerExtTrait, DependencyInjectTrait};
7
8use crate::error::HuberError::PackageNotFound;
9use crate::gh::{GithubClient, GithubClientTrait};
10use crate::model::config::{Config, ConfigFieldConvertTrait};
11use crate::model::package::{Package, PackageSource, PackageSummary};
12use crate::model::release::{ReleaseKind, SortModelTrait};
13use crate::service::cache::{CacheService, CacheTrait};
14use crate::service::{ItemOperationAsyncTrait, ItemOperationTrait, ItemSearchTrait, ServiceTrait};
15
16#[derive(Debug, Clone)]
17pub struct PackageService {
18 pub container: Option<Arc<DIContainer>>,
19}
20
21unsafe impl Send for PackageService {}
22
23unsafe impl Sync for PackageService {}
24
25impl Default for PackageService {
26 fn default() -> Self {
27 Self::new()
28 }
29}
30
31impl PackageService {
32 pub fn new() -> Self {
33 Self { container: None }
34 }
35
36 pub async fn find_summary(
37 &self,
38 pkg_name: &str,
39 release_build_only: bool,
40 ) -> anyhow::Result<Vec<PackageSummary>> {
41 let mut pkgs: Vec<PackageSummary> = self
42 .find(&pkg_name.to_string())
43 .await?
44 .into_iter()
45 .filter(|it| {
46 if release_build_only {
47 return matches!(
48 it.release_kind.unwrap_or(ReleaseKind::PreRelease),
49 ReleaseKind::Release
50 );
51 }
52 true
53 })
54 .map(PackageSummary::from)
55 .collect();
56
57 pkgs.sort_by_version();
58 Ok(pkgs)
59 }
60}
61
62impl ServiceTrait for PackageService {}
63
64impl DependencyInjectTrait for PackageService {
65 fn inject(&mut self, container: Arc<DIContainer>) {
66 self.container = Some(container)
67 }
68}
69
70impl ItemOperationTrait for PackageService {
71 type Item = Package;
72 type ItemInstance = Package;
73 type Condition = String;
74
75 fn delete(&self, _name: &str) -> anyhow::Result<()> {
76 unimplemented!()
77 }
78
79 fn list(&self) -> anyhow::Result<Vec<Self::ItemInstance>> {
80 debug!("Getting all packages");
81
82 self.search(None, None, None, None)
83 }
84
85 fn get(&self, name: &str) -> anyhow::Result<Self::ItemInstance> {
86 debug!("Getting package: {}", name);
87
88 let results = self.search(Some(name), None, None, None)?;
89 if !results.is_empty() {
90 Ok(results.first().unwrap().to_owned())
91 } else {
92 Err(anyhow!(PackageNotFound(name.into())))
93 }
94 }
95}
96
97#[async_trait]
98impl ItemOperationAsyncTrait for PackageService {
99 type Item_ = Package;
100 type ItemInstance_ = Package;
101 type Condition_ = String;
102
103 async fn create(&self, _obj: Self::Item_) -> anyhow::Result<Self::ItemInstance_> {
104 unimplemented!()
105 }
106
107 async fn update(&self, _obj: &Self::Item_) -> anyhow::Result<Self::ItemInstance_> {
108 unimplemented!()
109 }
110
111 async fn find(&self, pkg_name: &Self::Condition_) -> anyhow::Result<Vec<Self::ItemInstance_>> {
112 debug!("Finding packages: {}", pkg_name);
113
114 let config = self.container.get::<Config>().unwrap();
115 let client = GithubClient::new(config.to_github_credentials(), config.to_github_key_path());
116 let pkg = self.get(pkg_name)?;
117
118 match &pkg.source {
119 PackageSource::Github { owner, repo } => {
120 let releases = client.get_releases(owner, repo, &pkg).await?;
121 Ok(releases
122 .into_iter()
123 .map(|it| {
124 let mut pkg = it.package;
125 pkg.version = Some(it.version);
126 pkg.release_kind = it.kind;
127
128 pkg
129 })
130 .collect())
131 }
132 }
133 }
134}
135
136impl ItemSearchTrait for PackageService {
137 type SearchItem = Package;
138
139 fn search(
140 &self,
141 name: Option<&str>,
142 pattern: Option<&str>,
143 owner: Option<&str>,
144 repo: Option<&str>,
145 ) -> anyhow::Result<Vec<Self::SearchItem>> {
146 let cache_service = self.container.get::<CacheService>().unwrap();
147
148 let owner = owner.unwrap_or("");
149 let mut found_items: Vec<Self::SearchItem> = vec![];
150
151 if let Some(pattern) = pattern {
152 debug!("Searching package by pattern: {}", pattern);
153
154 let mut found_pkgs = cache_service.list_packages(pattern, owner, repo)?;
155 found_items.append(&mut found_pkgs);
156
157 return Ok(found_items);
158 }
159
160 if let Some(name) = name {
161 debug!("Searching package by name: {}", name);
162
163 match cache_service.get_package(name, repo) {
164 Ok(pkg) => found_items.push(pkg),
165 Err(err) => debug!("{}", err),
166 }
167
168 return Ok(found_items);
169 }
170
171 debug!("Searching all packages");
172 let mut all_pkgs = cache_service.list_packages("", owner, repo)?;
173 found_items.append(&mut all_pkgs);
174
175 Ok(found_items)
176 }
177}