You've already forked AstralRinth
forked from didirus/AstralRinth
Migrate to SQLite for Internal Launcher Data (#1300)
* initial migration * barebones profiles * Finish profiles * Add back file watcher * UI support progress * Finish most of cache * Fix options page * Fix forge, finish modrinth auth * Accounts, process cache * Run SQLX prepare * Finish * Run lint + actions * Fix version to be compat with windows * fix lint * actually fix lint * actually fix lint again
This commit is contained in:
@@ -8,7 +8,7 @@ use crate::{
|
||||
import::{self, copy_dotminecraft},
|
||||
install_from::CreatePackDescription,
|
||||
},
|
||||
prelude::{ModLoader, Profile, ProfilePathId},
|
||||
prelude::ModLoader,
|
||||
state::{LinkedData, ProfileInstallStage},
|
||||
util::io,
|
||||
State,
|
||||
@@ -116,11 +116,11 @@ pub async fn is_valid_atlauncher(instance_folder: PathBuf) -> bool {
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
#[theseus_macros::debug_pin]
|
||||
|
||||
pub async fn import_atlauncher(
|
||||
atlauncher_base_path: PathBuf, // path to base atlauncher folder
|
||||
instance_folder: String, // instance folder in atlauncher_base_path
|
||||
profile_path: ProfilePathId, // path to profile
|
||||
profile_path: &str, // path to profile
|
||||
) -> crate::Result<()> {
|
||||
let atlauncher_instance_path = atlauncher_base_path
|
||||
.join("instances")
|
||||
@@ -159,7 +159,7 @@ pub async fn import_atlauncher(
|
||||
project_id: None,
|
||||
version_id: None,
|
||||
existing_loading_bar: None,
|
||||
profile_path: profile_path.clone(),
|
||||
profile_path: profile_path.to_string(),
|
||||
};
|
||||
|
||||
let backup_name = format!("ATLauncher-{}", instance_folder);
|
||||
@@ -177,7 +177,7 @@ pub async fn import_atlauncher(
|
||||
}
|
||||
|
||||
async fn import_atlauncher_unmanaged(
|
||||
profile_path: ProfilePathId,
|
||||
profile_path: &str,
|
||||
minecraft_folder: PathBuf,
|
||||
backup_name: String,
|
||||
description: CreatePackDescription,
|
||||
@@ -198,10 +198,10 @@ async fn import_atlauncher_unmanaged(
|
||||
let game_version = atinstance.id;
|
||||
|
||||
let loader_version = if mod_loader != ModLoader::Vanilla {
|
||||
crate::profile::create::get_loader_version_from_loader(
|
||||
game_version.clone(),
|
||||
crate::launcher::get_loader_version_from_profile(
|
||||
&game_version,
|
||||
mod_loader,
|
||||
Some(atinstance.launcher.loader_version.version.clone()),
|
||||
Some(&atinstance.launcher.loader_version.version),
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
@@ -209,24 +209,30 @@ async fn import_atlauncher_unmanaged(
|
||||
};
|
||||
|
||||
// Set profile data to created default profile
|
||||
crate::api::profile::edit(&profile_path, |prof| {
|
||||
prof.metadata.name = description
|
||||
crate::api::profile::edit(profile_path, |prof| {
|
||||
prof.name = description
|
||||
.override_title
|
||||
.clone()
|
||||
.unwrap_or_else(|| backup_name.to_string());
|
||||
prof.install_stage = ProfileInstallStage::PackInstalling;
|
||||
prof.metadata.linked_data = Some(LinkedData {
|
||||
project_id: description.project_id.clone(),
|
||||
version_id: description.version_id.clone(),
|
||||
locked: Some(
|
||||
description.project_id.is_some()
|
||||
&& description.version_id.is_some(),
|
||||
),
|
||||
});
|
||||
prof.metadata.icon.clone_from(&description.icon);
|
||||
prof.metadata.game_version.clone_from(&game_version);
|
||||
prof.metadata.loader_version.clone_from(&loader_version);
|
||||
prof.metadata.loader = mod_loader;
|
||||
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
prof.icon_path = description
|
||||
.icon
|
||||
.clone()
|
||||
.map(|x| x.to_string_lossy().to_string());
|
||||
prof.game_version.clone_from(&game_version);
|
||||
prof.loader_version = loader_version.clone().map(|x| x.id);
|
||||
prof.loader = mod_loader;
|
||||
|
||||
async { Ok(()) }
|
||||
})
|
||||
@@ -235,32 +241,20 @@ async fn import_atlauncher_unmanaged(
|
||||
// Moves .minecraft folder over (ie: overrides such as resourcepacks, mods, etc)
|
||||
let state = State::get().await?;
|
||||
let loading_bar = copy_dotminecraft(
|
||||
profile_path.clone(),
|
||||
profile_path,
|
||||
minecraft_folder,
|
||||
&state.io_semaphore,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(profile_val) =
|
||||
crate::api::profile::get(&profile_path, None).await?
|
||||
{
|
||||
if let Some(profile_val) = crate::api::profile::get(profile_path).await? {
|
||||
crate::launcher::install_minecraft(
|
||||
&profile_val,
|
||||
Some(loading_bar),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
{
|
||||
let state = State::get().await?;
|
||||
let mut file_watcher = state.file_watcher.write().await;
|
||||
Profile::watch_fs(
|
||||
&profile_val.get_profile_full_path().await?,
|
||||
&mut file_watcher,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
State::sync().await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2,10 +2,8 @@ use std::path::PathBuf;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::prelude::Profile;
|
||||
use crate::state::CredentialsStore;
|
||||
use crate::{
|
||||
prelude::{ModLoader, ProfilePathId},
|
||||
prelude::ModLoader,
|
||||
state::ProfileInstallStage,
|
||||
util::{
|
||||
fetch::{fetch, write_cached_icon},
|
||||
@@ -49,7 +47,7 @@ pub async fn is_valid_curseforge(instance_folder: PathBuf) -> bool {
|
||||
|
||||
pub async fn import_curseforge(
|
||||
curseforge_instance_folder: PathBuf, // instance's folder
|
||||
profile_path: ProfilePathId, // path to profile
|
||||
profile_path: &str, // path to profile
|
||||
) -> crate::Result<()> {
|
||||
// Load minecraftinstance.json
|
||||
let minecraft_instance: String = io::read_to_string(
|
||||
@@ -77,13 +75,9 @@ pub async fn import_curseforge(
|
||||
thumbnail_url: Some(thumbnail_url),
|
||||
}) = minecraft_instance.installed_modpack.clone()
|
||||
{
|
||||
let icon_bytes = fetch(
|
||||
&thumbnail_url,
|
||||
None,
|
||||
&state.fetch_semaphore,
|
||||
&CredentialsStore(None),
|
||||
)
|
||||
.await?;
|
||||
let icon_bytes =
|
||||
fetch(&thumbnail_url, None, &state.fetch_semaphore, &state.pool)
|
||||
.await?;
|
||||
let filename = thumbnail_url.rsplit('/').last();
|
||||
if let Some(filename) = filename {
|
||||
icon = Some(
|
||||
@@ -121,10 +115,10 @@ pub async fn import_curseforge(
|
||||
let mod_loader = mod_loader.unwrap_or(ModLoader::Vanilla);
|
||||
|
||||
let loader_version = if mod_loader != ModLoader::Vanilla {
|
||||
crate::profile::create::get_loader_version_from_loader(
|
||||
game_version.clone(),
|
||||
crate::launcher::get_loader_version_from_profile(
|
||||
&game_version,
|
||||
mod_loader,
|
||||
loader_version,
|
||||
loader_version.as_deref(),
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
@@ -132,31 +126,32 @@ pub async fn import_curseforge(
|
||||
};
|
||||
|
||||
// Set profile data to created default profile
|
||||
crate::api::profile::edit(&profile_path, |prof| {
|
||||
prof.metadata.name = override_title
|
||||
crate::api::profile::edit(profile_path, |prof| {
|
||||
prof.name = override_title
|
||||
.clone()
|
||||
.unwrap_or_else(|| backup_name.to_string());
|
||||
prof.install_stage = ProfileInstallStage::PackInstalling;
|
||||
prof.metadata.icon.clone_from(&icon);
|
||||
prof.metadata.game_version.clone_from(&game_version);
|
||||
prof.metadata.loader_version.clone_from(&loader_version);
|
||||
prof.metadata.loader = mod_loader;
|
||||
prof.icon_path =
|
||||
icon.clone().map(|x| x.to_string_lossy().to_string());
|
||||
prof.game_version.clone_from(&game_version);
|
||||
prof.loader_version = loader_version.clone().map(|x| x.id);
|
||||
prof.loader = mod_loader;
|
||||
|
||||
async { Ok(()) }
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
// create a vanilla profile
|
||||
crate::api::profile::edit(&profile_path, |prof| {
|
||||
prof.metadata.name = override_title
|
||||
crate::api::profile::edit(profile_path, |prof| {
|
||||
prof.name = override_title
|
||||
.clone()
|
||||
.unwrap_or_else(|| backup_name.to_string());
|
||||
prof.metadata.icon.clone_from(&icon);
|
||||
prof.metadata
|
||||
.game_version
|
||||
prof.icon_path =
|
||||
icon.clone().map(|x| x.to_string_lossy().to_string());
|
||||
prof.game_version
|
||||
.clone_from(&minecraft_instance.game_version);
|
||||
prof.metadata.loader_version = None;
|
||||
prof.metadata.loader = ModLoader::Vanilla;
|
||||
prof.loader_version = None;
|
||||
prof.loader = ModLoader::Vanilla;
|
||||
|
||||
async { Ok(()) }
|
||||
})
|
||||
@@ -166,33 +161,20 @@ pub async fn import_curseforge(
|
||||
// Copy in contained folders as overrides
|
||||
let state = State::get().await?;
|
||||
let loading_bar = copy_dotminecraft(
|
||||
profile_path.clone(),
|
||||
profile_path,
|
||||
curseforge_instance_folder,
|
||||
&state.io_semaphore,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(profile_val) =
|
||||
crate::api::profile::get(&profile_path, None).await?
|
||||
{
|
||||
if let Some(profile_val) = crate::api::profile::get(profile_path).await? {
|
||||
crate::launcher::install_minecraft(
|
||||
&profile_val,
|
||||
Some(loading_bar),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
|
||||
{
|
||||
let state = State::get().await?;
|
||||
let mut file_watcher = state.file_watcher.write().await;
|
||||
Profile::watch_fs(
|
||||
&profile_val.get_profile_full_path().await?,
|
||||
&mut file_watcher,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
State::sync().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -2,12 +2,7 @@ use std::path::PathBuf;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
prelude::{ModLoader, Profile, ProfilePathId},
|
||||
state::ProfileInstallStage,
|
||||
util::io,
|
||||
State,
|
||||
};
|
||||
use crate::{prelude::ModLoader, state::ProfileInstallStage, util::io, State};
|
||||
|
||||
use super::{copy_dotminecraft, recache_icon};
|
||||
|
||||
@@ -41,7 +36,7 @@ pub async fn is_valid_gdlauncher(instance_folder: PathBuf) -> bool {
|
||||
|
||||
pub async fn import_gdlauncher(
|
||||
gdlauncher_instance_folder: PathBuf, // instance's folder
|
||||
profile_path: ProfilePathId, // path to profile
|
||||
profile_path: &str, // path to profile
|
||||
) -> crate::Result<()> {
|
||||
// Load config.json
|
||||
let config: String =
|
||||
@@ -74,10 +69,10 @@ pub async fn import_gdlauncher(
|
||||
let loader_version = config.loader.loader_version;
|
||||
|
||||
let loader_version = if mod_loader != ModLoader::Vanilla {
|
||||
crate::profile::create::get_loader_version_from_loader(
|
||||
game_version.clone(),
|
||||
crate::launcher::get_loader_version_from_profile(
|
||||
&game_version,
|
||||
mod_loader,
|
||||
loader_version,
|
||||
loader_version.as_deref(),
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
@@ -85,15 +80,15 @@ pub async fn import_gdlauncher(
|
||||
};
|
||||
|
||||
// Set profile data to created default profile
|
||||
crate::api::profile::edit(&profile_path, |prof| {
|
||||
prof.metadata.name = override_title
|
||||
crate::api::profile::edit(profile_path, |prof| {
|
||||
prof.name = override_title
|
||||
.clone()
|
||||
.unwrap_or_else(|| backup_name.to_string());
|
||||
prof.install_stage = ProfileInstallStage::PackInstalling;
|
||||
prof.metadata.icon.clone_from(&icon);
|
||||
prof.metadata.game_version.clone_from(&game_version);
|
||||
prof.metadata.loader_version.clone_from(&loader_version);
|
||||
prof.metadata.loader = mod_loader;
|
||||
prof.icon_path = icon.clone().map(|x| x.to_string_lossy().to_string());
|
||||
prof.game_version.clone_from(&game_version);
|
||||
prof.loader_version = loader_version.clone().map(|x| x.id);
|
||||
prof.loader = mod_loader;
|
||||
|
||||
async { Ok(()) }
|
||||
})
|
||||
@@ -102,32 +97,20 @@ pub async fn import_gdlauncher(
|
||||
// Copy in contained folders as overrides
|
||||
let state = State::get().await?;
|
||||
let loading_bar = copy_dotminecraft(
|
||||
profile_path.clone(),
|
||||
profile_path,
|
||||
gdlauncher_instance_folder,
|
||||
&state.io_semaphore,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(profile_val) =
|
||||
crate::api::profile::get(&profile_path, None).await?
|
||||
{
|
||||
if let Some(profile_val) = crate::api::profile::get(profile_path).await? {
|
||||
crate::launcher::install_minecraft(
|
||||
&profile_val,
|
||||
Some(loading_bar),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
{
|
||||
let state = State::get().await?;
|
||||
let mut file_watcher = state.file_watcher.write().await;
|
||||
Profile::watch_fs(
|
||||
&profile_val.get_profile_full_path().await?,
|
||||
&mut file_watcher,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
State::sync().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -7,7 +7,6 @@ use crate::{
|
||||
import::{self, copy_dotminecraft},
|
||||
install_from::{self, CreatePackDescription, PackDependency},
|
||||
},
|
||||
prelude::{Profile, ProfilePathId},
|
||||
util::io,
|
||||
State,
|
||||
};
|
||||
@@ -176,11 +175,11 @@ async fn load_instance_cfg(file_path: &Path) -> crate::Result<MMCInstance> {
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
#[theseus_macros::debug_pin]
|
||||
|
||||
pub async fn import_mmc(
|
||||
mmc_base_path: PathBuf, // path to base mmc folder
|
||||
instance_folder: String, // instance folder in mmc_base_path
|
||||
profile_path: ProfilePathId, // path to profile
|
||||
mmc_base_path: PathBuf, // path to base mmc folder
|
||||
instance_folder: String, // instance folder in mmc_base_path
|
||||
profile_path: &str, // path to profile
|
||||
) -> crate::Result<()> {
|
||||
let mmc_instance_path = mmc_base_path
|
||||
.join("instances")
|
||||
@@ -202,13 +201,13 @@ pub async fn import_mmc(
|
||||
};
|
||||
|
||||
// Create description from instance.cfg
|
||||
let description = CreatePackDescription {
|
||||
let mut description = CreatePackDescription {
|
||||
icon,
|
||||
override_title: instance_cfg.name,
|
||||
project_id: instance_cfg.managed_pack_id,
|
||||
version_id: instance_cfg.managed_pack_version_id,
|
||||
project_id: None,
|
||||
version_id: None,
|
||||
existing_loading_bar: None,
|
||||
profile_path: profile_path.clone(),
|
||||
profile_path: profile_path.to_string(),
|
||||
};
|
||||
|
||||
// Managed pack
|
||||
@@ -217,6 +216,9 @@ pub async fn import_mmc(
|
||||
if instance_cfg.managed_pack.unwrap_or(false) {
|
||||
match instance_cfg.managed_pack_type {
|
||||
Some(MMCManagedPackType::Modrinth) => {
|
||||
description.project_id = instance_cfg.managed_pack_id;
|
||||
description.version_id = instance_cfg.managed_pack_version_id;
|
||||
|
||||
// Modrinth Managed Pack
|
||||
// Kept separate as we may in the future want to add special handling for modrinth managed packs
|
||||
let backup_name = "Imported Modrinth Modpack".to_string();
|
||||
@@ -260,7 +262,7 @@ pub async fn import_mmc(
|
||||
}
|
||||
|
||||
async fn import_mmc_unmanaged(
|
||||
profile_path: ProfilePathId,
|
||||
profile_path: &str,
|
||||
minecraft_folder: PathBuf,
|
||||
backup_name: String,
|
||||
description: CreatePackDescription,
|
||||
@@ -302,7 +304,7 @@ async fn import_mmc_unmanaged(
|
||||
|
||||
// Sets profile information to be that loaded from mmc-pack.json and instance.cfg
|
||||
install_from::set_profile_information(
|
||||
profile_path.clone(),
|
||||
profile_path.to_string(),
|
||||
&description,
|
||||
&backup_name,
|
||||
&dependencies,
|
||||
@@ -313,32 +315,20 @@ async fn import_mmc_unmanaged(
|
||||
// Moves .minecraft folder over (ie: overrides such as resourcepacks, mods, etc)
|
||||
let state = State::get().await?;
|
||||
let loading_bar = copy_dotminecraft(
|
||||
profile_path.clone(),
|
||||
profile_path,
|
||||
minecraft_folder,
|
||||
&state.io_semaphore,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(profile_val) =
|
||||
crate::api::profile::get(&profile_path, None).await?
|
||||
{
|
||||
if let Some(profile_val) = crate::api::profile::get(profile_path).await? {
|
||||
crate::launcher::install_minecraft(
|
||||
&profile_val,
|
||||
Some(loading_bar),
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
{
|
||||
let state = State::get().await?;
|
||||
let mut file_watcher = state.file_watcher.write().await;
|
||||
Profile::watch_fs(
|
||||
&profile_val.get_profile_full_path().await?,
|
||||
&mut file_watcher,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
State::sync().await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -11,8 +11,6 @@ use crate::{
|
||||
emit::{emit_loading, init_or_edit_loading},
|
||||
LoadingBarId,
|
||||
},
|
||||
prelude::ProfilePathId,
|
||||
state::Profiles,
|
||||
util::{
|
||||
fetch::{self, IoSemaphore},
|
||||
io,
|
||||
@@ -105,10 +103,10 @@ pub async fn get_importable_instances(
|
||||
|
||||
// Import an instance from a launcher type and base path
|
||||
// Note: this *deletes* the submitted empty profile
|
||||
#[theseus_macros::debug_pin]
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn import_instance(
|
||||
profile_path: ProfilePathId, // This should be a blank profile
|
||||
profile_path: &str, // This should be a blank profile
|
||||
launcher_type: ImportLauncherType,
|
||||
base_path: PathBuf,
|
||||
instance_folder: String,
|
||||
@@ -117,31 +115,31 @@ pub async fn import_instance(
|
||||
let res = match launcher_type {
|
||||
ImportLauncherType::MultiMC | ImportLauncherType::PrismLauncher => {
|
||||
mmc::import_mmc(
|
||||
base_path, // path to base mmc folder
|
||||
instance_folder, // instance folder in mmc_base_path
|
||||
profile_path.clone(), // path to profile
|
||||
base_path, // path to base mmc folder
|
||||
instance_folder, // instance folder in mmc_base_path
|
||||
profile_path, // path to profile
|
||||
)
|
||||
.await
|
||||
}
|
||||
ImportLauncherType::ATLauncher => {
|
||||
atlauncher::import_atlauncher(
|
||||
base_path, // path to atlauncher folder
|
||||
instance_folder, // instance folder in atlauncher
|
||||
profile_path.clone(), // path to profile
|
||||
base_path, // path to atlauncher folder
|
||||
instance_folder, // instance folder in atlauncher
|
||||
profile_path, // path to profile
|
||||
)
|
||||
.await
|
||||
}
|
||||
ImportLauncherType::GDLauncher => {
|
||||
gdlauncher::import_gdlauncher(
|
||||
base_path.join("instances").join(instance_folder), // path to gdlauncher folder
|
||||
profile_path.clone(), // path to profile
|
||||
profile_path, // path to profile
|
||||
)
|
||||
.await
|
||||
}
|
||||
ImportLauncherType::Curseforge => {
|
||||
curseforge::import_curseforge(
|
||||
base_path.join("Instances").join(instance_folder), // path to curseforge folder
|
||||
profile_path.clone(), // path to profile
|
||||
profile_path, // path to profile
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -158,14 +156,11 @@ pub async fn import_instance(
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
tracing::warn!("Import failed: {:?}", e);
|
||||
let _ = crate::api::profile::remove(&profile_path).await;
|
||||
let _ = crate::api::profile::remove(profile_path).await;
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Check existing managed packs for potential updates
|
||||
tokio::task::spawn(Profiles::update_modrinth_versions());
|
||||
|
||||
tracing::debug!("Completed import.");
|
||||
Ok(())
|
||||
}
|
||||
@@ -200,7 +195,7 @@ pub fn get_default_launcher_path(
|
||||
}
|
||||
|
||||
/// Checks if this PathBuf is a valid instance for the given launcher type
|
||||
#[theseus_macros::debug_pin]
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn is_valid_importable_instance(
|
||||
instance_path: PathBuf,
|
||||
@@ -224,7 +219,7 @@ pub async fn is_valid_importable_instance(
|
||||
}
|
||||
|
||||
/// Caches an image file in the filesystem into the cache directory, and returns the path to the cached file.
|
||||
#[theseus_macros::debug_pin]
|
||||
|
||||
#[tracing::instrument]
|
||||
pub async fn recache_icon(
|
||||
icon_path: PathBuf,
|
||||
@@ -252,13 +247,14 @@ pub async fn recache_icon(
|
||||
}
|
||||
|
||||
pub async fn copy_dotminecraft(
|
||||
profile_path_id: ProfilePathId,
|
||||
profile_path_id: &str,
|
||||
dotminecraft: PathBuf,
|
||||
io_semaphore: &IoSemaphore,
|
||||
existing_loading_bar: Option<LoadingBarId>,
|
||||
) -> crate::Result<LoadingBarId> {
|
||||
// Get full path to profile
|
||||
let profile_path = profile_path_id.get_full_path().await?;
|
||||
let profile_path =
|
||||
crate::api::profile::get_full_path(profile_path_id).await?;
|
||||
|
||||
// Gets all subfiles recursively in src
|
||||
let subfiles = get_all_subfiles(&dotminecraft).await?;
|
||||
@@ -298,7 +294,7 @@ pub async fn copy_dotminecraft(
|
||||
|
||||
/// Recursively get a list of all subfiles in src
|
||||
/// uses async recursion
|
||||
#[theseus_macros::debug_pin]
|
||||
|
||||
#[async_recursion::async_recursion]
|
||||
#[tracing::instrument]
|
||||
pub async fn get_all_subfiles(src: &Path) -> crate::Result<Vec<PathBuf>> {
|
||||
|
||||
Reference in New Issue
Block a user