mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 08:26:44 +08:00
feat: prepare experiment push package
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
//! Official JP resource pull planning.
|
||||
|
||||
use bat_adapters::official::inventory::{
|
||||
YostarJpDownloadInventory, YostarJpPlatformDownloadInventory,
|
||||
};
|
||||
use bat_adapters::official::yostar_jp::{
|
||||
verified_official_platforms, PatchPlatform, YostarJpResourceDiscoveryPlan, YostarJpResourceRoot,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
|
||||
/// Full official JP pull plan, covering discovery endpoints and concrete
|
||||
/// resource downloads.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct OfficialResourcePullPlan {
|
||||
/// Seed URLs and selected root from server-info.
|
||||
pub discovery: YostarJpResourceDiscoveryPlan,
|
||||
/// Concrete file inventory extracted from the catalog bytes.
|
||||
pub inventory: YostarJpPlatformDownloadInventory,
|
||||
/// Platforms that will be pulled.
|
||||
pub platforms: Vec<PatchPlatform>,
|
||||
}
|
||||
|
||||
impl OfficialResourcePullPlan {
|
||||
/// Creates a pull plan for the requested platforms.
|
||||
pub fn new(
|
||||
discovery: YostarJpResourceDiscoveryPlan,
|
||||
inventory: YostarJpDownloadInventory,
|
||||
platforms: &[PatchPlatform],
|
||||
) -> Self {
|
||||
Self::new_platform_inventory(
|
||||
discovery,
|
||||
YostarJpPlatformDownloadInventory::from_shared_inventory(inventory, platforms),
|
||||
platforms,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a pull plan for the requested platforms using platform-specific
|
||||
/// bundle/media catalogs.
|
||||
pub fn new_platform_inventory(
|
||||
discovery: YostarJpResourceDiscoveryPlan,
|
||||
inventory: YostarJpPlatformDownloadInventory,
|
||||
platforms: &[PatchPlatform],
|
||||
) -> Self {
|
||||
Self {
|
||||
discovery,
|
||||
inventory,
|
||||
platforms: unique_platforms(platforms),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a pull plan for the verified official JP platforms.
|
||||
pub fn verified(
|
||||
discovery: YostarJpResourceDiscoveryPlan,
|
||||
inventory: YostarJpDownloadInventory,
|
||||
) -> Self {
|
||||
Self::new(discovery, inventory, &verified_official_platforms())
|
||||
}
|
||||
|
||||
/// Creates a pull plan for the verified official JP platforms using
|
||||
/// platform-specific bundle/media catalogs.
|
||||
pub fn verified_platform_inventory(
|
||||
discovery: YostarJpResourceDiscoveryPlan,
|
||||
inventory: YostarJpPlatformDownloadInventory,
|
||||
) -> Self {
|
||||
Self::new_platform_inventory(discovery, inventory, &verified_official_platforms())
|
||||
}
|
||||
|
||||
/// Returns all discovery URLs in server-provided order.
|
||||
pub fn discovery_urls(&self) -> Vec<String> {
|
||||
self.discovery
|
||||
.endpoints
|
||||
.iter()
|
||||
.map(|endpoint| endpoint.url.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Returns the validated official resource root used by the pull plan.
|
||||
pub fn resource_root(&self) -> Result<YostarJpResourceRoot, String> {
|
||||
YostarJpResourceRoot::from_addressables_root(&self.discovery.addressables_root)
|
||||
}
|
||||
|
||||
/// Returns all concrete download URLs for the selected platforms.
|
||||
pub fn content_urls(&self) -> Result<Vec<String>, String> {
|
||||
let root = self.resource_root()?;
|
||||
self.inventory
|
||||
.direct_download_urls_for_platforms(&root, &self.platforms)
|
||||
}
|
||||
|
||||
/// Returns discovery URLs followed by concrete content URLs.
|
||||
pub fn all_urls(&self) -> Result<Vec<String>, String> {
|
||||
let mut urls = self.discovery_urls();
|
||||
let mut seen = urls.iter().cloned().collect::<HashSet<_>>();
|
||||
|
||||
for url in self.content_urls()? {
|
||||
if seen.insert(url.clone()) {
|
||||
urls.push(url);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(urls)
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a pull plan for the verified official JP platforms.
|
||||
pub fn build_official_pull_plan(
|
||||
discovery: YostarJpResourceDiscoveryPlan,
|
||||
inventory: YostarJpDownloadInventory,
|
||||
) -> OfficialResourcePullPlan {
|
||||
OfficialResourcePullPlan::verified(discovery, inventory)
|
||||
}
|
||||
|
||||
/// Builds a pull plan for the verified official JP platforms using
|
||||
/// platform-specific bundle/media catalogs.
|
||||
pub fn build_official_pull_plan_from_platform_inventory(
|
||||
discovery: YostarJpResourceDiscoveryPlan,
|
||||
inventory: YostarJpPlatformDownloadInventory,
|
||||
) -> OfficialResourcePullPlan {
|
||||
OfficialResourcePullPlan::verified_platform_inventory(discovery, inventory)
|
||||
}
|
||||
|
||||
/// Builds a pull plan for the requested platforms.
|
||||
pub fn build_official_pull_plan_for_platforms(
|
||||
discovery: YostarJpResourceDiscoveryPlan,
|
||||
inventory: YostarJpDownloadInventory,
|
||||
platforms: &[PatchPlatform],
|
||||
) -> OfficialResourcePullPlan {
|
||||
OfficialResourcePullPlan::new(discovery, inventory, platforms)
|
||||
}
|
||||
|
||||
/// Builds a pull plan for the requested platforms using platform-specific
|
||||
/// bundle/media catalogs.
|
||||
pub fn build_official_pull_plan_for_platform_inventory(
|
||||
discovery: YostarJpResourceDiscoveryPlan,
|
||||
inventory: YostarJpPlatformDownloadInventory,
|
||||
platforms: &[PatchPlatform],
|
||||
) -> OfficialResourcePullPlan {
|
||||
OfficialResourcePullPlan::new_platform_inventory(discovery, inventory, platforms)
|
||||
}
|
||||
|
||||
fn unique_platforms(platforms: &[PatchPlatform]) -> Vec<PatchPlatform> {
|
||||
platforms
|
||||
.iter()
|
||||
.copied()
|
||||
.fold(Vec::new(), |mut unique, platform| {
|
||||
if !unique.contains(&platform) {
|
||||
unique.push(platform);
|
||||
}
|
||||
unique
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use bat_adapters::official::inventory::{
|
||||
YostarJpDownloadInventory, YostarJpPlatformCatalogInventory,
|
||||
YostarJpPlatformDownloadInventory,
|
||||
};
|
||||
use bat_adapters::official::yostar_jp::{
|
||||
YostarJpResourceEndpoint, YostarJpResourceEndpointKind,
|
||||
};
|
||||
|
||||
fn discovery_plan() -> YostarJpResourceDiscoveryPlan {
|
||||
YostarJpResourceDiscoveryPlan {
|
||||
connection_group_name: "Prod-Audit".to_string(),
|
||||
app_version: "1.70.0".to_string(),
|
||||
bundle_version: Some("s8tloc7lo3".to_string()),
|
||||
addressables_root:
|
||||
"https://prod-clientpatch.bluearchiveyostar.com/r93_token".to_string(),
|
||||
endpoints: vec![
|
||||
YostarJpResourceEndpoint {
|
||||
kind: YostarJpResourceEndpointKind::TableCatalog,
|
||||
platform: None,
|
||||
url: "https://prod-clientpatch.bluearchiveyostar.com/r93_token/TableBundles/TableCatalog.bytes".to_string(),
|
||||
},
|
||||
YostarJpResourceEndpoint {
|
||||
kind: YostarJpResourceEndpointKind::TableCatalogHash,
|
||||
platform: None,
|
||||
url: "https://prod-clientpatch.bluearchiveyostar.com/r93_token/TableBundles/TableCatalog.hash".to_string(),
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn inventory() -> YostarJpDownloadInventory {
|
||||
YostarJpDownloadInventory::from_catalog_bytes(
|
||||
b"FullPatch_000.zip",
|
||||
b"ExcelDB.db",
|
||||
b"JP_Airi.zip",
|
||||
)
|
||||
}
|
||||
|
||||
fn platform_inventory() -> YostarJpPlatformDownloadInventory {
|
||||
YostarJpPlatformDownloadInventory::from_catalog_bytes(
|
||||
b"ExcelDB.db",
|
||||
vec![
|
||||
YostarJpPlatformCatalogInventory::from_catalog_bytes(
|
||||
PatchPlatform::Windows,
|
||||
b"FullPatch_000.zip",
|
||||
b"JP_Airi_Win.zip",
|
||||
),
|
||||
YostarJpPlatformCatalogInventory::from_catalog_bytes(
|
||||
PatchPlatform::Android,
|
||||
b"FullPatch_001.zip",
|
||||
b"JP_Airi_Android.zip",
|
||||
),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_verified_pull_plan_with_all_urls() {
|
||||
let plan = build_official_pull_plan(discovery_plan(), inventory());
|
||||
|
||||
assert_eq!(plan.platforms, verified_official_platforms());
|
||||
assert_eq!(plan.discovery_urls().len(), 2);
|
||||
|
||||
let content_urls = plan.content_urls().unwrap();
|
||||
assert!(content_urls
|
||||
.iter()
|
||||
.any(|url| url.contains("/Windows_PatchPack/FullPatch_000.zip")));
|
||||
assert!(content_urls
|
||||
.iter()
|
||||
.any(|url| url.contains("/Android_PatchPack/FullPatch_000.zip")));
|
||||
assert_eq!(content_urls.len(), 5);
|
||||
|
||||
let all_urls = plan.all_urls().unwrap();
|
||||
assert_eq!(all_urls.len(), 7);
|
||||
assert!(all_urls[0].ends_with("TableCatalog.bytes"));
|
||||
assert!(all_urls
|
||||
.iter()
|
||||
.any(|url| url.ends_with("/MediaResources-Windows/JP_Airi.zip")));
|
||||
assert_eq!(
|
||||
all_urls
|
||||
.iter()
|
||||
.filter(|url| url.ends_with("/MediaResources/JP_Airi.zip"))
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deduplicates_requested_platforms() {
|
||||
let plan = build_official_pull_plan_for_platforms(
|
||||
discovery_plan(),
|
||||
inventory(),
|
||||
&[PatchPlatform::Windows, PatchPlatform::Windows],
|
||||
);
|
||||
|
||||
assert_eq!(plan.platforms, vec![PatchPlatform::Windows]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verified_pull_plan_is_windows_and_android_only() {
|
||||
let plan = build_official_pull_plan(discovery_plan(), inventory());
|
||||
|
||||
assert_eq!(
|
||||
plan.platforms,
|
||||
vec![PatchPlatform::Windows, PatchPlatform::Android]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_platform_inventory_pull_plan_without_cross_mixing_catalogs() {
|
||||
let plan = build_official_pull_plan_from_platform_inventory(
|
||||
discovery_plan(),
|
||||
platform_inventory(),
|
||||
);
|
||||
|
||||
let all_urls = plan.all_urls().unwrap();
|
||||
|
||||
assert_eq!(plan.platforms, verified_official_platforms());
|
||||
assert_eq!(all_urls.len(), 7);
|
||||
assert!(all_urls
|
||||
.iter()
|
||||
.any(|url| url.ends_with("/Windows_PatchPack/FullPatch_000.zip")));
|
||||
assert!(all_urls
|
||||
.iter()
|
||||
.any(|url| url.ends_with("/Android_PatchPack/FullPatch_001.zip")));
|
||||
assert!(!all_urls
|
||||
.iter()
|
||||
.any(|url| url.ends_with("/Android_PatchPack/FullPatch_000.zip")));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user