feat(package): implement espanso hub package index caching
This commit is contained in:
parent
23a73f7ea2
commit
bfb5a8ac4c
|
@ -32,11 +32,9 @@ mod util;
|
||||||
|
|
||||||
pub use archive::{ArchivedPackage, Archiver, SaveOptions, StoredPackage};
|
pub use archive::{ArchivedPackage, Archiver, SaveOptions, StoredPackage};
|
||||||
pub use package::Package;
|
pub use package::Package;
|
||||||
pub use provider::{PackageProvider, PackageSpecifier};
|
pub use provider::{PackageProvider, PackageSpecifier, ProviderOptions};
|
||||||
|
|
||||||
// TODO: once the download is completed, avoid copying files beginning with "."
|
pub fn get_provider(package: &PackageSpecifier, runtime_dir: &Path, options: &ProviderOptions) -> Result<Box<dyn PackageProvider>> {
|
||||||
|
|
||||||
pub fn get_provider(package: &PackageSpecifier,) -> Result<Box<dyn PackageProvider>> {
|
|
||||||
if let Some(git_repo_url) = package.git_repo_url.as_deref() {
|
if let Some(git_repo_url) = package.git_repo_url.as_deref() {
|
||||||
if !package.use_native_git {
|
if !package.use_native_git {
|
||||||
let matches_known_hosts =
|
let matches_known_hosts =
|
||||||
|
@ -76,7 +74,7 @@ pub fn get_provider(package: &PackageSpecifier,) -> Result<Box<dyn PackageProvid
|
||||||
Ok(Box::new(provider::git::GitPackageProvider::new()))
|
Ok(Box::new(provider::git::GitPackageProvider::new()))
|
||||||
} else {
|
} else {
|
||||||
// Download from the official espanso hub
|
// Download from the official espanso hub
|
||||||
Ok(Box::new(provider::hub::EspansoHubPackageProvider::new()))
|
Ok(Box::new(provider::hub::EspansoHubPackageProvider::new(runtime_dir, options.force_index_update)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,11 @@
|
||||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
time::UNIX_EPOCH,
|
||||||
|
};
|
||||||
|
|
||||||
use super::PackageProvider;
|
use super::PackageProvider;
|
||||||
use crate::{
|
use crate::{
|
||||||
package::DefaultPackage, resolver::resolve_package, util::download::read_string_from_url,
|
package::DefaultPackage, resolver::resolve_package, util::download::read_string_from_url,
|
||||||
|
@ -28,11 +33,20 @@ use serde::{Deserialize, Serialize};
|
||||||
pub const ESPANSO_HUB_PACKAGE_INDEX_URL: &str =
|
pub const ESPANSO_HUB_PACKAGE_INDEX_URL: &str =
|
||||||
"https://github.com/espanso/hub/releases/latest/download/package_index.json";
|
"https://github.com/espanso/hub/releases/latest/download/package_index.json";
|
||||||
|
|
||||||
pub struct EspansoHubPackageProvider {}
|
const PACKAGE_INDEX_CACHE_FILE: &str = "package_index_cache.json";
|
||||||
|
const PACKAGE_INDEX_CACHE_INVALIDATION_SECONDS: u64 = 60 * 60;
|
||||||
|
|
||||||
|
pub struct EspansoHubPackageProvider {
|
||||||
|
runtime_dir: PathBuf,
|
||||||
|
force_index_update: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl EspansoHubPackageProvider {
|
impl EspansoHubPackageProvider {
|
||||||
pub fn new() -> Self {
|
pub fn new(runtime_dir: &Path, force_index_update: bool) -> Self {
|
||||||
Self {}
|
Self {
|
||||||
|
runtime_dir: runtime_dir.to_path_buf(),
|
||||||
|
force_index_update,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,9 +56,8 @@ impl PackageProvider for EspansoHubPackageProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn download(&self, package: &PackageSpecifier) -> Result<Box<dyn Package>> {
|
fn download(&self, package: &PackageSpecifier) -> Result<Box<dyn Package>> {
|
||||||
// TODO: pass index update flag
|
|
||||||
let index = self
|
let index = self
|
||||||
.get_index(true)
|
.get_index(self.force_index_update)
|
||||||
.context("unable to get package index from espanso hub")?;
|
.context("unable to get package index from espanso hub")?;
|
||||||
|
|
||||||
let package_info = index
|
let package_info = index
|
||||||
|
@ -82,9 +95,23 @@ impl PackageProvider for EspansoHubPackageProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EspansoHubPackageProvider {
|
impl EspansoHubPackageProvider {
|
||||||
fn get_index(&self, _force_update: bool) -> Result<PackageIndex> {
|
fn get_index(&self, force_update: bool) -> Result<PackageIndex> {
|
||||||
// TODO: if force_update is false, we should try to use a locally-cached version of the package index
|
let old_index = self.get_index_from_cache()?;
|
||||||
self.download_index()
|
|
||||||
|
if let Some(old_index) = old_index {
|
||||||
|
if !force_update {
|
||||||
|
let current_time = std::time::SystemTime::now().duration_since(UNIX_EPOCH)?;
|
||||||
|
let current_unix = current_time.as_secs();
|
||||||
|
if old_index.cached_at >= (current_unix - PACKAGE_INDEX_CACHE_INVALIDATION_SECONDS) {
|
||||||
|
info_println!("using cached package index");
|
||||||
|
return Ok(old_index.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_index = self.download_index()?;
|
||||||
|
self.save_index_to_cache(new_index.clone())?;
|
||||||
|
Ok(new_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn download_index(&self) -> Result<PackageIndex> {
|
fn download_index(&self) -> Result<PackageIndex> {
|
||||||
|
@ -95,9 +122,40 @@ impl EspansoHubPackageProvider {
|
||||||
|
|
||||||
Ok(index)
|
Ok(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_index_from_cache(&self) -> Result<Option<CachedPackageIndex>> {
|
||||||
|
let target_file = self.runtime_dir.join(PACKAGE_INDEX_CACHE_FILE);
|
||||||
|
if !target_file.is_file() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let content =
|
||||||
|
std::fs::read_to_string(&target_file).context("unable to read package index cache")?;
|
||||||
|
let index: CachedPackageIndex = serde_json::from_str(&content)?;
|
||||||
|
Ok(Some(index))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_index_to_cache(&self, index: PackageIndex) -> Result<()> {
|
||||||
|
let target_file = self.runtime_dir.join(PACKAGE_INDEX_CACHE_FILE);
|
||||||
|
let current_time = std::time::SystemTime::now().duration_since(UNIX_EPOCH)?;
|
||||||
|
let current_unix = current_time.as_secs();
|
||||||
|
let cached_index = CachedPackageIndex {
|
||||||
|
cached_at: current_unix,
|
||||||
|
index,
|
||||||
|
};
|
||||||
|
let serialized = serde_json::to_string(&cached_index)?;
|
||||||
|
std::fs::write(&target_file, serialized)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct CachedPackageIndex {
|
||||||
|
cached_at: u64,
|
||||||
|
index: PackageIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
struct PackageIndex {
|
struct PackageIndex {
|
||||||
last_update: u64,
|
last_update: u64,
|
||||||
packages: Vec<PackageInfo>,
|
packages: Vec<PackageInfo>,
|
||||||
|
@ -134,4 +192,4 @@ impl PackageIndex {
|
||||||
matching_packages.into_iter().last()
|
matching_packages.into_iter().last()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,3 +44,7 @@ pub trait PackageProvider {
|
||||||
// TODO: fn check update available? (probably should be only available in the hub)
|
// TODO: fn check update available? (probably should be only available in the hub)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct ProviderOptions {
|
||||||
|
pub force_index_update: bool,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user