This repository has been archived on 2025-01-27. You can view files and clone it, but cannot push or open issues or pull requests.
puyoskey-firefish/packages/backend-rs/src/misc/latest_version.rs
HidemaruOwO 41186813ed ♻️ Refer develop version firefish (Cargo.lock, Cargo.toml, locales/ca-ES.yml, package.json, packages/backend-rs/src/cache/redis.rs, packages/backend-rs/src/database/redis.rs, packages/backend-rs/src/federation/activitypub/object/follow.rs, packages/backend-rs/src/federation/activitypub/object/like.rs, packages/backend-rs/src/federation/activitypub/object/relay.rs, packages/backend-rs/src/federation/internal_actor/instance.rs, packages/backend-rs/src/federation/internal_actor/relay.rs, packages/backend-rs/src/federation/nodeinfo/fetch.rs, packages/backend-rs/src/federation/nodeinfo/generate.rs, packages/backend-rs/src/misc/convert_host.rs, packages/backend-rs/src/misc/emoji.rs, packages/backend-rs/src/misc/emoji/reaction.rs, packages/backend-rs/src/misc/get_image_size.rs, packages/backend-rs/src/misc/latest_version.rs, packages/backend-rs/src/misc/password.rs, packages/backend-rs/src/misc/random_icon.rs, packages/backend-rs/src/misc/should_nyaify.rs, packages/backend-rs/src/misc/translate.rs, packages/backend-rs/src/service/antenna/check_hit.rs, packages/backend-rs/src/service/antenna/process_new_note.rs, packages/backend-rs/src/service/push_notification.rs, packages/backend-rs/src/service/stream.rs, packages/backend-rs/src/util/error_chain.rs, packages/backend-rs/src/util/http_client.rs, packages/backend/assets/resource-unknown.svg, packages/backend/package.json, packages/client/package.json, packages/client/src/components/MkInstanceCardMini.vue, packages/client/src/components/MkInstanceTicker.vue, packages/client/src/components/MkUrlPreview.vue, packages/client/src/ui/_common_/statusbar-federation.vue, packages/client/src/widgets/federation.vue, packages/client/src/widgets/instance-cloud.vue, packages/firefish-js/package.json, packages/macro-rs/macros-impl/Cargo.toml, packages/macro-rs/macros-impl/src/lib.rs, packages/macro-rs/macros-impl/src/napi.rs, packages/macro-rs/macros/src/lib.rs, packages/sw/package.json, pnpm-lock.yaml)
2024-08-24 09:40:20 +09:00

108 lines
3.2 KiB
Rust

//! Fetch latest Firefish version from the Firefish repository
use crate::{cache::Cache, util::http_client};
use chrono::Duration;
use futures_util::AsyncReadExt;
use isahc::AsyncReadResponseExt;
use serde::Deserialize;
#[error_doc::errors]
pub enum Error {
#[error("HTTP request failed")]
Isahc(#[from] isahc::Error),
#[error("failed to acquire an HTTP client")]
HttpClient(#[from] http_client::Error),
#[doc = "firefish.dev returned bad HTTP status"]
#[error("firefish.dev returned bad HTTP status ({0})")]
BadStatus(String),
#[error("failed to parse the HTTP response")]
Io(#[from] std::io::Error),
#[error("failed to parse the HTTP response as JSON")]
Json(#[from] serde_json::Error),
}
#[derive(Clone, Deserialize)]
struct PackageJson {
version: String,
}
const UPSTREAM_PACKAGE_JSON_URL: &str =
"https://firefish.dev/firefish/firefish/-/raw/main/package.json";
static PACKAGE_JSON_CACHE: Cache<PackageJson> = Cache::new_with_ttl(Duration::hours(3));
async fn get_package_json() -> Result<PackageJson, Error> {
// Read up to 1 MiB of the response body
let mut response = http_client::client()?
.get_async(UPSTREAM_PACKAGE_JSON_URL)
.await?
.map(|body| body.take(1024 * 1024));
if !response.status().is_success() {
tracing::info!("status: {}", response.status());
return Err(Error::BadStatus(response.status().to_string()));
}
let package_json: PackageJson = serde_json::from_str(&response.text().await?)?;
Ok(package_json)
}
/// Returns the latest Firefish version.
#[macros::export]
pub async fn latest_version() -> Result<String, Error> {
if let Some(package_json) = PACKAGE_JSON_CACHE.get() {
tracing::trace!("use cached value: {}", package_json.version);
Ok(package_json.version)
} else {
tracing::trace!("cache is expired, fetching the latest version");
let package_json = get_package_json().await?;
tracing::trace!("fetched value: {}", package_json.version);
PACKAGE_JSON_CACHE.set(package_json.clone());
Ok(package_json.version)
}
}
#[cfg(test)]
mod unit_test {
use super::latest_version;
use pretty_assertions::assert_eq;
fn validate_version(version: &str) {
// version: YYYYMMDD or YYYYMMDD-X
assert!(version.len() >= 8);
assert!(version[..8].chars().all(|c| c.is_ascii_digit()));
// YYYY
assert!(&version[..4] >= "2024");
// MM
assert!(&version[4..6] >= "01");
assert!(&version[4..6] <= "12");
// DD
assert!(&version[6..8] >= "01");
assert!(&version[6..8] <= "31");
// -X
if version.len() > 8 {
assert!(version.chars().nth(8).unwrap() == '-');
assert!(version[9..].chars().all(|c| c.is_ascii_digit()));
}
}
#[tokio::test]
#[cfg_attr(miri, ignore)] // can't call foreign function `getaddrinfo` on OS `linux`
async fn get_latest_version() {
// fetch from firefish.dev
let version_1 = latest_version().await.unwrap();
validate_version(&version_1);
// use cache
let version_2 = latest_version().await.unwrap();
validate_version(&version_2);
assert_eq!(version_1, version_2);
}
}