You've already forked AstralRinth
forked from didirus/AstralRinth
Merge commit 'df1499047ccc8f39d756d5beba60651237aca1c0' into beta
This commit is contained in:
@@ -50,10 +50,10 @@ pub async fn parse_command(
|
||||
// We assume anything else is a filepath to an .mrpack file
|
||||
let path = PathBuf::from(command_string);
|
||||
let path = io::canonicalize(path)?;
|
||||
if let Some(ext) = path.extension() {
|
||||
if ext == "mrpack" {
|
||||
return Ok(CommandPayload::RunMRPack { path });
|
||||
}
|
||||
if let Some(ext) = path.extension()
|
||||
&& ext == "mrpack"
|
||||
{
|
||||
return Ok(CommandPayload::RunMRPack { path });
|
||||
}
|
||||
emit_warning(&format!(
|
||||
"Invalid command, unrecognized filetype: {}",
|
||||
|
||||
@@ -106,13 +106,13 @@ pub async fn auto_install_java(java_version: u32) -> crate::Result<PathBuf> {
|
||||
})?;
|
||||
|
||||
// removes the old installation of java
|
||||
if let Some(file) = archive.file_names().next() {
|
||||
if let Some(dir) = file.split('/').next() {
|
||||
let path = path.join(dir);
|
||||
if let Some(file) = archive.file_names().next()
|
||||
&& let Some(dir) = file.split('/').next()
|
||||
{
|
||||
let path = path.join(dir);
|
||||
|
||||
if path.exists() {
|
||||
io::remove_dir_all(path).await?;
|
||||
}
|
||||
if path.exists() {
|
||||
io::remove_dir_all(path).await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,11 +72,11 @@ pub async fn remove_user(uuid: uuid::Uuid) -> crate::Result<()> {
|
||||
if let Some((uuid, user)) = users.remove(&uuid) {
|
||||
Credentials::remove(uuid, &state.pool).await?;
|
||||
|
||||
if user.active {
|
||||
if let Some((_, mut user)) = users.into_iter().next() {
|
||||
user.active = true;
|
||||
user.upsert(&state.pool).await?;
|
||||
}
|
||||
if user.active
|
||||
&& let Some((_, mut user)) = users.into_iter().next()
|
||||
{
|
||||
user.active = true;
|
||||
user.upsert(&state.pool).await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -221,14 +221,14 @@ async fn import_atlauncher_unmanaged(
|
||||
.unwrap_or_else(|| backup_name.to_string());
|
||||
prof.install_stage = ProfileInstallStage::PackInstalling;
|
||||
|
||||
if let Some(ref project_id) = description.project_id {
|
||||
if let Some(ref version_id) = description.version_id {
|
||||
prof.linked_data = Some(LinkedData {
|
||||
project_id: project_id.clone(),
|
||||
version_id: version_id.clone(),
|
||||
locked: true,
|
||||
})
|
||||
}
|
||||
if let Some(ref project_id) = description.project_id
|
||||
&& let Some(ref version_id) = description.version_id
|
||||
{
|
||||
prof.linked_data = Some(LinkedData {
|
||||
project_id: project_id.clone(),
|
||||
version_id: version_id.clone(),
|
||||
locked: true,
|
||||
})
|
||||
}
|
||||
|
||||
prof.icon_path = description
|
||||
|
||||
@@ -383,18 +383,18 @@ pub async fn set_profile_information(
|
||||
.unwrap_or_else(|| backup_name.to_string());
|
||||
prof.install_stage = ProfileInstallStage::PackInstalling;
|
||||
|
||||
if let Some(ref project_id) = description.project_id {
|
||||
if let Some(ref version_id) = description.version_id {
|
||||
prof.linked_data = Some(LinkedData {
|
||||
project_id: project_id.clone(),
|
||||
version_id: version_id.clone(),
|
||||
locked: if !ignore_lock {
|
||||
true
|
||||
} else {
|
||||
prof.linked_data.as_ref().is_none_or(|x| x.locked)
|
||||
},
|
||||
})
|
||||
}
|
||||
if let Some(ref project_id) = description.project_id
|
||||
&& let Some(ref version_id) = description.version_id
|
||||
{
|
||||
prof.linked_data = Some(LinkedData {
|
||||
project_id: project_id.clone(),
|
||||
version_id: version_id.clone(),
|
||||
locked: if !ignore_lock {
|
||||
true
|
||||
} else {
|
||||
prof.linked_data.as_ref().is_none_or(|x| x.locked)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
prof.icon_path = description
|
||||
|
||||
@@ -149,13 +149,12 @@ pub async fn install_zipped_mrpack_files(
|
||||
let profile_path = profile_path.clone();
|
||||
async move {
|
||||
//TODO: Future update: prompt user for optional files in a modpack
|
||||
if let Some(env) = project.env {
|
||||
if env
|
||||
if let Some(env) = project.env
|
||||
&& env
|
||||
.get(&EnvType::Client)
|
||||
.is_some_and(|x| x == &SideType::Unsupported)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let file = fetch_mirrors(
|
||||
@@ -375,12 +374,12 @@ pub async fn remove_all_related_files(
|
||||
)
|
||||
.await?
|
||||
{
|
||||
if let Some(metadata) = &project.metadata {
|
||||
if to_remove.contains(&metadata.project_id) {
|
||||
let path = profile_full_path.join(file_path);
|
||||
if path.exists() {
|
||||
io::remove_file(&path).await?;
|
||||
}
|
||||
if let Some(metadata) = &project.metadata
|
||||
&& to_remove.contains(&metadata.project_id)
|
||||
{
|
||||
let path = profile_full_path.join(file_path);
|
||||
if path.exists() {
|
||||
io::remove_file(&path).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,28 +337,26 @@ pub async fn update_project(
|
||||
)
|
||||
.await?
|
||||
.remove(project_path)
|
||||
&& let Some(update_version) = &file.update_version_id
|
||||
{
|
||||
if let Some(update_version) = &file.update_version_id {
|
||||
let path = Profile::add_project_version(
|
||||
profile_path,
|
||||
update_version,
|
||||
&state.pool,
|
||||
&state.fetch_semaphore,
|
||||
&state.io_semaphore,
|
||||
)
|
||||
.await?;
|
||||
let path = Profile::add_project_version(
|
||||
profile_path,
|
||||
update_version,
|
||||
&state.pool,
|
||||
&state.fetch_semaphore,
|
||||
&state.io_semaphore,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if path != project_path {
|
||||
Profile::remove_project(profile_path, project_path).await?;
|
||||
}
|
||||
|
||||
if !skip_send_event.unwrap_or(false) {
|
||||
emit_profile(profile_path, ProfilePayloadType::Edited)
|
||||
.await?;
|
||||
}
|
||||
|
||||
return Ok(path);
|
||||
if path != project_path {
|
||||
Profile::remove_project(profile_path, project_path).await?;
|
||||
}
|
||||
|
||||
if !skip_send_event.unwrap_or(false) {
|
||||
emit_profile(profile_path, ProfilePayloadType::Edited).await?;
|
||||
}
|
||||
|
||||
return Ok(path);
|
||||
}
|
||||
|
||||
Err(crate::ErrorKind::InputError(
|
||||
@@ -479,10 +477,10 @@ pub async fn export_mrpack(
|
||||
let included_export_candidates = included_export_candidates
|
||||
.into_iter()
|
||||
.filter(|x| {
|
||||
if let Some(f) = PathBuf::from(x).file_name() {
|
||||
if f.to_string_lossy().starts_with(".DS_Store") {
|
||||
return false;
|
||||
}
|
||||
if let Some(f) = PathBuf::from(x).file_name()
|
||||
&& f.to_string_lossy().starts_with(".DS_Store")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
true
|
||||
})
|
||||
@@ -765,7 +763,7 @@ pub async fn try_update_playtime(path: &str) -> crate::Result<()> {
|
||||
let updated_recent_playtime = profile.recent_time_played;
|
||||
|
||||
let res = if updated_recent_playtime > 0 {
|
||||
// Create update struct to send to Labrinth
|
||||
// Create update struct to send to labrinth
|
||||
let modrinth_pack_version_id =
|
||||
profile.linked_data.as_ref().map(|l| l.version_id.clone());
|
||||
let playtime_update_json = json!({
|
||||
|
||||
@@ -187,6 +187,7 @@ pub enum LoadingBarType {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[cfg(feature = "tauri")]
|
||||
pub struct LoadingPayload {
|
||||
pub event: LoadingBarType,
|
||||
pub loader_uuid: Uuid,
|
||||
@@ -195,11 +196,7 @@ pub struct LoadingPayload {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct OfflinePayload {
|
||||
pub offline: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[cfg(feature = "tauri")]
|
||||
pub struct WarningPayload {
|
||||
pub message: String,
|
||||
}
|
||||
@@ -223,12 +220,14 @@ pub enum CommandPayload {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[cfg(feature = "tauri")]
|
||||
pub struct ProcessPayload {
|
||||
pub profile_path_id: String,
|
||||
pub uuid: Uuid,
|
||||
pub event: ProcessPayloadType,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ProcessPayloadType {
|
||||
@@ -237,11 +236,13 @@ pub enum ProcessPayloadType {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[cfg(feature = "tauri")]
|
||||
pub struct ProfilePayload {
|
||||
pub profile_path_id: String,
|
||||
#[serde(flatten)]
|
||||
pub event: ProfilePayloadType,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[serde(tag = "event", rename_all = "snake_case")]
|
||||
pub enum ProfilePayloadType {
|
||||
@@ -260,6 +261,16 @@ pub enum ProfilePayloadType {
|
||||
Removed,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[serde(tag = "event")]
|
||||
pub enum FriendPayload {
|
||||
FriendRequest { from: UserId },
|
||||
UserOffline { id: UserId },
|
||||
StatusUpdate { user_status: UserStatus },
|
||||
StatusSync,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum EventError {
|
||||
#[error("Event state was not properly initialized")]
|
||||
@@ -272,13 +283,3 @@ pub enum EventError {
|
||||
#[error("Tauri error: {0}")]
|
||||
TauriError(#[from] tauri::Error),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[serde(tag = "event")]
|
||||
pub enum FriendPayload {
|
||||
FriendRequest { from: UserId },
|
||||
UserOffline { id: UserId },
|
||||
StatusUpdate { user_status: UserStatus },
|
||||
StatusSync,
|
||||
}
|
||||
|
||||
@@ -32,15 +32,15 @@ pub fn get_class_paths(
|
||||
let mut cps = libraries
|
||||
.iter()
|
||||
.filter_map(|library| {
|
||||
if let Some(rules) = &library.rules {
|
||||
if !parse_rules(
|
||||
if let Some(rules) = &library.rules
|
||||
&& !parse_rules(
|
||||
rules,
|
||||
java_arch,
|
||||
&QuickPlayType::None,
|
||||
minecraft_updated,
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
if !library.include_in_classpath {
|
||||
@@ -504,10 +504,10 @@ pub async fn get_processor_main_class(
|
||||
let mut line = line.map_err(IOError::from)?;
|
||||
line.retain(|c| !c.is_whitespace());
|
||||
|
||||
if line.starts_with("Main-Class:") {
|
||||
if let Some(class) = line.split(':').nth(1) {
|
||||
return Ok(Some(class.to_string()));
|
||||
}
|
||||
if line.starts_with("Main-Class:")
|
||||
&& let Some(class) = line.split(':').nth(1)
|
||||
{
|
||||
return Ok(Some(class.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -290,12 +290,11 @@ pub async fn download_libraries(
|
||||
loading_try_for_each_concurrent(
|
||||
stream::iter(libraries.iter())
|
||||
.map(Ok::<&Library, crate::Error>), None, loading_bar,loading_amount,num_files, None,|library| async move {
|
||||
if let Some(rules) = &library.rules {
|
||||
if !parse_rules(rules, java_arch, &QuickPlayType::None, minecraft_updated) {
|
||||
if let Some(rules) = &library.rules
|
||||
&& !parse_rules(rules, java_arch, &QuickPlayType::None, minecraft_updated) {
|
||||
tracing::trace!("Skipped library {}", &library.name);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
if !library.downloadable {
|
||||
tracing::trace!("Skipped non-downloadable library {}", &library.name);
|
||||
@@ -311,15 +310,14 @@ pub async fn download_libraries(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Some(d::minecraft::LibraryDownloads { artifact: Some(ref artifact), ..}) = library.downloads {
|
||||
if !artifact.url.is_empty(){
|
||||
if let Some(d::minecraft::LibraryDownloads { artifact: Some(ref artifact), ..}) = library.downloads
|
||||
&& !artifact.url.is_empty(){
|
||||
let bytes = fetch(&artifact.url, Some(&artifact.sha1), &st.fetch_semaphore, &st.pool)
|
||||
.await?;
|
||||
write(&path, &bytes, &st.io_semaphore).await?;
|
||||
tracing::trace!("Fetched library {} to path {:?}", &library.name, &path);
|
||||
return Ok::<_, crate::Error>(());
|
||||
}
|
||||
}
|
||||
|
||||
let url = [
|
||||
library
|
||||
|
||||
@@ -344,10 +344,10 @@ pub async fn install_minecraft(
|
||||
|
||||
// Forge processors (90-100)
|
||||
for (index, processor) in processors.iter().enumerate() {
|
||||
if let Some(sides) = &processor.sides {
|
||||
if !sides.contains(&String::from("client")) {
|
||||
continue;
|
||||
}
|
||||
if let Some(sides) = &processor.sides
|
||||
&& !sides.contains(&String::from("client"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let cp = {
|
||||
|
||||
@@ -391,10 +391,10 @@ impl DirectoryInfo {
|
||||
return Err(e);
|
||||
}
|
||||
} else {
|
||||
if let Some(disk_usage) = get_disk_usage(&move_dir)? {
|
||||
if total_size > disk_usage {
|
||||
return Err(crate::ErrorKind::DirectoryMoveError(format!("Not enough space to move directory to {}: only {} bytes available", app_dir.display(), disk_usage)).into());
|
||||
}
|
||||
if let Some(disk_usage) = get_disk_usage(&move_dir)?
|
||||
&& total_size > disk_usage
|
||||
{
|
||||
return Err(crate::ErrorKind::DirectoryMoveError(format!("Not enough space to move directory to {}: only {} bytes available", app_dir.display(), disk_usage)).into());
|
||||
}
|
||||
|
||||
let loader_bar_id = Arc::new(&loader_bar_id);
|
||||
|
||||
@@ -9,7 +9,7 @@ use ariadne::networking::message::{
|
||||
ClientToServerMessage, ServerToClientMessage,
|
||||
};
|
||||
use ariadne::users::UserStatus;
|
||||
use async_tungstenite::WebSocketStream;
|
||||
use async_tungstenite::WebSocketSender;
|
||||
use async_tungstenite::tokio::{ConnectStream, connect_async};
|
||||
use async_tungstenite::tungstenite::Message;
|
||||
use async_tungstenite::tungstenite::client::IntoClientRequest;
|
||||
@@ -17,7 +17,6 @@ use bytes::Bytes;
|
||||
use chrono::{DateTime, Utc};
|
||||
use dashmap::DashMap;
|
||||
use either::Either;
|
||||
use futures::stream::SplitSink;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use reqwest::Method;
|
||||
use reqwest::header::HeaderValue;
|
||||
@@ -32,7 +31,7 @@ use tokio::sync::{Mutex, RwLock};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub(super) type WriteSocket =
|
||||
Arc<RwLock<Option<SplitSink<WebSocketStream<ConnectStream>, Message>>>>;
|
||||
Arc<RwLock<Option<WebSocketSender<ConnectStream>>>>;
|
||||
pub(super) type TunnelSockets = Arc<DashMap<Uuid, Arc<InternalTunnelSocket>>>;
|
||||
|
||||
pub struct FriendsSocket {
|
||||
@@ -180,27 +179,24 @@ impl FriendsSocket {
|
||||
ServerToClientMessage::FriendSocketStoppedListening { .. } => {}, // TODO
|
||||
|
||||
ServerToClientMessage::SocketConnected { to_socket, new_socket } => {
|
||||
if let Some(connected_to) = sockets.get(&to_socket) {
|
||||
if let InternalTunnelSocket::Listening(local_addr) = *connected_to.value().clone() {
|
||||
if let Ok(new_stream) = TcpStream::connect(local_addr).await {
|
||||
if let Some(connected_to) = sockets.get(&to_socket)
|
||||
&& let InternalTunnelSocket::Listening(local_addr) = *connected_to.value().clone()
|
||||
&& let Ok(new_stream) = TcpStream::connect(local_addr).await {
|
||||
let (read, write) = new_stream.into_split();
|
||||
sockets.insert(new_socket, Arc::new(InternalTunnelSocket::Connected(Mutex::new(write))));
|
||||
Self::socket_read_loop(write_handle.clone(), read, new_socket);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = Self::send_message(&write_handle, ClientToServerMessage::SocketClose { socket: new_socket }).await;
|
||||
},
|
||||
ServerToClientMessage::SocketClosed { socket } => {
|
||||
sockets.remove_if(&socket, |_, x| matches!(*x.clone(), InternalTunnelSocket::Connected(_)));
|
||||
},
|
||||
ServerToClientMessage::SocketData { socket, data } => {
|
||||
if let Some(mut socket) = sockets.get_mut(&socket) {
|
||||
if let InternalTunnelSocket::Connected(ref stream) = *socket.value_mut().clone() {
|
||||
if let Some(mut socket) = sockets.get_mut(&socket)
|
||||
&& let InternalTunnelSocket::Connected(ref stream) = *socket.value_mut().clone() {
|
||||
let _ = stream.lock().await.write_all(&data).await;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +100,8 @@ pub async fn init_watcher() -> crate::Result<FileWatcher> {
|
||||
let profile_path_str = profile_path_str.clone();
|
||||
let world = world.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Ok(state) = State::get().await {
|
||||
if let Err(e) = attached_world_data::AttachedWorldData::remove_for_world(
|
||||
if let Ok(state) = State::get().await
|
||||
&& let Err(e) = attached_world_data::AttachedWorldData::remove_for_world(
|
||||
&profile_path_str,
|
||||
WorldType::Singleplayer,
|
||||
&world,
|
||||
@@ -109,7 +109,6 @@ pub async fn init_watcher() -> crate::Result<FileWatcher> {
|
||||
).await {
|
||||
tracing::warn!("Failed to remove AttachedWorldData for '{world}': {e}")
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Some(ProfilePayloadType::WorldUpdated { world })
|
||||
@@ -150,14 +149,14 @@ pub(crate) async fn watch_profiles_init(
|
||||
) {
|
||||
if let Ok(profiles_dir) = std::fs::read_dir(dirs.profiles_dir()) {
|
||||
for profile_dir in profiles_dir {
|
||||
if let Ok(file_name) = profile_dir.map(|x| x.file_name()) {
|
||||
if let Some(file_name) = file_name.to_str() {
|
||||
if file_name.starts_with(".DS_Store") {
|
||||
continue;
|
||||
};
|
||||
if let Ok(file_name) = profile_dir.map(|x| x.file_name())
|
||||
&& let Some(file_name) = file_name.to_str()
|
||||
{
|
||||
if file_name.starts_with(".DS_Store") {
|
||||
continue;
|
||||
};
|
||||
|
||||
watch_profile(file_name, watcher, dirs).await;
|
||||
}
|
||||
watch_profile(file_name, watcher, dirs).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,10 +76,9 @@ where
|
||||
.loaded_config_dir
|
||||
.clone()
|
||||
.and_then(|x| x.to_str().map(|x| x.to_string()))
|
||||
&& path != old_launcher_root_str
|
||||
{
|
||||
if path != old_launcher_root_str {
|
||||
settings.custom_dir = Some(path);
|
||||
}
|
||||
settings.custom_dir = Some(path);
|
||||
}
|
||||
|
||||
settings.prev_custom_dir = Some(old_launcher_root_str.clone());
|
||||
@@ -137,31 +136,27 @@ where
|
||||
.await?;
|
||||
}
|
||||
|
||||
if let Some(device_token) = minecraft_auth.token {
|
||||
if let Ok(private_key) =
|
||||
if let Some(device_token) = minecraft_auth.token
|
||||
&& let Ok(private_key) =
|
||||
SigningKey::from_pkcs8_pem(&device_token.private_key)
|
||||
{
|
||||
if let Ok(uuid) = Uuid::parse_str(&device_token.id) {
|
||||
DeviceTokenPair {
|
||||
token: DeviceToken {
|
||||
issue_instant: device_token.token.issue_instant,
|
||||
not_after: device_token.token.not_after,
|
||||
token: device_token.token.token,
|
||||
display_claims: device_token
|
||||
.token
|
||||
.display_claims,
|
||||
},
|
||||
key: DeviceTokenKey {
|
||||
id: uuid,
|
||||
key: private_key,
|
||||
x: device_token.x,
|
||||
y: device_token.y,
|
||||
},
|
||||
}
|
||||
.upsert(exec)
|
||||
.await?;
|
||||
}
|
||||
&& let Ok(uuid) = Uuid::parse_str(&device_token.id)
|
||||
{
|
||||
DeviceTokenPair {
|
||||
token: DeviceToken {
|
||||
issue_instant: device_token.token.issue_instant,
|
||||
not_after: device_token.token.not_after,
|
||||
token: device_token.token.token,
|
||||
display_claims: device_token.token.display_claims,
|
||||
},
|
||||
key: DeviceTokenKey {
|
||||
id: uuid,
|
||||
key: private_key,
|
||||
x: device_token.x,
|
||||
y: device_token.y,
|
||||
},
|
||||
}
|
||||
.upsert(exec)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,100 +203,93 @@ where
|
||||
update_version,
|
||||
..
|
||||
} = project.metadata
|
||||
{
|
||||
if let Some(file) = version
|
||||
&& let Some(file) = version
|
||||
.files
|
||||
.iter()
|
||||
.find(|x| x.hashes.get("sha512") == Some(&sha512))
|
||||
{
|
||||
if let Some(sha1) = file.hashes.get("sha1") {
|
||||
if let Ok(metadata) = full_path.metadata() {
|
||||
let file_name = format!(
|
||||
"{}/{}",
|
||||
profile.path,
|
||||
path.replace('\\', "/")
|
||||
.replace(".disabled", "")
|
||||
);
|
||||
&& let Some(sha1) = file.hashes.get("sha1")
|
||||
{
|
||||
if let Ok(metadata) = full_path.metadata() {
|
||||
let file_name = format!(
|
||||
"{}/{}",
|
||||
profile.path,
|
||||
path.replace('\\', "/")
|
||||
.replace(".disabled", "")
|
||||
);
|
||||
|
||||
cached_entries.push(CacheValue::FileHash(
|
||||
CachedFileHash {
|
||||
path: file_name,
|
||||
size: metadata.len(),
|
||||
hash: sha1.clone(),
|
||||
project_type: ProjectType::get_from_parent_folder(&full_path),
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
cached_entries.push(CacheValue::File(
|
||||
CachedFile {
|
||||
hash: sha1.clone(),
|
||||
project_id: version.project_id.clone(),
|
||||
version_id: version.id.clone(),
|
||||
},
|
||||
));
|
||||
|
||||
if let Some(update_version) = update_version {
|
||||
let mod_loader: ModLoader =
|
||||
profile.metadata.loader.into();
|
||||
cached_entries.push(
|
||||
CacheValue::FileUpdate(
|
||||
CachedFileUpdate {
|
||||
hash: sha1.clone(),
|
||||
game_version: profile
|
||||
.metadata
|
||||
.game_version
|
||||
.clone(),
|
||||
loaders: vec![
|
||||
mod_loader
|
||||
.as_str()
|
||||
.to_string(),
|
||||
],
|
||||
update_version_id:
|
||||
update_version.id.clone(),
|
||||
},
|
||||
cached_entries.push(CacheValue::FileHash(
|
||||
CachedFileHash {
|
||||
path: file_name,
|
||||
size: metadata.len(),
|
||||
hash: sha1.clone(),
|
||||
project_type:
|
||||
ProjectType::get_from_parent_folder(
|
||||
&full_path,
|
||||
),
|
||||
);
|
||||
|
||||
cached_entries.push(CacheValue::Version(
|
||||
(*update_version).into(),
|
||||
));
|
||||
}
|
||||
|
||||
let members = members
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
let user = User {
|
||||
id: x.user.id,
|
||||
username: x.user.username,
|
||||
avatar_url: x.user.avatar_url,
|
||||
bio: x.user.bio,
|
||||
created: x.user.created,
|
||||
role: x.user.role,
|
||||
badges: 0,
|
||||
};
|
||||
|
||||
cached_entries.push(CacheValue::User(
|
||||
user.clone(),
|
||||
));
|
||||
|
||||
TeamMember {
|
||||
team_id: x.team_id,
|
||||
user,
|
||||
is_owner: x.role == "Owner",
|
||||
role: x.role,
|
||||
ordering: x.ordering,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
cached_entries.push(CacheValue::Team(members));
|
||||
|
||||
cached_entries.push(CacheValue::Version(
|
||||
(*version).into(),
|
||||
));
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
cached_entries.push(CacheValue::File(CachedFile {
|
||||
hash: sha1.clone(),
|
||||
project_id: version.project_id.clone(),
|
||||
version_id: version.id.clone(),
|
||||
}));
|
||||
|
||||
if let Some(update_version) = update_version {
|
||||
let mod_loader: ModLoader =
|
||||
profile.metadata.loader.into();
|
||||
cached_entries.push(CacheValue::FileUpdate(
|
||||
CachedFileUpdate {
|
||||
hash: sha1.clone(),
|
||||
game_version: profile
|
||||
.metadata
|
||||
.game_version
|
||||
.clone(),
|
||||
loaders: vec![
|
||||
mod_loader.as_str().to_string(),
|
||||
],
|
||||
update_version_id: update_version
|
||||
.id
|
||||
.clone(),
|
||||
},
|
||||
));
|
||||
|
||||
cached_entries.push(CacheValue::Version(
|
||||
(*update_version).into(),
|
||||
));
|
||||
}
|
||||
|
||||
let members = members
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
let user = User {
|
||||
id: x.user.id,
|
||||
username: x.user.username,
|
||||
avatar_url: x.user.avatar_url,
|
||||
bio: x.user.bio,
|
||||
created: x.user.created,
|
||||
role: x.user.role,
|
||||
badges: 0,
|
||||
};
|
||||
|
||||
cached_entries
|
||||
.push(CacheValue::User(user.clone()));
|
||||
|
||||
TeamMember {
|
||||
team_id: x.team_id,
|
||||
user,
|
||||
is_owner: x.role == "Owner",
|
||||
role: x.role,
|
||||
ordering: x.ordering,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
cached_entries.push(CacheValue::Team(members));
|
||||
|
||||
cached_entries
|
||||
.push(CacheValue::Version((*version).into()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,16 +321,15 @@ where
|
||||
.map(|x| x.id),
|
||||
groups: profile.metadata.groups,
|
||||
linked_data: profile.metadata.linked_data.and_then(|x| {
|
||||
if let Some(project_id) = x.project_id {
|
||||
if let Some(version_id) = x.version_id {
|
||||
if let Some(locked) = x.locked {
|
||||
return Some(LinkedData {
|
||||
project_id,
|
||||
version_id,
|
||||
locked,
|
||||
});
|
||||
}
|
||||
}
|
||||
if let Some(project_id) = x.project_id
|
||||
&& let Some(version_id) = x.version_id
|
||||
&& let Some(locked) = x.locked
|
||||
{
|
||||
return Some(LinkedData {
|
||||
project_id,
|
||||
version_id,
|
||||
locked,
|
||||
});
|
||||
}
|
||||
|
||||
None
|
||||
|
||||
@@ -477,10 +477,9 @@ impl Credentials {
|
||||
..
|
||||
},
|
||||
) = *err.raw
|
||||
&& (source.is_connect() || source.is_timeout())
|
||||
{
|
||||
if source.is_connect() || source.is_timeout() {
|
||||
return Ok(Some(creds));
|
||||
}
|
||||
return Ok(Some(creds));
|
||||
}
|
||||
|
||||
Err(err)
|
||||
@@ -729,36 +728,31 @@ impl DeviceTokenPair {
|
||||
.fetch_optional(exec)
|
||||
.await?;
|
||||
|
||||
if let Some(x) = res {
|
||||
if let Ok(uuid) = Uuid::parse_str(&x.uuid) {
|
||||
if let Ok(private_key) =
|
||||
SigningKey::from_pkcs8_pem(&x.private_key)
|
||||
{
|
||||
return Ok(Some(Self {
|
||||
token: DeviceToken {
|
||||
issue_instant: Utc
|
||||
.timestamp_opt(x.issue_instant, 0)
|
||||
.single()
|
||||
.unwrap_or_else(Utc::now),
|
||||
not_after: Utc
|
||||
.timestamp_opt(x.not_after, 0)
|
||||
.single()
|
||||
.unwrap_or_else(Utc::now),
|
||||
token: x.token,
|
||||
display_claims: serde_json::from_value(
|
||||
x.display_claims,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
key: DeviceTokenKey {
|
||||
id: uuid,
|
||||
key: private_key,
|
||||
x: x.x,
|
||||
y: x.y,
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
if let Some(x) = res
|
||||
&& let Ok(uuid) = Uuid::parse_str(&x.uuid)
|
||||
&& let Ok(private_key) = SigningKey::from_pkcs8_pem(&x.private_key)
|
||||
{
|
||||
return Ok(Some(Self {
|
||||
token: DeviceToken {
|
||||
issue_instant: Utc
|
||||
.timestamp_opt(x.issue_instant, 0)
|
||||
.single()
|
||||
.unwrap_or_else(Utc::now),
|
||||
not_after: Utc
|
||||
.timestamp_opt(x.not_after, 0)
|
||||
.single()
|
||||
.unwrap_or_else(Utc::now),
|
||||
token: x.token,
|
||||
display_claims: serde_json::from_value(x.display_claims)
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
key: DeviceTokenKey {
|
||||
id: uuid,
|
||||
key: private_key,
|
||||
x: x.x,
|
||||
y: x.y,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
@@ -813,11 +807,7 @@ const MICROSOFT_CLIENT_ID: &str = "00000000402b5328";
|
||||
const AUTH_REPLY_URL: &str = "https://login.live.com/oauth20_desktop.srf";
|
||||
const REQUESTED_SCOPE: &str = "service::user.auth.xboxlive.com::MBI_SSL";
|
||||
|
||||
/* [AR] Fix
|
||||
* Weird visibility issue that didn't reproduce before
|
||||
* Had to make DeviceToken and RequestWithDate pub(crate) to fix compilation error
|
||||
*/
|
||||
pub(crate) struct RequestWithDate<T> {
|
||||
pub struct RequestWithDate<T> {
|
||||
pub date: DateTime<Utc>,
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ pub async fn finish_login_flow(
|
||||
semaphore: &FetchSemaphore,
|
||||
exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite>,
|
||||
) -> crate::Result<ModrinthCredentials> {
|
||||
// The authorization code actually is the access token, since Labrinth doesn't
|
||||
// The authorization code actually is the access token, since labrinth doesn't
|
||||
// issue separate authorization codes. Therefore, this is equivalent to an
|
||||
// implicit OAuth grant flow, and no additional exchanging or finalization is
|
||||
// needed. TODO not do this for the reasons outlined at
|
||||
|
||||
@@ -360,18 +360,17 @@ impl Process {
|
||||
}
|
||||
|
||||
// Write the throwable if present
|
||||
if !current_content.is_empty() {
|
||||
if let Err(e) =
|
||||
if !current_content.is_empty()
|
||||
&& let Err(e) =
|
||||
Process::append_to_log_file(
|
||||
&log_path,
|
||||
¤t_content,
|
||||
)
|
||||
{
|
||||
tracing::error!(
|
||||
"Failed to write throwable to log file: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
{
|
||||
tracing::error!(
|
||||
"Failed to write throwable to log file: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -429,15 +428,13 @@ impl Process {
|
||||
|
||||
if let Some(timestamp) =
|
||||
current_event.timestamp.as_deref()
|
||||
{
|
||||
if let Err(e) = Self::maybe_handle_server_join_logging(
|
||||
&& let Err(e) = Self::maybe_handle_server_join_logging(
|
||||
profile_path,
|
||||
timestamp,
|
||||
message
|
||||
).await {
|
||||
tracing::error!("Failed to handle server join logging: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -445,35 +442,29 @@ impl Process {
|
||||
}
|
||||
Ok(Event::Text(mut e)) => {
|
||||
if in_message || in_throwable {
|
||||
if let Ok(text) = e.unescape() {
|
||||
if let Ok(text) = e.xml_content() {
|
||||
current_content.push_str(&text);
|
||||
}
|
||||
} else if !in_event
|
||||
&& !e.inplace_trim_end()
|
||||
&& !e.inplace_trim_start()
|
||||
&& let Ok(text) = e.xml_content()
|
||||
&& let Err(e) = Process::append_to_log_file(
|
||||
&log_path,
|
||||
&format!("{text}\n"),
|
||||
)
|
||||
{
|
||||
if let Ok(text) = e.unescape() {
|
||||
if let Err(e) = Process::append_to_log_file(
|
||||
&log_path,
|
||||
&format!("{text}\n"),
|
||||
) {
|
||||
tracing::error!(
|
||||
"Failed to write to log file: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
tracing::error!(
|
||||
"Failed to write to log file: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(Event::CData(e)) => {
|
||||
if in_message || in_throwable {
|
||||
if let Ok(text) = e
|
||||
.escape()
|
||||
.map_err(|x| x.into())
|
||||
.and_then(|x| x.unescape())
|
||||
{
|
||||
current_content.push_str(&text);
|
||||
}
|
||||
if (in_message || in_throwable)
|
||||
&& let Ok(text) = e.xml_content()
|
||||
{
|
||||
current_content.push_str(&text);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
@@ -720,16 +711,13 @@ impl Process {
|
||||
let logs_folder = state.directories.profile_logs_dir(&profile_path);
|
||||
let log_path = logs_folder.join(LAUNCHER_LOG_PATH);
|
||||
|
||||
if log_path.exists() {
|
||||
if let Err(e) = Process::append_to_log_file(
|
||||
if log_path.exists()
|
||||
&& let Err(e) = Process::append_to_log_file(
|
||||
&log_path,
|
||||
&format!("\n# Process exited with status: {mc_exit_status}\n"),
|
||||
) {
|
||||
tracing::warn!(
|
||||
"Failed to write exit status to log file: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
)
|
||||
{
|
||||
tracing::warn!("Failed to write exit status to log file: {}", e);
|
||||
}
|
||||
|
||||
let _ = state.discord_rpc.clear_to_default(true).await;
|
||||
|
||||
@@ -595,8 +595,8 @@ impl Profile {
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self, semaphore, icon))]
|
||||
pub async fn set_icon<'a>(
|
||||
&'a mut self,
|
||||
pub async fn set_icon(
|
||||
&mut self,
|
||||
cache_dir: &Path,
|
||||
semaphore: &IoSemaphore,
|
||||
icon: bytes::Bytes,
|
||||
@@ -629,21 +629,20 @@ impl Profile {
|
||||
{
|
||||
let subdirectory =
|
||||
subdirectory.map_err(io::IOError::from)?.path();
|
||||
if subdirectory.is_file() {
|
||||
if let Some(file_name) = subdirectory
|
||||
if subdirectory.is_file()
|
||||
&& let Some(file_name) = subdirectory
|
||||
.file_name()
|
||||
.and_then(|x| x.to_str())
|
||||
{
|
||||
let file_size = subdirectory
|
||||
.metadata()
|
||||
.map_err(io::IOError::from)?
|
||||
.len();
|
||||
{
|
||||
let file_size = subdirectory
|
||||
.metadata()
|
||||
.map_err(io::IOError::from)?
|
||||
.len();
|
||||
|
||||
keys.push(format!(
|
||||
"{file_size}-{}/{folder}/{file_name}",
|
||||
profile.path
|
||||
));
|
||||
}
|
||||
keys.push(format!(
|
||||
"{file_size}-{}/{folder}/{file_name}",
|
||||
profile.path
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -901,30 +900,29 @@ impl Profile {
|
||||
{
|
||||
let subdirectory =
|
||||
subdirectory.map_err(io::IOError::from)?.path();
|
||||
if subdirectory.is_file() {
|
||||
if let Some(file_name) =
|
||||
if subdirectory.is_file()
|
||||
&& let Some(file_name) =
|
||||
subdirectory.file_name().and_then(|x| x.to_str())
|
||||
{
|
||||
let file_size = subdirectory
|
||||
.metadata()
|
||||
.map_err(io::IOError::from)?
|
||||
.len();
|
||||
{
|
||||
let file_size = subdirectory
|
||||
.metadata()
|
||||
.map_err(io::IOError::from)?
|
||||
.len();
|
||||
|
||||
keys.push(InitialScanFile {
|
||||
path: format!(
|
||||
"{}/{folder}/{}",
|
||||
self.path,
|
||||
file_name.trim_end_matches(".disabled")
|
||||
),
|
||||
file_name: file_name.to_string(),
|
||||
project_type,
|
||||
size: file_size,
|
||||
cache_key: format!(
|
||||
"{file_size}-{}/{folder}/{file_name}",
|
||||
self.path
|
||||
),
|
||||
});
|
||||
}
|
||||
keys.push(InitialScanFile {
|
||||
path: format!(
|
||||
"{}/{folder}/{}",
|
||||
self.path,
|
||||
file_name.trim_end_matches(".disabled")
|
||||
),
|
||||
file_name: file_name.to_string(),
|
||||
project_type,
|
||||
size: file_size,
|
||||
cache_key: format!(
|
||||
"{file_size}-{}/{folder}/{file_name}",
|
||||
self.path
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ where
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(bytes, semaphore))]
|
||||
pub async fn write<'a>(
|
||||
pub async fn write(
|
||||
path: &Path,
|
||||
bytes: &[u8],
|
||||
semaphore: &IoSemaphore,
|
||||
|
||||
@@ -191,22 +191,21 @@ async fn get_all_autoinstalled_jre_path() -> Result<HashSet<PathBuf>, JREError>
|
||||
let mut jre_paths = HashSet::new();
|
||||
let base_path = state.directories.java_versions_dir();
|
||||
|
||||
if base_path.is_dir() {
|
||||
if let Ok(dir) = std::fs::read_dir(base_path) {
|
||||
for entry in dir.flatten() {
|
||||
let file_path = entry.path().join("bin");
|
||||
if base_path.is_dir()
|
||||
&& let Ok(dir) = std::fs::read_dir(base_path)
|
||||
{
|
||||
for entry in dir.flatten() {
|
||||
let file_path = entry.path().join("bin");
|
||||
|
||||
if let Ok(contents) =
|
||||
std::fs::read_to_string(file_path.clone())
|
||||
if let Ok(contents) = std::fs::read_to_string(file_path.clone())
|
||||
{
|
||||
let entry = entry.path().join(contents);
|
||||
jre_paths.insert(entry);
|
||||
} else {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
let entry = entry.path().join(contents);
|
||||
jre_paths.insert(entry);
|
||||
} else {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
let file_path = file_path.join(JAVA_BIN);
|
||||
jre_paths.insert(file_path);
|
||||
}
|
||||
let file_path = file_path.join(JAVA_BIN);
|
||||
jre_paths.insert(file_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -300,20 +299,20 @@ pub async fn check_java_at_filepath(path: &Path) -> crate::Result<JavaVersion> {
|
||||
}
|
||||
|
||||
// Extract version info from it
|
||||
if let Some(arch) = java_arch {
|
||||
if let Some(version) = java_version {
|
||||
if let Ok(version) = extract_java_version(version) {
|
||||
let path = java.to_string_lossy().to_string();
|
||||
return Ok(JavaVersion {
|
||||
parsed_version: version,
|
||||
path,
|
||||
version: version.to_string(),
|
||||
architecture: arch.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
return Err(JREError::InvalidJREVersion(version.to_owned()).into());
|
||||
if let Some(arch) = java_arch
|
||||
&& let Some(version) = java_version
|
||||
{
|
||||
if let Ok(version) = extract_java_version(version) {
|
||||
let path = java.to_string_lossy().to_string();
|
||||
return Ok(JavaVersion {
|
||||
parsed_version: version,
|
||||
path,
|
||||
version: version.to_string(),
|
||||
architecture: arch.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
return Err(JREError::InvalidJREVersion(version.to_owned()).into());
|
||||
}
|
||||
|
||||
Err(JREError::FailedJavaCheck(java).into())
|
||||
|
||||
Reference in New Issue
Block a user