Skip to content

Commit cd65af4

Browse files
committed
Support importing from arbitrary paths
1 parent 9552497 commit cd65af4

File tree

9 files changed

+357
-220
lines changed

9 files changed

+357
-220
lines changed

crates/backend/src/backend_handler.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,8 +1055,8 @@ impl BackendState {
10551055
}
10561056
}
10571057
},
1058-
MessageToBackend::GetImportFromOtherLauncherPaths { channel } => {
1059-
let result = crate::launcher_import::discover_instances_from_other_launchers();
1058+
MessageToBackend::GetImportFromOtherLauncherJob { channel, launcher, path } => {
1059+
let result = crate::launcher_import::get_import_from_other_launcher_job(launcher, path);
10601060
_ = channel.send(result);
10611061
},
10621062
MessageToBackend::GetSyncState { channel } => {
@@ -1491,8 +1491,8 @@ impl BackendState {
14911491
MessageToBackend::InstallUpdate { update, modal_action } => {
14921492
tokio::task::spawn(crate::update::install_update(self.redirecting_http_client.clone(), self.directories.clone(), self.send.clone(), update, modal_action));
14931493
},
1494-
MessageToBackend::ImportFromOtherLauncher { launcher, import_accounts, import_instances, modal_action } => {
1495-
crate::launcher_import::import_from_other_launcher(self, launcher, import_accounts, import_instances, modal_action).await;
1494+
MessageToBackend::ImportFromOtherLauncher { launcher, import_job, modal_action } => {
1495+
crate::launcher_import::import_from_other_launcher(self, launcher, import_job, modal_action).await;
14961496
},
14971497
MessageToBackend::GetAccountSkin { account, result } => {
14981498
let backend = self.clone();

crates/backend/src/launcher_import/atlauncher.rs

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::{path::{Path, PathBuf}, str::FromStr};
1+
use std::{path::{Path, PathBuf}, str::FromStr, sync::Arc};
22
use auth::{credentials::AccountCredentials, models::{TokenWithExpiry, XstsToken}, secret::PlatformSecretStorage};
3-
use bridge::modal_action::{ModalAction, ProgressTracker};
3+
use bridge::{import::ImportFromOtherLauncherJob, modal_action::{ModalAction, ProgressTracker}};
44
use chrono::DateTime;
55
use log::debug;
66
use schema::{instance::{InstanceConfiguration, InstanceMemoryConfiguration, InstanceWrapperCommandConfiguration}, loader::Loader};
@@ -230,52 +230,45 @@ struct AtLauncherXstsAuth {
230230
display_claims: AtLauncherDisplayClaims,
231231
}
232232

233-
234233
#[derive(Debug, Deserialize)]
235234
// #[serde(rename_all = "case")]
236235
struct AtLauncherDisplayClaims {
237236
xui: Vec<AtLauncherDisplayClaim>,
238237
}
239238

240-
241239
#[derive(Debug, Deserialize)]
242240
// #[serde(rename_all = "case")]
243241
struct AtLauncherDisplayClaim {
244242
uhs: String,
245243
}
246244

247-
248-
249-
250-
pub async fn import_from_atlauncher(backend: &BackendState, path: &Path, import_accounts: bool, import_instance: bool, modal_action: ModalAction) {
251-
let Ok(launcher_config_bytes) = std::fs::read(path.join("configs/ATLauncher.json")) else {
245+
pub async fn import_from_atlauncher(backend: &BackendState, import_job: ImportFromOtherLauncherJob, modal_action: ModalAction) {
246+
let Ok(launcher_config_bytes) = std::fs::read(import_job.root.join("configs/ATLauncher.json")) else {
252247
return;
253248
};
254249
let launcher_config = serde_json::from_slice::<AtLauncherConfig>(&launcher_config_bytes).expect("Failed to parse to json");
255-
// log::debug!("Launcher config: {}", launcher_config.is_some());
256250

257-
if import_accounts {
258-
import_accounts_from_atlauncher(backend, path, &launcher_config, &modal_action).await;
259-
}
260-
if import_instance {
261-
import_instances_from_atlauncher(backend, path, &launcher_config, &modal_action);
262-
}
251+
import_accounts_from_atlauncher(backend, &import_job, &launcher_config, &modal_action).await;
252+
import_instances_from_atlauncher(backend, &import_job, &launcher_config, &modal_action);
263253
}
264254

265-
async fn import_accounts_from_atlauncher(backend: &BackendState, path: &Path, launcher_config: &AtLauncherConfig, modal_action: &ModalAction) {
255+
async fn import_accounts_from_atlauncher(backend: &BackendState, import_job: &ImportFromOtherLauncherJob, launcher_config: &AtLauncherConfig, modal_action: &ModalAction) {
256+
if !import_job.import_accounts {
257+
return;
258+
}
259+
266260
let tracker = ProgressTracker::new("Reading accounts.json".into(), backend.send.clone());
267261
modal_action.trackers.push(tracker.clone());
268262
tracker.notify();
269263

270-
let accounts_path = path.join("configs/accounts.json");
264+
let accounts_path = import_job.root.join("configs/accounts.json");
271265
let Ok(accounts_bytes) = std::fs::read(&accounts_path) else {
272266
return;
273267
};
274268

275269
let Ok(accounts_json) = serde_json::from_slice::<Vec<AtLauncherAccount>>(&accounts_bytes) else {
276270
return;
277271
};
278-
// let accounts_json = serde_json::from_slice::<Vec<AtLauncherAccount>>(&accounts_bytes).expect("Failed to read account file");
279272

280273
let secret_storage = match backend.secret_storage.get_or_init(PlatformSecretStorage::new).await {
281274
Ok(secret_storage) => secret_storage,
@@ -348,7 +341,7 @@ async fn import_accounts_from_atlauncher(backend: &BackendState, path: &Path, la
348341
struct AtLauncherInstanceToImport {
349342
pandora_path: PathBuf,
350343
config_path: PathBuf,
351-
folder: PathBuf,
344+
folder: Arc<Path>,
352345
}
353346

354347
fn try_load_from_atlauncher(config_path: &Path, launcher_config: &AtLauncherConfig) -> anyhow::Result<InstanceConfiguration> {
@@ -384,24 +377,18 @@ fn try_load_from_atlauncher(config_path: &Path, launcher_config: &AtLauncherConf
384377
Ok(configuration)
385378
}
386379

387-
fn import_instances_from_atlauncher(backend: &BackendState, path: &Path, launcher_config: &AtLauncherConfig, modal_action: &ModalAction) {
380+
fn import_instances_from_atlauncher(backend: &BackendState, import_job: &ImportFromOtherLauncherJob, launcher_config: &AtLauncherConfig, modal_action: &ModalAction) {
381+
if import_job.paths.is_empty() {
382+
return;
383+
}
384+
388385
let all_tracker = ProgressTracker::new("Importing instances".into(), backend.send.clone());
389386
modal_action.trackers.push(all_tracker.clone());
390387
all_tracker.notify();
391388

392-
let Ok(read_dir) = std::fs::read_dir(path.join("instances")) else {
393-
all_tracker.set_finished(bridge::modal_action::ProgressTrackerFinishType::Error);
394-
all_tracker.notify();
395-
return;
396-
};
397-
398389
let mut to_import = Vec::new();
399390

400-
for entry in read_dir {
401-
let Ok(entry) = entry else {
402-
continue;
403-
};
404-
let folder = entry.path();
391+
for folder in import_job.paths.iter() {
405392
if !folder.is_dir() {
406393
continue;
407394
}
@@ -425,7 +412,7 @@ fn import_instances_from_atlauncher(backend: &BackendState, path: &Path, launche
425412
to_import.push(AtLauncherInstanceToImport {
426413
pandora_path,
427414
config_path: atlauncher_instance_cfg,
428-
folder,
415+
folder: folder.clone(),
429416
});
430417
}
431418

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::path::Path;
1+
use std::{path::Path, sync::Arc};
22

3-
use bridge::{import::{ImportFromOtherLauncher, ImportFromOtherLaunchers, OtherLauncher}, modal_action::ModalAction};
3+
use bridge::{import::{ImportFromOtherLauncherJob, OtherLauncher}, modal_action::ModalAction};
44
use schema::instance::InstanceConfiguration;
55
use crate::{BackendState, launcher_import::{
66
modrinth::{import_instances_from_modrinth, read_profiles_from_modrinth_db},
@@ -13,39 +13,56 @@ mod multimc;
1313
mod modrinth;
1414
mod atlauncher;
1515

16-
pub fn discover_instances_from_other_launchers() -> ImportFromOtherLaunchers {
17-
let mut imports = ImportFromOtherLaunchers::default();
18-
19-
let Some(base_dirs) = directories::BaseDirs::new() else {
20-
return imports;
21-
};
22-
let data_dir = base_dirs.data_dir();
23-
24-
let prism_instances = data_dir.join("PrismLauncher").join("instances");
25-
imports.imports[OtherLauncher::Prism] = from_subfolders(&prism_instances, &|path| {
26-
path.join("instance.cfg").exists() && path.join("mmc-pack.json").exists()
27-
});
28-
29-
let multimc_instances = data_dir.join("multimc").join("instances");
30-
imports.imports[OtherLauncher::MultiMC] = from_subfolders(&multimc_instances, &|path| {
31-
path.join("instance.cfg").exists() && path.join("mmc-pack.json").exists()
32-
});
33-
34-
if let Ok(import) = read_profiles_from_modrinth_db(data_dir) {
35-
imports.imports[OtherLauncher::Modrinth] = import;
16+
pub fn get_import_from_other_launcher_job(other_launcher: OtherLauncher, path: Arc<Path>) -> Option<ImportFromOtherLauncherJob> {
17+
if !path.is_dir() {
18+
return None;
3619
}
20+
match other_launcher {
21+
OtherLauncher::Prism | OtherLauncher::MultiMC => {
22+
if !path.join("prismlauncher.cfg").is_file() && !path.join("multimc.cfg").is_file() {
23+
return None;
24+
}
25+
Some(ImportFromOtherLauncherJob {
26+
import_accounts: path.join("accounts.json").is_file(),
27+
paths: collect_subfolders_matching(&path.join("instances"), &|path| {
28+
path.join("instance.cfg").exists() && path.join("mmc-pack.json").exists()
29+
}),
30+
root: path,
31+
})
32+
},
33+
OtherLauncher::Modrinth => {
34+
let paths = match read_profiles_from_modrinth_db(&path) {
35+
Ok(paths) => paths?,
36+
Err(err) => {
37+
log::error!("Unable to read modrinth profile database: {err}");
38+
return None;
39+
},
40+
};
3741

38-
let atlauncher_instances = data_dir.join("atlauncher").join("instances");
39-
imports.imports[OtherLauncher::ATLauncher] = from_subfolders(&atlauncher_instances, &|path| {
40-
path.join("instance.json").exists()
41-
});
42-
43-
imports
42+
Some(ImportFromOtherLauncherJob {
43+
import_accounts: false,
44+
paths,
45+
root: path,
46+
})
47+
},
48+
OtherLauncher::ATLauncher => {
49+
if !path.join("configs/ATLauncher.json").is_file() {
50+
return None;
51+
}
52+
Some(ImportFromOtherLauncherJob {
53+
import_accounts: path.join("configs/accounts.json").is_file(),
54+
paths: collect_subfolders_matching(&path.join("instances"), &|path| {
55+
path.join("instance.json").exists()
56+
}),
57+
root: path,
58+
})
59+
},
60+
}
4461
}
4562

46-
fn from_subfolders(folder: &Path, check: &dyn Fn(&Path) -> bool) -> Option<ImportFromOtherLauncher> {
63+
fn collect_subfolders_matching(folder: &Path, check: &dyn Fn(&Path) -> bool) -> Vec<Arc<Path>> {
4764
let Ok(read_dir) = std::fs::read_dir(folder) else {
48-
return None;
65+
return Vec::new();
4966
};
5067
let mut paths = Vec::new();
5168
for entry in read_dir {
@@ -59,12 +76,9 @@ fn from_subfolders(folder: &Path, check: &dyn Fn(&Path) -> bool) -> Option<Impor
5976
if !(check)(&path) {
6077
continue;
6178
}
62-
paths.push(path);
79+
paths.push(path.into());
6380
}
64-
Some(ImportFromOtherLauncher {
65-
can_import_accounts: true,
66-
paths,
67-
})
81+
paths
6882
}
6983

7084
pub fn try_load_from_other_launcher_formats(folder: &Path) -> Option<InstanceConfiguration> {
@@ -77,33 +91,20 @@ pub fn try_load_from_other_launcher_formats(folder: &Path) -> Option<InstanceCon
7791
None
7892
}
7993

80-
pub async fn import_from_other_launcher(backend: &BackendState, launcher: OtherLauncher, import_accounts: bool, import_instances: bool, modal_action: ModalAction) {
81-
let Some(base_dirs) = directories::BaseDirs::new() else {
82-
return;
83-
};
84-
let data_dir = base_dirs.data_dir();
94+
pub async fn import_from_other_launcher(backend: &BackendState, launcher: OtherLauncher, import_job: ImportFromOtherLauncherJob, modal_action: ModalAction) {
8595

8696
match launcher {
87-
OtherLauncher::Prism => {
88-
let prism = data_dir.join("PrismLauncher");
89-
import_from_multimc(backend, &prism, import_accounts, import_instances, modal_action).await;
97+
OtherLauncher::Prism | OtherLauncher::MultiMC => {
98+
import_from_multimc(backend, import_job, modal_action).await;
9099
},
91100
OtherLauncher::Modrinth => {
92-
if import_instances {
93-
let modrinth = data_dir.join("ModrinthApp");
94-
if let Err(err) = import_instances_from_modrinth(backend, &modrinth, &modal_action) {
95-
log::error!("Sqlite error while importing from modrinth: {err}");
96-
modal_action.set_error_message("Sqlite error while importing from modrinth, see logs for more info".into());
97-
}
101+
if let Err(err) = import_instances_from_modrinth(backend, import_job, &modal_action) {
102+
log::error!("Sqlite error while importing from modrinth: {err}");
103+
modal_action.set_error_message("Sqlite error while importing from modrinth, see logs for more info".into());
98104
}
99105
},
100-
OtherLauncher::MultiMC => {
101-
let multimc = data_dir.join("multimc");
102-
import_from_multimc(backend, &multimc, import_accounts, import_instances, modal_action).await;
103-
},
104106
OtherLauncher::ATLauncher => {
105-
let atlauncher = data_dir.join("atlauncher");
106-
import_from_atlauncher(backend, &atlauncher, import_accounts, import_instances, modal_action).await;
107+
import_from_atlauncher(backend, import_job, modal_action).await;
107108
}
108109
}
109110
}

0 commit comments

Comments
 (0)