forked from didirus/AstralRinth
Merge pull request 'feature-another-migration-fix' (#5) from feature-another-migration-fix into beta
Reviewed-on: didirus/AstralRinth#5
This commit is contained in:
29
.github/workflows/astralrinth-build.yml
vendored
29
.github/workflows/astralrinth-build.yml
vendored
@@ -42,6 +42,35 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- name: 🔍 Validate Git config does not introduce CRLF
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "🔍 Checking Git config for CRLF settings..."
|
||||||
|
|
||||||
|
autocrlf=$(git config --get core.autocrlf || echo "unset")
|
||||||
|
eol_setting=$(git config --get core.eol || echo "unset")
|
||||||
|
|
||||||
|
echo "core.autocrlf = $autocrlf"
|
||||||
|
echo "core.eol = $eol_setting"
|
||||||
|
|
||||||
|
if [ "$autocrlf" = "true" ]; then
|
||||||
|
echo "⚠️ WARNING: core.autocrlf is set to 'true'. Consider setting it to 'input' or 'false'."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$eol_setting" = "crlf" ]; then
|
||||||
|
echo "⚠️ WARNING: core.eol is set to 'crlf'. Consider unsetting it or setting to 'lf'."
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: 🔍 Check migration files line endings (LF only)
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "🔍 Scanning migration SQL files for CR characters (\\r)..."
|
||||||
|
if grep -Iq $'\r' packages/app-lib/migrations/*.sql; then
|
||||||
|
echo "❌ ERROR: Some migration files contain CR (\\r) characters — expected only LF line endings."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ All migration files use LF line endings"
|
||||||
|
|
||||||
- name: 🧰 Setup Rust toolchain
|
- name: 🧰 Setup Rust toolchain
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -161,11 +161,11 @@ async function setupApp() {
|
|||||||
|
|
||||||
initAnalytics()
|
initAnalytics()
|
||||||
if (!telemetry) {
|
if (!telemetry) {
|
||||||
console.info("[AR] Telemetry disabled by default (Hard patched).")
|
console.info("[AR] • Telemetry disabled by default (Hard patched).")
|
||||||
optOutAnalytics()
|
optOutAnalytics()
|
||||||
}
|
}
|
||||||
if (!personalized_ads) {
|
if (!personalized_ads) {
|
||||||
console.info("[AR] Personalized ads disabled by default (Hard patched).")
|
console.info("[AR] • Personalized ads disabled by default (Hard patched).")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev) debugAnalytics()
|
if (dev) debugAnalytics()
|
||||||
|
|||||||
@@ -18,11 +18,15 @@ import { cancel_directory_change } from '@/helpers/settings.ts'
|
|||||||
import { install } from '@/helpers/profile.js'
|
import { install } from '@/helpers/profile.js'
|
||||||
import { trackEvent } from '@/helpers/analytics'
|
import { trackEvent } from '@/helpers/analytics'
|
||||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||||
|
import { applyMigrationFix } from '@/helpers/utils.js'
|
||||||
|
|
||||||
const errorModal = ref()
|
const errorModal = ref()
|
||||||
const error = ref()
|
const error = ref()
|
||||||
const closable = ref(true)
|
const closable = ref(true)
|
||||||
const errorCollapsed = ref(false)
|
const errorCollapsed = ref(false)
|
||||||
|
const language = ref('en')
|
||||||
|
const migrationFixSuccess = ref(null) // null | true | false
|
||||||
|
const migrationFixCallbackModel = ref()
|
||||||
|
|
||||||
const title = ref('An error occurred')
|
const title = ref('An error occurred')
|
||||||
const errorType = ref('unknown')
|
const errorType = ref('unknown')
|
||||||
@@ -148,6 +152,25 @@ async function copyToClipboard(text) {
|
|||||||
copied.value = false
|
copied.value = false
|
||||||
}, 3000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleLanguage() {
|
||||||
|
language.value = language.value === 'en' ? 'ru' : 'en'
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onApplyMigrationFix(eol) {
|
||||||
|
console.log(`[AR] • Attempting to apply migration ${eol.toUpperCase()} fix`)
|
||||||
|
try {
|
||||||
|
const result = await applyMigrationFix(eol)
|
||||||
|
migrationFixSuccess.value = result === true
|
||||||
|
console.log(`[AR] • Successfully applied migration ${eol.toUpperCase()} fix`, result)
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[AR] • Failed to apply migration fix:`, err)
|
||||||
|
migrationFixSuccess.value = false
|
||||||
|
} finally {
|
||||||
|
migrationFixCallbackModel.value?.show?.()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -298,6 +321,11 @@ async function copyToClipboard(text) {
|
|||||||
<template v-if="copied"> <CheckIcon class="text-green" /> Copied! </template>
|
<template v-if="copied"> <CheckIcon class="text-green" /> Copied! </template>
|
||||||
<template v-else> <CopyIcon /> Copy debug info </template>
|
<template v-else> <CopyIcon /> Copy debug info </template>
|
||||||
</button>
|
</button>
|
||||||
|
<ButtonStyled color="brand">
|
||||||
|
<a href="https://me.astralium.su/get/ar/help" target="_blank" rel="noopener noreferrer">
|
||||||
|
<button>Get AstralRinth support</button>
|
||||||
|
</a>
|
||||||
|
</ButtonStyled>
|
||||||
</ButtonStyled>
|
</ButtonStyled>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="hasDebugInfo">
|
<template v-if="hasDebugInfo">
|
||||||
@@ -316,9 +344,116 @@ async function copyToClipboard(text) {
|
|||||||
<pre class="m-0 px-4 py-3 bg-bg rounded-none">{{ debugInfo }}</pre>
|
<pre class="m-0 px-4 py-3 bg-bg rounded-none">{{ debugInfo }}</pre>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="notice">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<h3 v-if="language === 'en'" class="notice__title">⚠️ Important Notice ⚠️</h3>
|
||||||
|
<h3 v-if="language === 'ru'" class="notice__title">⚠️ Важное уведомление ⚠️</h3>
|
||||||
|
<ButtonStyled>
|
||||||
|
<button @click="toggleLanguage">
|
||||||
|
{{ language === 'en' ? '📖 Русский' : '📖 English' }}
|
||||||
|
</button>
|
||||||
|
</ButtonStyled>
|
||||||
|
</div>
|
||||||
|
<p v-if="language === 'en'" class="notice__text">
|
||||||
|
We're experiencing an issue with our database migration system due to differences in how different operating systems handle line endings. This might cause problems with our app's functionality.
|
||||||
|
</p>
|
||||||
|
<p v-if="language === 'en'" class="notice__text">
|
||||||
|
<strong>What's happening?</strong> When we build our app, we use a system that checks the integrity of our database migrations. However, this system can get confused when it encounters different line endings (like CRLF vs LF) used by different operating systems. This can lead to errors and make our app unusable.
|
||||||
|
</p>
|
||||||
|
<p v-if="language === 'en'" class="notice__text">
|
||||||
|
<strong>Why is this happening?</strong> This issue is caused by a combination of factors, including different operating systems handling line endings differently, Git's line ending conversion settings, and our app's build process.
|
||||||
|
</p>
|
||||||
|
<p v-if="language === 'en'" class="notice__text">
|
||||||
|
<strong>What are we doing about it?</strong> We're working to resolve this issue and ensure that our app works smoothly for all users. In the meantime, we apologize for any inconvenience this might cause and appreciate your patience and understanding.
|
||||||
|
</p>
|
||||||
|
<p v-if="language === 'ru'" class="notice__text">
|
||||||
|
Мы сталкиваемся с проблемой в нашей системе миграции базы данных из-за различий в том, как разные операционные системы обрабатывают окончания строк. Это может вызвать проблемы с функциональностью нашего приложения.
|
||||||
|
</p>
|
||||||
|
<p v-if="language === 'ru'" class="notice__text">
|
||||||
|
<strong>Что происходит?</strong> Когда мы строим наше приложение, мы используем систему, которая проверяет целостность наших миграций базы данных. Однако эта система может сбиваться, когда сталкивается с различными окончаниями строк (например, CRLF против LF), используемыми разными операционными системами. Это может привести к ошибкам и сделать наше приложение неработоспособным.
|
||||||
|
</p>
|
||||||
|
<p v-if="language === 'ru'" class="notice__text">
|
||||||
|
<strong>Почему это происходит?</strong> Эта проблема вызвана сочетанием факторов, включая различную обработку окончаний строк разными операционными системами, настройки преобразования окончаний строк в Git и процесс сборки нашего приложения.
|
||||||
|
</p>
|
||||||
|
<p v-if="language === 'ru'" class="notice__text">
|
||||||
|
<strong>Что мы с этим делаем?</strong> Мы работаем над решением этой проблемы и обеспечением бесперебойной работы нашего приложения для всех пользователей. В это время мы извиняемся за возможные неудобства и благодарим вас за терпение и понимание.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<h2 class="text-lg font-bold text-contrast">
|
||||||
|
<template v-if="language === 'en'">Possible fix in real time:</template>
|
||||||
|
<template v-if="language === 'ru'">Возможное исправление в реальном времени:</template>
|
||||||
|
</h2>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<ul class="flex flex-col gap-3">
|
||||||
|
<li>
|
||||||
|
<ButtonStyled color="purple">
|
||||||
|
<button
|
||||||
|
:title="language === 'en'
|
||||||
|
? 'Convert all line endings in migration files to LF (Unix-style: \\n)'
|
||||||
|
: 'Преобразовать все окончания строк в файлах миграций в LF (Unix-стиль: \\n)'"
|
||||||
|
aria-label="LF"
|
||||||
|
@click="onApplyMigrationFix('lf')"
|
||||||
|
>
|
||||||
|
{{ language === 'en' ? 'Apply LF Migration Fix' : 'Применить исправление миграции LF' }}
|
||||||
|
</button>
|
||||||
|
</ButtonStyled>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<ButtonStyled color="purple">
|
||||||
|
<button
|
||||||
|
:title="language === 'en'
|
||||||
|
? 'Convert all line endings in migration files to CRLF (Windows-style: \\r\\n)'
|
||||||
|
: 'Преобразовать все окончания строк в файлах миграций в CRLF (Windows-стиль: \\r\\n)'"
|
||||||
|
aria-label="CRLF"
|
||||||
|
@click="onApplyMigrationFix('crlf')"
|
||||||
|
>
|
||||||
|
{{ language === 'en' ? 'Apply CRLF Migration Fix' : 'Применить исправление миграции CRLF' }}
|
||||||
|
</button>
|
||||||
|
</ButtonStyled>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</ModalWrapper>
|
</ModalWrapper>
|
||||||
|
<ModalWrapper
|
||||||
|
ref="migrationFixCallbackModel"
|
||||||
|
:header="language === 'en'
|
||||||
|
? '💡 Migration fix report'
|
||||||
|
: '💡 Отчет об исправлении миграции'"
|
||||||
|
:closable="closable">
|
||||||
|
<div class="modal-body">
|
||||||
|
<h2 class="text-lg font-bold text-contrast space-y-2">
|
||||||
|
<template v-if="migrationFixSuccess === true">
|
||||||
|
<p class="flex items-center gap-2 text-green-600">
|
||||||
|
✅
|
||||||
|
{{ language === 'en'
|
||||||
|
? 'The migration fix has been applied successfully. Please restart the launcher and try to log in to the game :)'
|
||||||
|
: 'Исправление миграции успешно применено. Пожалуйста, перезапустите лаунчер и попробуйте снова авторизоваться в игре :)' }}
|
||||||
|
</p>
|
||||||
|
<p class="mt-2 text-sm text-gray-600">
|
||||||
|
{{ language === 'en'
|
||||||
|
? 'If the problem persists, please try the other fix.'
|
||||||
|
: 'Если проблема сохраняется, пожалуйста, попробуйте другой способ.' }}
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="migrationFixSuccess === false">
|
||||||
|
<p class="flex items-center gap-2 text-red-600">
|
||||||
|
❌
|
||||||
|
{{ language === 'en'
|
||||||
|
? 'The migration fix failed or had no effect.'
|
||||||
|
: 'Исправление миграции не было успешно применено или не имело эффекта.' }}
|
||||||
|
</p>
|
||||||
|
<p class="mt-2 text-sm text-gray-600">
|
||||||
|
{{ language === 'en'
|
||||||
|
? 'If the problem persists, please try the other fix.'
|
||||||
|
: 'Если проблема сохраняется, пожалуйста, попробуйте другой способ.' }}
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -10,11 +10,17 @@ export async function getOS() {
|
|||||||
return await invoke('plugin:utils|get_os')
|
return await invoke('plugin:utils|get_os')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [AR] Feature
|
||||||
export async function getArtifact(downloadurl, filename, ostype, autoupdatesupported) {
|
export async function getArtifact(downloadurl, filename, ostype, autoupdatesupported) {
|
||||||
console.log('Downloading build', downloadurl, filename, ostype, autoupdatesupported)
|
console.log('Downloading build', downloadurl, filename, ostype, autoupdatesupported)
|
||||||
return await invoke('plugin:utils|get_artifact', { downloadurl, filename, ostype, autoupdatesupported })
|
return await invoke('plugin:utils|get_artifact', { downloadurl, filename, ostype, autoupdatesupported })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [AR] Patch fix
|
||||||
|
export async function applyMigrationFix(eol) {
|
||||||
|
return await invoke('plugin:utils|apply_migration_fix', { eol })
|
||||||
|
}
|
||||||
|
|
||||||
export async function openPath(path) {
|
export async function openPath(path) {
|
||||||
return await invoke('plugin:utils|open_path', { path })
|
return await invoke('plugin:utils|open_path', { path })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ fn main() {
|
|||||||
"utils",
|
"utils",
|
||||||
InlinedPlugin::new()
|
InlinedPlugin::new()
|
||||||
.commands(&[
|
.commands(&[
|
||||||
|
"apply_migration_fix",
|
||||||
"get_artifact",
|
"get_artifact",
|
||||||
"get_os",
|
"get_os",
|
||||||
"should_disable_mouseover",
|
"should_disable_mouseover",
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ use dashmap::DashMap;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use theseus::prelude::canonicalize;
|
use theseus::prelude::canonicalize;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
use theseus::util::utils;
|
||||||
|
|
||||||
pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
||||||
tauri::plugin::Builder::new("utils")
|
tauri::plugin::Builder::new("utils")
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
apply_migration_fix,
|
||||||
get_artifact,
|
get_artifact,
|
||||||
get_os,
|
get_os,
|
||||||
should_disable_mouseover,
|
should_disable_mouseover,
|
||||||
@@ -27,9 +29,17 @@ pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [AR] Patch fix
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn apply_migration_fix(eol: &str) -> Result<bool> {
|
||||||
|
let result = utils::apply_migration_fix(eol).await?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [AR] Feature
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn get_artifact(downloadurl: &str, filename: &str, ostype: &str, autoupdatesupported: bool) -> Result<()> {
|
pub async fn get_artifact(downloadurl: &str, filename: &str, ostype: &str, autoupdatesupported: bool) -> Result<()> {
|
||||||
theseus::download::init_download(downloadurl, filename, ostype, autoupdatesupported).await;
|
let _ = utils::init_download(downloadurl, filename, ostype, autoupdatesupported).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"productName": "AstralRinth App",
|
"productName": "AstralRinth App",
|
||||||
"version": "0.10.302",
|
"version": "0.10.303",
|
||||||
"mainBinaryName": "AstralRinth App",
|
"mainBinaryName": "AstralRinth App",
|
||||||
"identifier": "AstralRinthApp",
|
"identifier": "AstralRinthApp",
|
||||||
"plugins": {
|
"plugins": {
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,8 +12,8 @@ pub mod pack;
|
|||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod profile;
|
pub mod profile;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
pub mod update; // [AR] Feature
|
||||||
pub mod tags;
|
pub mod tags;
|
||||||
pub mod download; // AstralRinth
|
|
||||||
pub mod worlds;
|
pub mod worlds;
|
||||||
|
|
||||||
pub mod data {
|
pub mod data {
|
||||||
|
|||||||
42
packages/app-lib/src/api/update.rs
Normal file
42
packages/app-lib/src/api/update.rs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
use reqwest;
|
||||||
|
use tokio::fs::File as AsyncFile;
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
use tokio::process::Command;
|
||||||
|
|
||||||
|
pub(crate) 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("[AR] • 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!("[AR] • 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("[AR] • 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("[AR] • Failed to execute command");
|
||||||
|
} else {
|
||||||
|
status = Command::new(".")
|
||||||
|
.arg(full_path.to_str().unwrap_or_default())
|
||||||
|
.status()
|
||||||
|
.await
|
||||||
|
.expect("[AR] • Failed to execute command");
|
||||||
|
}
|
||||||
|
if status.success() {
|
||||||
|
println!("[AR] • File opened successfully!");
|
||||||
|
} else {
|
||||||
|
eprintln!("[AR] • Failed to open the file. Exit code: {:?}", status.code());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ and launching Modrinth mod packs
|
|||||||
#![deny(unused_must_use)]
|
#![deny(unused_must_use)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod util;
|
pub mod util; // [AR] Refactor
|
||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod config;
|
mod config;
|
||||||
|
|||||||
@@ -1,18 +1,31 @@
|
|||||||
use crate::state::DirectoryInfo;
|
use crate::state::DirectoryInfo;
|
||||||
|
use crate::ErrorKind;
|
||||||
use sqlx::sqlite::{
|
use sqlx::sqlite::{
|
||||||
SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions,
|
SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions,
|
||||||
};
|
};
|
||||||
use sqlx::{Pool, Sqlite};
|
use sqlx::{Pool, Sqlite};
|
||||||
use std::env;
|
use std::collections::HashMap;
|
||||||
use tokio::time::Instant;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use tokio::time::Instant;
|
||||||
|
|
||||||
pub(crate) async fn connect() -> crate::Result<Pool<Sqlite>> {
|
pub(crate) async fn connect() -> crate::Result<Pool<Sqlite>> {
|
||||||
|
let pool = connect_without_migrate().await?;
|
||||||
|
|
||||||
|
sqlx::migrate!().run(&pool).await?;
|
||||||
|
|
||||||
|
if let Err(err) = stale_data_cleanup(&pool).await {
|
||||||
|
tracing::warn!(
|
||||||
|
"Failed to clean up stale data from state database: {err}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(pool)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn connect_without_migrate() -> crate::Result<Pool<Sqlite>> {
|
||||||
let settings_dir = DirectoryInfo::get_initial_settings_dir().ok_or(
|
let settings_dir = DirectoryInfo::get_initial_settings_dir().ok_or(
|
||||||
crate::ErrorKind::FSError(
|
ErrorKind::FSError("Could not find valid config dir".to_string()),
|
||||||
"Could not find valid config dir".to_string(),
|
|
||||||
),
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if !settings_dir.exists() {
|
if !settings_dir.exists() {
|
||||||
@@ -20,7 +33,6 @@ pub(crate) async fn connect() -> crate::Result<Pool<Sqlite>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let db_path = settings_dir.join("app.db");
|
let db_path = settings_dir.join("app.db");
|
||||||
let db_exists = db_path.exists();
|
|
||||||
|
|
||||||
let uri = format!("sqlite:{}", db_path.display());
|
let uri = format!("sqlite:{}", db_path.display());
|
||||||
let conn_options = SqliteConnectOptions::from_str(&uri)?
|
let conn_options = SqliteConnectOptions::from_str(&uri)?
|
||||||
@@ -34,22 +46,6 @@ pub(crate) async fn connect() -> crate::Result<Pool<Sqlite>> {
|
|||||||
.connect_with(conn_options)
|
.connect_with(conn_options)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if db_exists {
|
|
||||||
fix_modrinth_issued_migrations(&pool).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlx::migrate!().run(&pool).await?;
|
|
||||||
|
|
||||||
if !db_exists {
|
|
||||||
fix_modrinth_issued_migrations(&pool).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(err) = stale_data_cleanup(&pool).await {
|
|
||||||
tracing::warn!(
|
|
||||||
"Failed to clean up stale data from state database: {err}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(pool)
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,72 +71,103 @@ async fn stale_data_cleanup(pool: &Pool<Sqlite>) -> crate::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
// Patch by AstralRinth - 08.07.2025
|
// Patched by AstralRinth
|
||||||
Problem files:
|
Problem files, view detailed information in .gitattributes:
|
||||||
/packages/app-lib/migrations/20240711194701_init.sql !eol
|
/packages/app-lib/migrations/20240711194701_init.sql !eol
|
||||||
|
CRLF -> 4c47e326f16f2b1efca548076ce638d4c90dd610172fe48c47d6de9bc46ef1c5abeadfdea05041ddd72c3819fa10c040
|
||||||
|
LF -> e973512979feac07e415405291eefafc1ef0bd89454958ad66f5452c381db8679c20ffadab55194ecf6ba8ec4ca2db21
|
||||||
/packages/app-lib/migrations/20240813205023_drop-active-unique.sql !eol
|
/packages/app-lib/migrations/20240813205023_drop-active-unique.sql !eol
|
||||||
|
CRLF -> 10f4a494df6fd791a093cc61401ecf3f9750fa6b97aa304ab06e29671e446586240910ffbf806f6ddc484a756770dde9
|
||||||
|
LF -> 5b53534a7ffd74eebede234222be47e1d37bd0cc5fee4475212491b0c0379c16e3079e08eee0af959b1fa20835eeb206
|
||||||
/packages/app-lib/migrations/20240930001852_disable-personalized-ads.sql !eol
|
/packages/app-lib/migrations/20240930001852_disable-personalized-ads.sql !eol
|
||||||
|
CRLF -> c8028ec3a2e61d15586e2f69ad6c6be5ac03b95918c2014cefb183ed6c254a52aad6f9ce98cda13ad545da3398574702
|
||||||
|
LF -> c0de804f171b5530010edae087a6e75645c0e90177e28365f935c9fdd9a5c68e24850b8c1498e386a379d525d520bc57
|
||||||
/packages/app-lib/migrations/20241222013857_feature-flags.sql !eol
|
/packages/app-lib/migrations/20241222013857_feature-flags.sql !eol
|
||||||
|
CRLF -> f8c55065e2563fa4738976eb13a052ae4c28da8d33143185550f6e1cee394a3243b1dca090b3e8bc50a93a8286a78c09
|
||||||
|
LF -> c17542cb989a0466153e695bfa4717f8970feee185ca186a2caa1f2f6c5d4adb990ab97c26cacfbbe09c39ac81551704
|
||||||
*/
|
*/
|
||||||
async fn fix_modrinth_issued_migrations(
|
pub(crate) async fn fix_version_hash(
|
||||||
pool: &Pool<Sqlite>,
|
eol: &str,
|
||||||
) -> crate::Result<()> {
|
) -> crate::Result<bool> {
|
||||||
let arch = env::consts::ARCH;
|
let started = Instant::now();
|
||||||
let os = env::consts::OS;
|
|
||||||
|
|
||||||
tracing::info!("Running on OS: {}, ARCH: {}", os, arch);
|
// Create connection to the database without migrations
|
||||||
|
let pool = connect_without_migrate().await?;
|
||||||
|
tracing::info!("⚙️ Patching Modrinth corrupted migration checksums using EOL standard: {eol}");
|
||||||
|
|
||||||
if os == "windows" && arch == "x86_64" {
|
// validate EOL input
|
||||||
tracing::warn!("🛑 Skipping migration checksum fix on Windows x86_64 (runtime-detected)");
|
if eol != "lf" && eol != "crlf" {
|
||||||
return Ok(());
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let started = Instant::now();
|
// [eol][version] -> checksum
|
||||||
tracing::info!("Fixing modrinth issued migrations");
|
let checksums: HashMap<(&str, &str), &str> = HashMap::from([
|
||||||
sqlx::query(
|
(
|
||||||
|
("lf", "20240711194701"),
|
||||||
|
"e973512979feac07e415405291eefafc1ef0bd89454958ad66f5452c381db8679c20ffadab55194ecf6ba8ec4ca2db21",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
("crlf", "20240711194701"),
|
||||||
|
"4c47e326f16f2b1efca548076ce638d4c90dd610172fe48c47d6de9bc46ef1c5abeadfdea05041ddd72c3819fa10c040",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
("lf", "20240813205023"),
|
||||||
|
"5b53534a7ffd74eebede234222be47e1d37bd0cc5fee4475212491b0c0379c16e3079e08eee0af959b1fa20835eeb206",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
("crlf", "20240813205023"),
|
||||||
|
"10f4a494df6fd791a093cc61401ecf3f9750fa6b97aa304ab06e29671e446586240910ffbf806f6ddc484a756770dde9",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
("lf", "20240930001852"),
|
||||||
|
"c0de804f171b5530010edae087a6e75645c0e90177e28365f935c9fdd9a5c68e24850b8c1498e386a379d525d520bc57",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
("crlf", "20240930001852"),
|
||||||
|
"c8028ec3a2e61d15586e2f69ad6c6be5ac03b95918c2014cefb183ed6c254a52aad6f9ce98cda13ad545da3398574702",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
("lf", "20241222013857"),
|
||||||
|
"c17542cb989a0466153e695bfa4717f8970feee185ca186a2caa1f2f6c5d4adb990ab97c26cacfbbe09c39ac81551704",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
("crlf", "20241222013857"),
|
||||||
|
"f8c55065e2563fa4738976eb13a052ae4c28da8d33143185550f6e1cee394a3243b1dca090b3e8bc50a93a8286a78c09",
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let mut changed = false;
|
||||||
|
|
||||||
|
for ((eol_key, version), checksum) in checksums.iter() {
|
||||||
|
if *eol_key != eol {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing::info!(
|
||||||
|
"⏳ Patching checksum for migration {version} ({})",
|
||||||
|
eol.to_uppercase()
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = sqlx::query(&format!(
|
||||||
r#"
|
r#"
|
||||||
UPDATE "_sqlx_migrations"
|
UPDATE "_sqlx_migrations"
|
||||||
SET checksum = X'e973512979feac07e415405291eefafc1ef0bd89454958ad66f5452c381db8679c20ffadab55194ecf6ba8ec4ca2db21'
|
SET checksum = X'{checksum}'
|
||||||
WHERE version = '20240711194701';
|
WHERE version = '{version}';
|
||||||
"#,
|
"#
|
||||||
)
|
))
|
||||||
.execute(pool)
|
.execute(&pool)
|
||||||
.await?;
|
.await?;
|
||||||
tracing::info!("⚙️ Fixed checksum for first migration");
|
|
||||||
sqlx::query(
|
if result.rows_affected() > 0 {
|
||||||
r#"
|
changed = true;
|
||||||
UPDATE "_sqlx_migrations"
|
}
|
||||||
SET checksum = X'5b53534a7ffd74eebede234222be47e1d37bd0cc5fee4475212491b0c0379c16e3079e08eee0af959b1fa20835eeb206'
|
}
|
||||||
WHERE version = '20240813205023';
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.execute(pool)
|
|
||||||
.await?;
|
|
||||||
tracing::info!("⚙️ Fixed checksum for second migration");
|
|
||||||
sqlx::query(
|
|
||||||
r#"
|
|
||||||
UPDATE "_sqlx_migrations"
|
|
||||||
SET checksum = X'c0de804f171b5530010edae087a6e75645c0e90177e28365f935c9fdd9a5c68e24850b8c1498e386a379d525d520bc57'
|
|
||||||
WHERE version = '20240930001852';
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.execute(pool)
|
|
||||||
.await?;
|
|
||||||
tracing::info!("⚙️ Fixed checksum for third migration");
|
|
||||||
sqlx::query(
|
|
||||||
r#"
|
|
||||||
UPDATE "_sqlx_migrations"
|
|
||||||
SET checksum = X'c17542cb989a0466153e695bfa4717f8970feee185ca186a2caa1f2f6c5d4adb990ab97c26cacfbbe09c39ac81551704'
|
|
||||||
WHERE version = '20241222013857';
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.execute(pool)
|
|
||||||
.await?;
|
|
||||||
tracing::info!("⚙️ Fixed checksum for fourth migration");
|
|
||||||
let elapsed = started.elapsed();
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"✅ Fixed all known Modrinth checksums for migrations in {:.2?}",
|
"✅ Checksum patching completed in {:.2?} (changes: {})",
|
||||||
elapsed
|
started.elapsed(),
|
||||||
|
changed
|
||||||
);
|
);
|
||||||
Ok(())
|
|
||||||
|
Ok(changed)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
|
///
|
||||||
|
/// [AR] Feature
|
||||||
|
///
|
||||||
|
use crate::Result;
|
||||||
|
use crate::api::update;
|
||||||
|
use crate::state::db;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::process;
|
||||||
use tokio::io;
|
use tokio::io;
|
||||||
|
|
||||||
/*
|
|
||||||
AstralRinth Utils
|
|
||||||
*/
|
|
||||||
const PACKAGE_JSON_CONTENT: &str =
|
const PACKAGE_JSON_CONTENT: &str =
|
||||||
// include_str!("../../../../apps/app-frontend/package.json");
|
// include_str!("../../../../apps/app-frontend/package.json");
|
||||||
include_str!("../../../../apps/app/tauri.conf.json");
|
include_str!("../../../../apps/app/tauri.conf.json");
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Launcher {
|
pub struct Launcher {
|
||||||
pub version: String
|
pub version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_package_json() -> io::Result<Launcher> {
|
pub fn read_package_json() -> io::Result<Launcher> {
|
||||||
@@ -19,3 +23,41 @@ pub fn read_package_json() -> io::Result<Launcher> {
|
|||||||
|
|
||||||
Ok(launcher)
|
Ok(launcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn apply_migration_fix(eol: &str) -> Result<bool> {
|
||||||
|
tracing::info!("[AR] • Attempting to apply migration fix");
|
||||||
|
let patched = db::fix_version_hash(eol).await?;
|
||||||
|
if patched {
|
||||||
|
tracing::info!("[AR] • Successfully applied migration fix");
|
||||||
|
} else {
|
||||||
|
tracing::error!("[AR] • Failed to apply migration fix");
|
||||||
|
}
|
||||||
|
Ok(patched)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn init_download(
|
||||||
|
download_url: &str,
|
||||||
|
local_filename: &str,
|
||||||
|
os_type: &str,
|
||||||
|
auto_update_supported: bool,
|
||||||
|
) -> Result<()> {
|
||||||
|
println!("[AR] • Initialize downloading from • {:?}", download_url);
|
||||||
|
println!("[AR] • Save local file name • {:?}", local_filename);
|
||||||
|
if let Err(e) = update::download_file(
|
||||||
|
download_url,
|
||||||
|
local_filename,
|
||||||
|
os_type,
|
||||||
|
auto_update_supported,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
eprintln!(
|
||||||
|
"[AR] • An error occurred! Failed to download the file: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("[AR] • Code finishes without errors.");
|
||||||
|
process::exit(0)
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user