feat:移除了弹窗,服务器添加sls

This commit is contained in:
AxTps committed 2026-09-08 22:39:45 +08:00
commit 6a295f9a7a
4082 files changed
+1322534

No files matched your search

@@ -0,0 +1,193 @@
//! Logical stream budgets for shared native HTTP/2 connections.
//!
//! HTTP/2 streams share one physical connection per authority, so they must
//! not consume the HTTP/1 connection permits held by `native_budget`.
use crate::util::fetch::{DownloadRoute, ProxyPolicy};
use parking_lot::Mutex;
use std::collections::HashMap;
use std::sync::{Arc, LazyLock};
use tokio::sync::{AcquireError, OwnedSemaphorePermit, Semaphore};
use tokio::time::{Duration, sleep};
const MAX_H2_STREAMS: usize = 128;
const MAX_H2_STREAMS_PER_AUTHORITY: usize = 32;
const MAX_ASSET_H2_STREAMS: usize = 96;
const MAX_ASSET_H2_STREAMS_PER_AUTHORITY: usize = 24;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
struct AuthorityKey {
authority: String,
proxy: ProxyPolicy,
}
static AUTHORITY_BUDGETS: LazyLock<
Mutex<HashMap<AuthorityKey, Arc<Semaphore>>>,
> = LazyLock::new(|| Mutex::new(HashMap::new()));
static GLOBAL_BUDGET: LazyLock<Arc<Semaphore>> =
LazyLock::new(|| Arc::new(Semaphore::new(MAX_H2_STREAMS)));
static ASSET_AUTHORITY_BUDGETS: LazyLock<
Mutex<HashMap<AuthorityKey, Arc<Semaphore>>>,
> = LazyLock::new(|| Mutex::new(HashMap::new()));
static ASSET_GLOBAL_BUDGET: LazyLock<Arc<Semaphore>> =
LazyLock::new(|| Arc::new(Semaphore::new(MAX_ASSET_H2_STREAMS)));
pub(crate) struct H2StreamPermit {
_global: OwnedSemaphorePermit,
_authority: Option<OwnedSemaphorePermit>,
}
fn budget(route: &DownloadRoute) -> Option<Arc<Semaphore>> {
let authority = crate::util::fetch::url_authority(&route.url)?;
let key = AuthorityKey {
authority,
proxy: route.proxy,
};
let mut budgets = AUTHORITY_BUDGETS.lock();
if budgets.len() >= 256 {
budgets.retain(|_, budget| Arc::strong_count(budget) > 1);
}
Some(
budgets
.entry(key)
.or_insert_with(|| {
Arc::new(Semaphore::new(MAX_H2_STREAMS_PER_AUTHORITY))
})
.clone(),
)
}
fn asset_budget(route: &DownloadRoute) -> Option<Arc<Semaphore>> {
let authority = crate::util::fetch::url_authority(&route.url)?;
let key = AuthorityKey {
authority,
proxy: route.proxy,
};
let mut budgets = ASSET_AUTHORITY_BUDGETS.lock();
if budgets.len() >= 256 {
budgets.retain(|_, budget| Arc::strong_count(budget) > 1);
}
Some(
budgets
.entry(key)
.or_insert_with(|| {
Arc::new(Semaphore::new(MAX_ASSET_H2_STREAMS_PER_AUTHORITY))
})
.clone(),
)
}
pub(crate) async fn acquire(
route: &DownloadRoute,
) -> Result<H2StreamPermit, AcquireError> {
let authority_budget = budget(route);
loop {
let global = Arc::clone(&GLOBAL_BUDGET).acquire_owned().await?;
let authority = match authority_budget.as_ref() {
Some(budget) => match Arc::clone(budget).try_acquire_owned() {
Ok(permit) => Some(permit),
Err(tokio::sync::TryAcquireError::NoPermits) => {
drop(global);
sleep(Duration::from_millis(5)).await;
continue;
}
Err(tokio::sync::TryAcquireError::Closed) => {
unreachable!("H2 authority budgets are never closed")
}
},
None => None,
};
return Ok(H2StreamPermit {
_global: global,
_authority: authority,
});
}
}
/// Acquires a stream for the Minecraft asset batch. Assets retain a large
/// logical worker window, but use a separate physical stream pool so they
/// cannot consume the ordinary native content share.
pub(crate) async fn acquire_asset(
route: &DownloadRoute,
) -> Result<H2StreamPermit, AcquireError> {
let authority_budget = asset_budget(route);
loop {
let global = Arc::clone(&ASSET_GLOBAL_BUDGET).acquire_owned().await?;
let authority = match authority_budget.as_ref() {
Some(budget) => match Arc::clone(budget).try_acquire_owned() {
Ok(permit) => Some(permit),
Err(tokio::sync::TryAcquireError::NoPermits) => {
drop(global);
sleep(Duration::from_millis(5)).await;
continue;
}
Err(tokio::sync::TryAcquireError::Closed) => {
unreachable!("asset authority budgets are never closed")
}
},
None => None,
};
return Ok(H2StreamPermit {
_global: global,
_authority: authority,
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::util::fetch::DownloadRouteSource;
fn route() -> DownloadRoute {
DownloadRoute {
url: "https://h2-budget.example/file".to_string(),
source: DownloadRouteSource::Official,
is_mirror: false,
allow_sensitive_headers: true,
supports_range: true,
proxy: ProxyPolicy::Direct,
}
}
#[tokio::test]
async fn authority_stream_budget_is_independent_from_connection_budget() {
let route = route();
let mut permits = Vec::new();
for _ in 0..MAX_H2_STREAMS_PER_AUTHORITY {
permits.push(acquire(&route).await.unwrap());
}
assert_eq!(budget(&route).unwrap().available_permits(), 0,);
drop(permits);
assert_eq!(
budget(&route).unwrap().available_permits(),
MAX_H2_STREAMS_PER_AUTHORITY,
);
}
#[tokio::test]
async fn asset_stream_budget_is_separate_and_bounded() {
let route = DownloadRoute {
url: "https://asset-h2-budget.example/file".to_string(),
source: DownloadRouteSource::Bmclapi,
is_mirror: true,
allow_sensitive_headers: false,
supports_range: true,
proxy: ProxyPolicy::Direct,
};
let mut permits = Vec::new();
for _ in 0..MAX_ASSET_H2_STREAMS_PER_AUTHORITY {
permits.push(acquire_asset(&route).await.unwrap());
}
assert_eq!(asset_budget(&route).unwrap().available_permits(), 0,);
drop(permits);
assert_eq!(
asset_budget(&route).unwrap().available_permits(),
MAX_ASSET_H2_STREAMS_PER_AUTHORITY,
);
assert_eq!(
budget(&route).unwrap().available_permits(),
MAX_H2_STREAMS_PER_AUTHORITY
);
}
}