use gloo::net::http; use thiserror::Error; use time::{format_description::well_known::Rfc3339, OffsetDateTime}; const GITHUB_API: &str = "https://api.github.com"; pub async fn github_fetch_last_updated( owner: &str, repo: &str, path: &str, ) -> Result<OffsetDateTime, GithubError> { let commit: Vec<serde_json::Value> = http::Request::get(&format!( "{GITHUB_API}/repos/{owner}/{repo}/commits?path={path}&page=1&per_page=1" )) .send() .await? .json() .await?; commit[0] .get("commit") .and_then(|commit| commit.get("committer")) .and_then(|committer| committer.get("date")) .map(|date| { OffsetDateTime::parse( date.as_str().ok_or(GithubError::MissingCommitDateError)?, &Rfc3339, ) .map_err(|err| err.into()) }) .unwrap_or(Err(GithubError::MissingCommitDateError)) } pub async fn github_fetch_file( owner: &str, repo: &str, path: &str, ) -> Result<Vec<u8>, GithubError> { http::Request::get(&format!( "{GITHUB_API}/repos/{owner}/{repo}/contents/{path}" )) .header("Accept", "application/vnd.github.raw+json") .send() .await? .binary() .await .map_err(|err| err.into()) } #[derive(Debug, Error)] pub enum GithubError { #[error("no file returned from the given GitHub API")] NoSuchFile, #[error("failed to fetch from GitHub API")] RequestError(#[from] gloo::net::Error), #[error("file fetched from the GitHub API does not have a commit date")] MissingCommitDateError, #[error("date/time format reported for GitHub commit is invalid")] InvalidDateTimeError(#[from] time::error::Parse), }