Skip to main content

huber/service/
package.rs

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}