You've already forked AstralRinth
forked from didirus/AstralRinth
Initial commit
This commit is contained in:
55
packages/app-lib/src/api/download.rs
Normal file
55
packages/app-lib/src/api/download.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use std::process::exit;
|
||||
|
||||
use reqwest;
|
||||
use tokio::fs::File as AsyncFile;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::process::Command;
|
||||
|
||||
async fn download_file(download_url: &str, local_filename: &str, os_type: &str, auto_update_supported: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let download_dir = dirs::download_dir().ok_or("[download_file] • Failed to determine download directory")?;
|
||||
let full_path = download_dir.join(local_filename);
|
||||
let response = reqwest::get(download_url).await?;
|
||||
let bytes = response.bytes().await?;
|
||||
let mut dest_file = AsyncFile::create(&full_path).await?;
|
||||
dest_file.write_all(&bytes).await?;
|
||||
println!("[download_file] • File downloaded to: {:?}", full_path);
|
||||
if auto_update_supported {
|
||||
let status;
|
||||
if os_type.to_lowercase() == "Windows".to_lowercase() {
|
||||
status = Command::new("explorer")
|
||||
.arg(download_dir.display().to_string())
|
||||
.status()
|
||||
.await
|
||||
.expect("[download_file] • Failed to open downloads folder");
|
||||
} else if os_type.to_lowercase() == "MacOS".to_lowercase() {
|
||||
status = Command::new("open")
|
||||
.arg(full_path.to_str().unwrap_or_default())
|
||||
.status()
|
||||
.await
|
||||
.expect("[download_file] • Failed to execute command");
|
||||
} else {
|
||||
status = Command::new(".")
|
||||
.arg(full_path.to_str().unwrap_or_default())
|
||||
.status()
|
||||
.await
|
||||
.expect("[download_file] • Failed to execute command");
|
||||
}
|
||||
if status.success() {
|
||||
println!("[download_file] • File opened successfully!");
|
||||
} else {
|
||||
eprintln!("[download_file] • Failed to open the file. Exit code: {:?}", status.code());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn init_download(download_url: &str, local_filename: &str, os_type: &str, auto_update_supported: bool) {
|
||||
println!("[init_download] • Initialize downloading from • {:?}", download_url);
|
||||
println!("[init_download] • Save local file name • {:?}", local_filename);
|
||||
if let Err(e) = download_file(download_url, local_filename, os_type, auto_update_supported).await {
|
||||
eprintln!("[init_download] • An error occurred! Failed to download the file: {}", e);
|
||||
} else {
|
||||
println!("[init_download] • Code finishes without errors.");
|
||||
exit(0)
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,14 @@ pub async fn finish_login(
|
||||
crate::state::login_finish(code, flow, &state.pool).await
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn offline_auth(
|
||||
name: &str
|
||||
) -> crate::Result<Credentials> {
|
||||
let state = State::get().await?;
|
||||
crate::state::offline_auth(name, &state.pool).await
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn get_default_user() -> crate::Result<Option<uuid::Uuid>> {
|
||||
let state = State::get().await?;
|
||||
|
||||
@@ -11,6 +11,7 @@ pub mod process;
|
||||
pub mod profile;
|
||||
pub mod settings;
|
||||
pub mod tags;
|
||||
pub mod download;
|
||||
|
||||
pub mod data {
|
||||
pub use crate::state::{
|
||||
|
||||
@@ -16,6 +16,7 @@ use chrono::Utc;
|
||||
use daedalus as d;
|
||||
use daedalus::minecraft::{RuleAction, VersionInfo};
|
||||
use daedalus::modded::LoaderVersion;
|
||||
use rand::seq::SliceRandom;
|
||||
use st::Profile;
|
||||
use std::collections::HashMap;
|
||||
use tokio::process::Command;
|
||||
@@ -24,6 +25,8 @@ mod args;
|
||||
|
||||
pub mod download;
|
||||
|
||||
use crate::state::ACTIVE_STATE;
|
||||
|
||||
// All nones -> disallowed
|
||||
// 1+ true -> allowed
|
||||
// 1+ false -> disallowed
|
||||
@@ -672,10 +675,11 @@ pub async fn launch_minecraft(
|
||||
}
|
||||
}
|
||||
|
||||
let _ = state
|
||||
.discord_rpc
|
||||
.set_activity(&format!("Playing {}", profile.name), true)
|
||||
.await;
|
||||
let selected_phrase = ACTIVE_STATE.choose(&mut rand::thread_rng()).unwrap();
|
||||
let _ = state
|
||||
.discord_rpc
|
||||
.set_activity(&format!("{} {}", selected_phrase, profile.name), true)
|
||||
.await;
|
||||
|
||||
// Create Minecraft child by inserting it into the state
|
||||
// This also spawns the process and prepares the subsequent processes
|
||||
|
||||
@@ -24,7 +24,7 @@ impl DirectoryInfo {
|
||||
// init() is not needed for this function
|
||||
pub fn get_initial_settings_dir() -> Option<PathBuf> {
|
||||
Self::env_path("THESEUS_CONFIG_DIR")
|
||||
.or_else(|| Some(dirs::data_dir()?.join("ModrinthApp")))
|
||||
.or_else(|| Some(dirs::data_dir()?.join("AstralRinthApp")))
|
||||
}
|
||||
|
||||
/// Get all paths needed for Theseus to operate properly
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
use std::sync::{atomic::AtomicBool, Arc};
|
||||
use std::{
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use discord_rich_presence::{
|
||||
activity::{Activity, Assets},
|
||||
activity::{Activity, Assets, Timestamps},
|
||||
DiscordIpc, DiscordIpcClient,
|
||||
};
|
||||
use rand::seq::SliceRandom;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::state::Profile;
|
||||
// use crate::state::Profile;
|
||||
use crate::util::utils;
|
||||
use crate::State;
|
||||
|
||||
pub struct DiscordGuard {
|
||||
@@ -14,12 +19,29 @@ pub struct DiscordGuard {
|
||||
connected: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
pub(crate) const ACTIVE_STATE: [&str; 6] = [
|
||||
"Explores",
|
||||
"Travels with",
|
||||
"Pirating",
|
||||
"Investigating the",
|
||||
"Engaged in",
|
||||
"Conducting",
|
||||
];
|
||||
pub(crate) const INACTIVE_STATE: [&str; 6] = [
|
||||
"Idling...",
|
||||
"Waiting for the pirate team...",
|
||||
"Taking a break...",
|
||||
"Resting...",
|
||||
"On standby...",
|
||||
"In a holding pattern...",
|
||||
];
|
||||
|
||||
impl DiscordGuard {
|
||||
/// Initialize discord IPC client, and attempt to connect to it
|
||||
/// If it fails, it will still return a DiscordGuard, but the client will be unconnected
|
||||
pub fn init() -> crate::Result<DiscordGuard> {
|
||||
let dipc =
|
||||
DiscordIpcClient::new("1123683254248148992").map_err(|e| {
|
||||
DiscordIpcClient::new("1190718475832918136").map_err(|e| {
|
||||
crate::ErrorKind::OtherError(format!(
|
||||
"Could not create Discord client {}",
|
||||
e,
|
||||
@@ -77,11 +99,32 @@ impl DiscordGuard {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let activity = Activity::new().state(msg).assets(
|
||||
Assets::new()
|
||||
.large_image("modrinth_simple")
|
||||
.large_text("Modrinth Logo"),
|
||||
);
|
||||
// let activity = Activity::new().state(msg).assets(
|
||||
// Assets::new()
|
||||
// .large_image("modrinth_simple")
|
||||
// .large_text("Modrinth Logo"),
|
||||
// );
|
||||
|
||||
let launcher =
|
||||
utils::read_package_json().expect("Failed to read package.json");
|
||||
|
||||
let build_info = format!("AR • v{}", launcher.version);
|
||||
let build_download = "https://astralium.su/get/ar";
|
||||
|
||||
let time = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.expect("Failed to get system time")
|
||||
.as_secs() as i64;
|
||||
let activity = Activity::new()
|
||||
.state(msg)
|
||||
.assets(
|
||||
Assets::new()
|
||||
.large_image("astralrinth_logo")
|
||||
.large_text(&build_info)
|
||||
.small_image("astralrinth_logo")
|
||||
.small_text(&build_download),
|
||||
)
|
||||
.timestamps(Timestamps::new().start(time));
|
||||
|
||||
// Attempt to set the activity
|
||||
// If the existing connection fails, attempt to reconnect and try again
|
||||
@@ -167,20 +210,10 @@ impl DiscordGuard {
|
||||
return self.clear_activity(true).await;
|
||||
}
|
||||
|
||||
let running_profiles = state.process_manager.get_all();
|
||||
if let Some(existing_child) = running_profiles.first() {
|
||||
let prof =
|
||||
Profile::get(&existing_child.profile_path, &state.pool).await?;
|
||||
if let Some(prof) = prof {
|
||||
self.set_activity(
|
||||
&format!("Playing {}", prof.name),
|
||||
reconnect_if_fail,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
} else {
|
||||
self.set_activity("Idling...", reconnect_if_fail).await?;
|
||||
}
|
||||
let selected_phrase =
|
||||
INACTIVE_STATE.choose(&mut rand::thread_rng()).unwrap();
|
||||
self.set_activity(&format!("{}", selected_phrase), reconnect_if_fail)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +197,29 @@ pub async fn login_finish(
|
||||
Ok(credentials)
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn offline_auth(
|
||||
name: &str,
|
||||
exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite> + Copy,
|
||||
) -> crate::Result<Credentials> {
|
||||
let random_uuid = Uuid::new_v4();
|
||||
let access_token = "null".to_string();
|
||||
let refresh_token = "null".to_string();
|
||||
|
||||
let credentials = Credentials {
|
||||
id: random_uuid,
|
||||
username: name.to_string(),
|
||||
access_token: access_token,
|
||||
refresh_token: refresh_token,
|
||||
expires: Utc::now() + Duration::days(365 * 99),
|
||||
active: true,
|
||||
};
|
||||
|
||||
credentials.upsert(exec).await?;
|
||||
|
||||
Ok(credentials)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct Credentials {
|
||||
pub id: Uuid,
|
||||
|
||||
@@ -3,6 +3,7 @@ pub mod fetch;
|
||||
pub mod io;
|
||||
pub mod jre;
|
||||
pub mod platform;
|
||||
pub mod utils;
|
||||
|
||||
/// Wrap a builder which uses a mut reference into one which outputs an owned value
|
||||
macro_rules! wrap_ref_builder {
|
||||
|
||||
18
packages/app-lib/src/util/utils.rs
Normal file
18
packages/app-lib/src/util/utils.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::io;
|
||||
|
||||
const PACKAGE_JSON_CONTENT: &str =
|
||||
include_str!("../../../../apps/app-frontend/package.json");
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Launcher {
|
||||
pub version: String,
|
||||
pub development_build: bool,
|
||||
}
|
||||
|
||||
pub fn read_package_json() -> io::Result<Launcher> {
|
||||
// Deserialize the content of package.json into a Launcher struct
|
||||
let launcher: Launcher = serde_json::from_str(PACKAGE_JSON_CONTENT)?;
|
||||
|
||||
Ok(launcher)
|
||||
}
|
||||
Reference in New Issue
Block a user