mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 04:55:42 +09:00
fix(ci): stop verifying published assets against the CDN (#2738)
This commit is contained in:
1 parent
7375ac9d80
commit
7d34d25497
1 file changed
+1
-94
@@ -12,17 +12,11 @@ use base64::Engine;
|
|||||||
use base64::engine::general_purpose::STANDARD as BASE64;
|
use base64::engine::general_purpose::STANDARD as BASE64;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use clap::{Args, ValueEnum};
|
use clap::{Args, ValueEnum};
|
||||||
use reqwest::Client;
|
|
||||||
use serde_json::{Map, Value, json};
|
use serde_json::{Map, Value, json};
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
|
||||||
use tokio::sync::Semaphore;
|
|
||||||
use tokio::task::JoinSet;
|
|
||||||
use tokio::time::sleep;
|
|
||||||
|
|
||||||
const DEFAULT_PUBLIC_ASSET_BASE_URL: &str = "https://fluxerstatic.com";
|
const DEFAULT_PUBLIC_ASSET_BASE_URL: &str = "https://fluxerstatic.com";
|
||||||
const DEFAULT_APP_PROXY_TIME_FREEZE_ENABLED: &str = "true";
|
const DEFAULT_APP_PROXY_TIME_FREEZE_ENABLED: &str = "true";
|
||||||
@@ -35,10 +29,6 @@ const CANONICAL_ASSETS_DIR: &str = "/assets";
|
|||||||
const AMD64_PLATFORM: &str = "linux/amd64";
|
const AMD64_PLATFORM: &str = "linux/amd64";
|
||||||
const ARM64_PLATFORM: &str = "linux/arm64";
|
const ARM64_PLATFORM: &str = "linux/arm64";
|
||||||
const PARITY_DIFF_LIMIT: usize = 20;
|
const PARITY_DIFF_LIMIT: usize = 20;
|
||||||
const ASSET_READ_CONCURRENCY: usize = 16;
|
|
||||||
const ASSET_READ_ATTEMPTS: u32 = 3;
|
|
||||||
const ASSET_READ_RETRY_DELAY: Duration = Duration::from_secs(2);
|
|
||||||
const ASSET_READ_TIMEOUT: Duration = Duration::from_secs(30);
|
|
||||||
|
|
||||||
#[derive(Debug, Args, Clone)]
|
#[derive(Debug, Args, Clone)]
|
||||||
pub struct BuildAppProxyArgs {
|
pub struct BuildAppProxyArgs {
|
||||||
@@ -365,10 +355,7 @@ async fn verify_published_assets_step() -> Result<()> {
|
|||||||
unproduced.join(", ")
|
unproduced.join(", ")
|
||||||
);
|
);
|
||||||
|
|
||||||
match env_string("PUBLIC_ASSET_BASE_URL") {
|
verify_local_assets(&dist, &assets)
|
||||||
Some(base) => verify_remote_assets(&base, &assets).await,
|
|
||||||
None => verify_local_assets(&dist, &assets),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_local_assets(dist: &Path, assets: &[String]) -> Result<()> {
|
fn verify_local_assets(dist: &Path, assets: &[String]) -> Result<()> {
|
||||||
@@ -391,74 +378,6 @@ fn verify_local_assets(dist: &Path, assets: &[String]) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn verify_remote_assets(base: &str, assets: &[String]) -> Result<()> {
|
|
||||||
let client = Client::builder()
|
|
||||||
.timeout(ASSET_READ_TIMEOUT)
|
|
||||||
.build()
|
|
||||||
.context("Failed to build the asset verification HTTP client")?;
|
|
||||||
let semaphore = Arc::new(Semaphore::new(ASSET_READ_CONCURRENCY));
|
|
||||||
let mut tasks = JoinSet::new();
|
|
||||||
for asset in assets {
|
|
||||||
let permit = semaphore
|
|
||||||
.clone()
|
|
||||||
.acquire_owned()
|
|
||||||
.await
|
|
||||||
.context("Asset verification semaphore closed")?;
|
|
||||||
let client = client.clone();
|
|
||||||
let url = asset_url(base, asset);
|
|
||||||
let asset = asset.clone();
|
|
||||||
tasks.spawn(async move {
|
|
||||||
let _permit = permit;
|
|
||||||
read_published_asset(&client, &url)
|
|
||||||
.await
|
|
||||||
.err()
|
|
||||||
.map(|error| format!("{asset}: {error}"))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut failures = Vec::new();
|
|
||||||
while let Some(result) = tasks.join_next().await {
|
|
||||||
if let Some(failure) = result.context("Asset verification task failed")? {
|
|
||||||
failures.push(failure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
failures.sort();
|
|
||||||
ensure!(
|
|
||||||
failures.is_empty(),
|
|
||||||
"{} of {} published assets are not readable at {base}:\n{}",
|
|
||||||
failures.len(),
|
|
||||||
assets.len(),
|
|
||||||
failures.join("\n")
|
|
||||||
);
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"published asset verification passed - {} assets readable at {base}",
|
|
||||||
assets.len()
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn read_published_asset(client: &Client, url: &str) -> Result<()> {
|
|
||||||
let mut last_error = None;
|
|
||||||
for attempt in 1..=ASSET_READ_ATTEMPTS {
|
|
||||||
match client.get(url).header("range", "bytes=0-0").send().await {
|
|
||||||
Ok(response) if response.status().is_success() => return Ok(()),
|
|
||||||
Ok(response) => {
|
|
||||||
last_error = Some(anyhow!("{url} responded {}", response.status()));
|
|
||||||
}
|
|
||||||
Err(error) => last_error = Some(anyhow!("{url} request failed: {error}")),
|
|
||||||
}
|
|
||||||
if attempt < ASSET_READ_ATTEMPTS {
|
|
||||||
sleep(ASSET_READ_RETRY_DELAY).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(last_error.unwrap_or_else(|| anyhow!("{url} could not be read")))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn asset_url(base: &str, key: &str) -> String {
|
|
||||||
format!("{}/{}", base.trim_end_matches('/'), key)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn referenced_assets(source: &str) -> Vec<String> {
|
fn referenced_assets(source: &str) -> Vec<String> {
|
||||||
const PREFIX: &str = "assets/";
|
const PREFIX: &str = "assets/";
|
||||||
let bytes = source.as_bytes();
|
let bytes = source.as_bytes();
|
||||||
@@ -1018,18 +937,6 @@ mod tests {
|
|||||||
assert_eq!(digests["index.html"], changed["index.html"]);
|
assert_eq!(digests["index.html"], changed["index.html"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn asset_url_joins_the_base_and_key_once() {
|
|
||||||
assert_eq!(
|
|
||||||
asset_url("https://fluxerstatic.com", "assets/a.js"),
|
|
||||||
"https://fluxerstatic.com/assets/a.js"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
asset_url("https://fluxerstatic.com/", "assets/a.js"),
|
|
||||||
"https://fluxerstatic.com/assets/a.js"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assets_image_ref_names_the_canonical_image() {
|
fn assets_image_ref_names_the_canonical_image() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in new issue
Block a user