feat:移除了弹窗,服务器添加sls
This commit is contained in:
169
packages/app-lib/src/state/minecraft_skins/mojang_api.rs
Normal file
169
packages/app-lib/src/state/minecraft_skins/mojang_api.rs
Normal file
@ -0,0 +1,169 @@
|
||||
use std::{error::Error, sync::Arc, time::Instant};
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures::TryStream;
|
||||
use reqwest::{Body, multipart::Part};
|
||||
use serde_json::json;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::MinecraftSkinVariant;
|
||||
use crate::{
|
||||
ErrorKind,
|
||||
data::Credentials,
|
||||
state::{
|
||||
MINECRAFT_SERVICES_USER_AGENT, MinecraftProfile, PROFILE_CACHE,
|
||||
ProfileCacheEntry,
|
||||
},
|
||||
util::fetch::INSECURE_REQWEST_CLIENT,
|
||||
util::mojang::{mojang_service_url, should_use_mojang_mirror},
|
||||
};
|
||||
|
||||
/// Provides operations for interacting with capes on a Minecraft player profile.
|
||||
pub struct MinecraftCapeOperation;
|
||||
|
||||
impl MinecraftCapeOperation {
|
||||
pub async fn equip(
|
||||
credentials: &Credentials,
|
||||
cape_id: Uuid,
|
||||
) -> crate::Result<()> {
|
||||
let url = mojang_service_url(
|
||||
"https://api.minecraftservices.com/minecraft/profile/capes/active",
|
||||
should_use_mojang_mirror(),
|
||||
);
|
||||
update_profile_cache_from_response(
|
||||
INSECURE_REQWEST_CLIENT
|
||||
.put(url.as_ref())
|
||||
.header("Content-Type", "application/json; charset=utf-8")
|
||||
.header("Accept", "application/json")
|
||||
.header("User-Agent", MINECRAFT_SERVICES_USER_AGENT)
|
||||
.bearer_auth(&credentials.access_token)
|
||||
.json(&json!({
|
||||
"capeId": cape_id.hyphenated(),
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.and_then(|response| response.error_for_status())?,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn unequip_any(credentials: &Credentials) -> crate::Result<()> {
|
||||
let url = mojang_service_url(
|
||||
"https://api.minecraftservices.com/minecraft/profile/capes/active",
|
||||
should_use_mojang_mirror(),
|
||||
);
|
||||
update_profile_cache_from_response(
|
||||
INSECURE_REQWEST_CLIENT
|
||||
.delete(url.as_ref())
|
||||
.header("Accept", "application/json")
|
||||
.header("User-Agent", MINECRAFT_SERVICES_USER_AGENT)
|
||||
.bearer_auth(&credentials.access_token)
|
||||
.send()
|
||||
.await
|
||||
.and_then(|response| response.error_for_status())?,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides operations for interacting with skins on a Minecraft player profile.
|
||||
pub struct MinecraftSkinOperation;
|
||||
|
||||
impl MinecraftSkinOperation {
|
||||
pub async fn equip<TextureStream>(
|
||||
credentials: &Credentials,
|
||||
texture: TextureStream,
|
||||
variant: MinecraftSkinVariant,
|
||||
) -> crate::Result<Option<Arc<MinecraftProfile>>>
|
||||
where
|
||||
TextureStream: TryStream + Send + 'static,
|
||||
TextureStream::Error: Into<Box<dyn Error + Send + Sync>>,
|
||||
Bytes: From<TextureStream::Ok>,
|
||||
{
|
||||
let form = reqwest::multipart::Form::new()
|
||||
.text(
|
||||
"variant",
|
||||
match variant {
|
||||
MinecraftSkinVariant::Slim => "slim",
|
||||
MinecraftSkinVariant::Classic => "classic",
|
||||
_ => {
|
||||
return Err(ErrorKind::OtherError(
|
||||
"Cannot equip skin of unknown model variant".into(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
},
|
||||
)
|
||||
.part(
|
||||
"file",
|
||||
Part::stream(Body::wrap_stream(texture))
|
||||
.mime_str("image/png")?
|
||||
.file_name("skin.png"),
|
||||
);
|
||||
|
||||
let url = mojang_service_url(
|
||||
"https://api.minecraftservices.com/minecraft/profile/skins",
|
||||
should_use_mojang_mirror(),
|
||||
);
|
||||
let profile = update_profile_cache_from_response(
|
||||
INSECURE_REQWEST_CLIENT
|
||||
.post(url.as_ref())
|
||||
.header("Accept", "application/json")
|
||||
.header("User-Agent", MINECRAFT_SERVICES_USER_AGENT)
|
||||
.bearer_auth(&credentials.access_token)
|
||||
.multipart(form)
|
||||
.send()
|
||||
.await
|
||||
.and_then(|response| response.error_for_status())?,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(profile)
|
||||
}
|
||||
|
||||
pub async fn unequip_any(credentials: &Credentials) -> crate::Result<()> {
|
||||
let url = mojang_service_url(
|
||||
"https://api.minecraftservices.com/minecraft/profile/skins/active",
|
||||
should_use_mojang_mirror(),
|
||||
);
|
||||
update_profile_cache_from_response(
|
||||
INSECURE_REQWEST_CLIENT
|
||||
.delete(url.as_ref())
|
||||
.header("Accept", "application/json")
|
||||
.header("User-Agent", MINECRAFT_SERVICES_USER_AGENT)
|
||||
.bearer_auth(&credentials.access_token)
|
||||
.send()
|
||||
.await
|
||||
.and_then(|response| response.error_for_status())?,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_profile_cache_from_response(
|
||||
response: reqwest::Response,
|
||||
) -> Option<Arc<MinecraftProfile>> {
|
||||
let Some(mut profile) = response.json::<MinecraftProfile>().await.ok()
|
||||
else {
|
||||
tracing::warn!(
|
||||
"Failed to parse player profile from skin or cape operation response, not updating profile cache"
|
||||
);
|
||||
return None;
|
||||
};
|
||||
|
||||
profile.fetch_time = Some(Instant::now());
|
||||
let profile = Arc::new(profile);
|
||||
|
||||
PROFILE_CACHE
|
||||
.lock()
|
||||
.await
|
||||
.insert(profile.id, ProfileCacheEntry::Hit(Arc::clone(&profile)));
|
||||
|
||||
Some(profile)
|
||||
}
|
||||
Reference in New Issue
Block a user