10 Commits

Author SHA1 Message Date
3ecb20afd6 chore: store db fix patch file in all patches 2025-07-08 05:15:01 +03:00
1e10f24efe fix: typo
All checks were successful
AstralRinth App build / Build (x86_64-unknown-linux-gnu, ubuntu-latest) (push) Successful in 33m50s
2025-07-08 05:06:39 +03:00
006fd7c7f5 fix: another sqlx migrations fix
Some checks failed
AstralRinth App build / Build (x86_64-unknown-linux-gnu, ubuntu-latest) (push) Has been cancelled
2025-07-08 04:59:33 +03:00
1e8e001eb8 fix: Impl. fixes for all known migration issues from modrinth authors
All checks were successful
AstralRinth App build / Build (x86_64-unknown-linux-gnu, ubuntu-latest) (push) Successful in 33m45s
2025-07-08 04:25:37 +03:00
585935c799 fix: Impl. fix for migration 20240711194701
All checks were successful
AstralRinth App build / Build (x86_64-unknown-linux-gnu, ubuntu-latest) (push) Successful in 35m18s
2025-07-08 03:42:03 +03:00
a64c3360d2 refactor: remove unnecessary code lines 2025-07-08 03:08:27 +03:00
a2b2711204 refactor: Improve update.js and RunningAppBar.vue.
All checks were successful
AstralRinth App build / Build (x86_64-unknown-linux-gnu, ubuntu-latest) (push) Successful in 38m33s
Bump to v0.10.302
2025-07-08 01:12:16 +03:00
ab57926e44 ref: Remove unused workflow steps
All checks were successful
AstralRinth App build / Build (x86_64-unknown-linux-gnu, ubuntu-latest) (push) Successful in 38m6s
2025-07-07 19:20:40 +03:00
35cd79727a Merge commit 'c47bcf665d0686db29732629b36113d3b25915af' into feature-clean
Some checks failed
AstralRinth App build / Build (universal-apple-darwin, macos-latest) (push) Has been cancelled
AstralRinth App build / Build (x86_64-pc-windows-msvc, windows-latest) (push) Has been cancelled
AstralRinth App build / Build (x86_64-unknown-linux-gnu, ubuntu-latest) (push) Has started running
2025-07-07 19:04:00 +03:00
Josiah Glosson
c47bcf665d Fix MinecraftLaunch failing in the case of a package-private main class on Java 8 (#3932)
I don't know of any mod loaders where this is the case, but better be safe than sorry
2025-07-07 15:42:38 +00:00
8 changed files with 313 additions and 159 deletions

View File

@@ -23,12 +23,13 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [macos-latest, windows-latest, ubuntu-latest] # platform: [macos-latest, windows-latest, ubuntu-latest]
platform: [ubuntu-latest]
include: include:
- platform: macos-latest # - platform: macos-latest
artifact-target-name: universal-apple-darwin # artifact-target-name: universal-apple-darwin
- platform: windows-latest # - platform: windows-latest
artifact-target-name: x86_64-pc-windows-msvc # artifact-target-name: x86_64-pc-windows-msvc
- platform: ubuntu-latest - platform: ubuntu-latest
artifact-target-name: x86_64-unknown-linux-gnu artifact-target-name: x86_64-unknown-linux-gnu
@@ -72,11 +73,11 @@ jobs:
- name: 🧰 Install dependencies - name: 🧰 Install dependencies
run: pnpm install run: pnpm install
- name: ✍️ Set up Windows code signing (jsign) # - name: ✍️ Set up Windows code signing (jsign)
if: matrix.platform == 'windows' && env.SIGN_WINDOWS_BINARIES == 'true' # if: matrix.platform == 'windows-latest' && env.SIGN_WINDOWS_BINARIES == 'true'
shell: bash # shell: bash
run: | # run: |
choco install jsign --ignore-dependencies # choco install jsign --ignore-dependencies
- name: 🗑️ Clean up cached bundles - name: 🗑️ Clean up cached bundles
shell: bash shell: bash
@@ -84,12 +85,12 @@ jobs:
rm -rf target/release/bundle rm -rf target/release/bundle
rm -rf target/*/release/bundle || true rm -rf target/*/release/bundle || true
- name: 🔨 Build macOS app # - name: 🔨 Build macOS app
if: matrix.platform == 'macos-latest' # if: matrix.platform == 'macos-latest'
run: pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-release.conf.json # run: pnpm --filter=@modrinth/app run tauri build --target universal-apple-darwin --config tauri-release.conf.json
env: # env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} # TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} # TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: 🔨 Build Linux app - name: 🔨 Build Linux app
if: matrix.platform == 'ubuntu-latest' if: matrix.platform == 'ubuntu-latest'
@@ -98,15 +99,15 @@ jobs:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: 🔨 Build Windows app # - name: 🔨 Build Windows app
if: matrix.platform == 'windows-latest' # if: matrix.platform == 'windows-latest'
shell: pwsh # shell: pwsh
run: | # run: |
$env:JAVA_HOME = "$env:JAVA_HOME_11_X64" # $env:JAVA_HOME = "$env:JAVA_HOME_11_X64"
pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json --verbose --bundles 'nsis' # pnpm --filter=@modrinth/app run tauri build --config tauri-release.conf.json --verbose --bundles 'nsis'
env: # env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} # TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} # TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
- name: 📤 Upload app bundles - name: 📤 Upload app bundles
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3

View File

@@ -38,7 +38,7 @@
</div> </div>
<div v-if="updateState"> <div v-if="updateState">
<a> <a>
<Button class="download" :disabled="installState" @click="confirmUpdating(), getRemote(false, false)"> <Button class="download" :disabled="installState" @click="initUpdateModal(), getRemote(false)">
<DownloadIcon /> <DownloadIcon />
{{ {{
installState installState
@@ -48,7 +48,7 @@
</Button> </Button>
</a> </a>
</div> </div>
<ModalWrapper ref="confirmUpdate" :has-to-type="false" header="Request to update the AstralRinth launcher"> <ModalWrapper ref="updateModalView" :has-to-type="false" header="Request to update the AstralRinth launcher">
<div class="modal-body"> <div class="modal-body">
<div class="markdown-body"> <div class="markdown-body">
<p>The new version of the AstralRinth launcher is available.</p> <p>The new version of the AstralRinth launcher is available.</p>
@@ -66,14 +66,30 @@
<p class="cosmic inline-fix">v{{ version }}</p> <p class="cosmic inline-fix">v{{ version }}</p>
</span> </span>
<div class="button-group push-right"> <div class="button-group push-right">
<Button class="download-modal" @click="confirmUpdate.hide()"> <Button class="updater-modal" @click="updateModalView.hide()">
Decline</Button> Cancel</Button>
<Button class="download-modal" @click="approveUpdate()"> <Button class="updater-modal" @click="initDownload()">
Accept Download file
</Button> </Button>
</div> </div>
</div> </div>
</ModalWrapper> </ModalWrapper>
<ModalWrapper ref="updateRequestFailView" :has-to-type="false" header="Failed to request a file from the server :(">
<div class="modal-body">
<div class="markdown-body">
<p><strong>Error occurred</strong></p>
<p>Unfortunately, the program was unable to download the file from our servers.</p>
<p>Please try downloading it yourself from <a href="https://me.astralium.su/get/ar" target="_blank" rel="noopener noreferrer">Git Astralium</a> if there are any updates available.</p>
</div>
<span>Local AstralRinth
<p class="cosmic inline-fix">v{{ version }}</p>
</span>
</div>
<div class="button-group push-right">
<Button class="updater-modal" @click="updateRequestFailView.hide()">
Close</Button>
</div>
</ModalWrapper>
</div> </div>
<transition name="download"> <transition name="download">
<Card v-if="showCard === true && currentLoadingBars.length > 0" ref="card" class="info-card"> <Card v-if="showCard === true && currentLoadingBars.length > 0" ref="card" class="info-card">
@@ -129,18 +145,22 @@ const version = await getVersion()
import { installState, getRemote, updateState } from '@/helpers/update.js' import { installState, getRemote, updateState } from '@/helpers/update.js'
import ModalWrapper from './modal/ModalWrapper.vue' import ModalWrapper from './modal/ModalWrapper.vue'
const confirmUpdate = ref(null) const updateModalView = ref(null)
const updateRequestFailView = ref(null)
const confirmUpdating = async () => { const initUpdateModal = async () => {
confirmUpdate.value.show() updateModalView.value.show()
} }
const approveUpdate = async () => { const initDownload = async () => {
confirmUpdate.value.hide() updateModalView.value.hide()
await getRemote(true, true) const result = await getRemote(true);
if (!result) {
updateRequestFailView.value.show()
}
} }
await getRemote(true, false) await getRemote(false)
const router = useRouter() const router = useRouter()
const card = ref(null) const card = ref(null)
@@ -375,7 +395,7 @@ onBeforeUnmount(() => {
text-shadow: #26065e; text-shadow: #26065e;
} }
.download-modal { .updater-modal {
color: #3e8cde; color: #3e8cde;
padding: var(--gap-sm) var(--gap-lg); padding: var(--gap-sm) var(--gap-lg);
text-decoration: none; text-decoration: none;
@@ -386,9 +406,9 @@ onBeforeUnmount(() => {
transition: color 0.35s ease; transition: color 0.35s ease;
} }
.download-modal:hover, .updater-modal:hover,
.download-modal:focus, .updater-modal:focus,
.download-modal:active { .updater-modal:active {
color: #10fae5; color: #10fae5;
text-shadow: #26065e; text-shadow: #26065e;
} }

View File

@@ -2,21 +2,19 @@ import { ref } from 'vue'
import { getVersion } from '@tauri-apps/api/app' import { getVersion } from '@tauri-apps/api/app'
import { getArtifact, getOS } from '@/helpers/utils.js' import { getArtifact, getOS } from '@/helpers/utils.js'
export const allowState = ref(false) export const allowState = ref(false)
export const installState = ref(false) export const installState = ref(false)
export const updateState = ref(false) export const updateState = ref(false)
export const latestBetaCommitTruncatedSha = ref('')
export const latestBetaCommitLink = ref('')
export const launcherUrl = 'https://www.astralium.su/get/ar'
const os = ref('') const currentOS = ref('')
const releaseLink = `https://git.astralium.su/api/v1/repos/didirus/AstralRinth/releases/latest` const releaseLink = `https://git.astralium.su/api/v1/repos/didirus/AstralRinth/releases/latest`
const failedFetch = [`Failed to fetch remote releases:`, `Failed to fetch remote commits:`] const failedFetch = [`Failed to fetch remote releases:`, `Failed to fetch remote commits:`]
const osNames = ['macos', 'windows', 'linux']
const macExtension = `.dmg` // MacOS file type for download const osList = ['macos', 'windows', 'linux']
const windowsExtension = `.msi` // Windows file type for download const macExtensionList = ['.app', '.dmg']
const blacklistedBuilds = [ const windowsExtensionList = ['.exe', '.msi']
const blacklistPrefixes = [
`dev`, `dev`,
`nightly`, `nightly`,
`dirty`, `dirty`,
@@ -26,110 +24,73 @@ const blacklistedBuilds = [
`dirty_nightly`, `dirty_nightly`,
] // This is blacklisted builds for download. For example, file.startsWith('dev') is not allowed. ] // This is blacklisted builds for download. For example, file.startsWith('dev') is not allowed.
/** export async function getRemote(isDownloadState) {
* Asynchronous function to get remote data and handle updates and downloads. var releaseData = null;
* var result = false;
* @param {boolean} elementIdBool - Indicates whether to disable an element ID. try {
* @param {boolean} downloadArtifactBool - Indicates whether to download an artifact. const response = await fetch(releaseLink);
*/ if (!response.ok) {
export async function getRemote(elementIdBool, downloadArtifactBool) { throw new Error(response.status);
fetch(releaseLink) }
.then((response) => { const remoteData = await response.json();
if (!response.ok) { currentOS.value = await getOS();
throw new Error(response.status) const remoteLatestReleaseTag = remoteData.tag_name;
} releaseData = document.getElementById('releaseData');
return response.json() const remoteVersion = releaseData ? (releaseData.textContent = remoteLatestReleaseTag) : remoteLatestReleaseTag;
})
.then(async (data) => {
os.value = await getOS()
const latestRelease = data.name
let remoteVersion = undefined
if (!elementIdBool) { if (osList.includes(currentOS.value.toLowerCase())) {
const releaseData = document.getElementById('releaseData') const localVersion = await getVersion();
if (releaseData == null) { const isUpdateAvailable = !remoteVersion.includes(localVersion);
console.error('Release data element not found.')
return false
}
releaseData.textContent = latestRelease
remoteVersion = `${releaseData.textContent}`
} else {
remoteVersion = latestRelease
}
if (osNames.includes(os.value.toLowerCase())) {
if (remoteVersion.startsWith('v' + await getVersion())) {
updateState.value = false
allowState.value = false
} else {
updateState.value = true
allowState.value = true
}
} else {
updateState.value = false
allowState.value = false
}
console.log('Update available state is', updateState.value)
console.log('Remote version is', remoteVersion)
console.log('Local version is', await getVersion())
console.log('Operating System is', os.value)
if (downloadArtifactBool) { updateState.value = isUpdateAvailable;
installState.value = true allowState.value = isUpdateAvailable;
const builds = data.assets } else {
const fileName = getInstaller(getExtension(), builds) updateState.value = false;
if (fileName != null) { allowState.value = false;
await getArtifact(fileName[1], fileName[0], os.value, true) }
} if (isDownloadState) {
installState.value = false installState.value = true;
} const builds = remoteData.assets;
}) const fileName = getInstaller(getExtension(), builds);
.catch((error) => { result = fileName ? await getArtifact(fileName[1], fileName[0], currentOS.value, true) : false;
console.error(failedFetch[0], error) installState.value = false;
if (!elementIdBool) { }
const errorData = document.getElementById('releaseData')
if (errorData) {
errorData.textContent = `${error.message}`
}
updateState.value = false
allowState.value = false
installState.value = false
}
})
}
/** console.log('Update available state is', updateState.value);
* Retrieves the installer for a specific operating system. console.log('Remote version is', remoteVersion);
* console.log('Local version is', await getVersion());
* @param {string} osExtension - The file extension of the installer. console.log('Operating System is', currentOS.value);
* @param {Array} builds - The list of builds. return result;
* @return {Array|null} An array containing the installer name and URL if found, or null if not found. } catch (error) {
*/ console.error(failedFetch[0], error);
function getInstaller(osExtension, builds) { if (!releaseData) {
for (let i of builds) { const errorData = document.getElementById('releaseData');
let blacklistedItem = false if (errorData) {
blacklistedBuilds.forEach((item) => { errorData.textContent = `${error.message}`;
if (i.name.startsWith(item)) {
return (blacklistedItem = true)
} }
}) updateState.value = false;
if (i.name.endsWith(osExtension) && !blacklistedItem) { allowState.value = false;
console.log(i.browser_download_url) installState.value = false;
return [i.name, i.browser_download_url]
} }
} }
return null
} }
/** function getInstaller(osExtension, builds) {
* A function to get the extension based on the operating system. console.log(osExtension, builds)
* for (const build of builds) {
* @return {string} The extension based on the operating system. if (blacklistPrefixes.some(prefix => build.name.startsWith(prefix))) {
*/ continue;
function getExtension() { }
if (os.value.toLowerCase() == osNames[0]) { if (osExtension.some(ext => build.name.endsWith(ext))) {
return macExtension console.log(build.name, build.browser_download_url);
} else if (os.value.toLowerCase() == osNames[1]) { return [build.name, build.browser_download_url];
return windowsExtension }
} }
return null return null;
} }
function getExtension() {
return osList.find(osName => osName === currentOS.value.toLowerCase())?.endsWith('macos')
? macExtensionList
: windowsExtensionList;
}

View File

@@ -34,9 +34,6 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
// let update_fut = updater.check(); // let update_fut = updater.check();
// tracing::info!("Initializing app state...");
State::init().await?;
// let check_bar = theseus::init_loading( // let check_bar = theseus::init_loading(
// theseus::LoadingBarType::CheckingForUpdates, // theseus::LoadingBarType::CheckingForUpdates,
// 1.0, // 1.0,
@@ -87,7 +84,7 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
// #[cfg(not(feature = "updater"))] // #[cfg(not(feature = "updater"))]
// { // {
// } // }
tracing::info!("Initializing app state...");
State::init().await?; State::init().await?;
tracing::info!("AstralRinth state successfully initialized."); tracing::info!("AstralRinth state successfully initialized.");
let state = State::get().await?; let state = State::get().await?;
@@ -164,10 +161,10 @@ fn main() {
let mut builder = tauri::Builder::default(); let mut builder = tauri::Builder::default();
#[cfg(feature = "updater")] // #[cfg(feature = "updater")]
{ // {
builder = builder.plugin(tauri_plugin_updater::Builder::new().build()); // builder = builder.plugin(tauri_plugin_updater::Builder::new().build());
} // }
builder = builder builder = builder
.plugin(tauri_plugin_single_instance::init(|app, args, _cwd| { .plugin(tauri_plugin_single_instance::init(|app, args, _cwd| {

View File

@@ -41,7 +41,7 @@
] ]
}, },
"productName": "AstralRinth App", "productName": "AstralRinth App",
"version": "0.10.3", "version": "0.10.302",
"mainBinaryName": "AstralRinth App", "mainBinaryName": "AstralRinth App",
"identifier": "AstralRinthApp", "identifier": "AstralRinthApp",
"plugins": { "plugins": {

View File

@@ -123,6 +123,7 @@ public final class MinecraftLaunch {
setAccessible0.setAccessible(true); setAccessible0.setAccessible(true);
setAccessible0.invoke(object, true); setAccessible0.invoke(object, true);
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
object.setAccessible(true);
} }
return object; return object;
} }

View File

@@ -3,6 +3,7 @@ use sqlx::sqlite::{
SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions, SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions,
}; };
use sqlx::{Pool, Sqlite}; use sqlx::{Pool, Sqlite};
use tokio::time::Instant;
use std::str::FromStr; use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
@@ -17,8 +18,10 @@ pub(crate) async fn connect() -> crate::Result<Pool<Sqlite>> {
crate::util::io::create_dir_all(&settings_dir).await?; crate::util::io::create_dir_all(&settings_dir).await?;
} }
let uri = format!("sqlite:{}", settings_dir.join("app.db").display()); let db_path = settings_dir.join("app.db");
let db_exists = db_path.exists();
let uri = format!("sqlite:{}", db_path.display());
let conn_options = SqliteConnectOptions::from_str(&uri)? let conn_options = SqliteConnectOptions::from_str(&uri)?
.busy_timeout(Duration::from_secs(30)) .busy_timeout(Duration::from_secs(30))
.journal_mode(SqliteJournalMode::Wal) .journal_mode(SqliteJournalMode::Wal)
@@ -30,8 +33,16 @@ 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?; sqlx::migrate!().run(&pool).await?;
if !db_exists {
fix_modrinth_issued_migrations(&pool).await?;
}
if let Err(err) = stale_data_cleanup(&pool).await { if let Err(err) = stale_data_cleanup(&pool).await {
tracing::warn!( tracing::warn!(
"Failed to clean up stale data from state database: {err}" "Failed to clean up stale data from state database: {err}"
@@ -62,3 +73,63 @@ async fn stale_data_cleanup(pool: &Pool<Sqlite>) -> crate::Result<()> {
Ok(()) Ok(())
} }
/*
// Patch by AstralRinth - 08.07.2025
Problem files:
/packages/app-lib/migrations/20240711194701_init.sql !eol
/packages/app-lib/migrations/20240813205023_drop-active-unique.sql !eol
/packages/app-lib/migrations/20240930001852_disable-personalized-ads.sql !eol
/packages/app-lib/migrations/20241222013857_feature-flags.sql !eol
*/
async fn fix_modrinth_issued_migrations(
pool: &Pool<Sqlite>,
) -> crate::Result<()> {
let started = Instant::now();
tracing::info!("Fixing modrinth issued migrations");
sqlx::query(
r#"
UPDATE "_sqlx_migrations"
SET checksum = X'e973512979feac07e415405291eefafc1ef0bd89454958ad66f5452c381db8679c20ffadab55194ecf6ba8ec4ca2db21'
WHERE version = '20240711194701';
"#,
)
.execute(pool)
.await?;
tracing::info!("⚙️ Fixed first migration");
sqlx::query(
r#"
UPDATE "_sqlx_migrations"
SET checksum = X'5b53534a7ffd74eebede234222be47e1d37bd0cc5fee4475212491b0c0379c16e3079e08eee0af959b1fa20835eeb206'
WHERE version = '20240813205023';
"#,
)
.execute(pool)
.await?;
tracing::info!("⚙️ Fixed second migration");
sqlx::query(
r#"
UPDATE "_sqlx_migrations"
SET checksum = X'c0de804f171b5530010edae087a6e75645c0e90177e28365f935c9fdd9a5c68e24850b8c1498e386a379d525d520bc57'
WHERE version = '20240930001852';
"#,
)
.execute(pool)
.await?;
tracing::info!("⚙️ Fixed third migration");
sqlx::query(
r#"
UPDATE "_sqlx_migrations"
SET checksum = X'c17542cb989a0466153e695bfa4717f8970feee185ca186a2caa1f2f6c5d4adb990ab97c26cacfbbe09c39ac81551704'
WHERE version = '20241222013857';
"#,
)
.execute(pool)
.await?;
tracing::info!("⚙️ Fixed fourth migration");
let elapsed = started.elapsed();
tracing::info!(
"✅ Fixed all known modrinth-issued migrations in {:.2?}",
elapsed
);
Ok(())
}

View File

@@ -0,0 +1,103 @@
diff --git a/packages/app-lib/src/state/db.rs b/packages/app-lib/src/state/db.rs
index 14c53d81..607a345f 100644
--- a/packages/app-lib/src/state/db.rs
+++ b/packages/app-lib/src/state/db.rs
@@ -3,6 +3,7 @@ use sqlx::sqlite::{
SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions,
};
use sqlx::{Pool, Sqlite};
+use tokio::time::Instant;
use std::str::FromStr;
use std::time::Duration;
@@ -17,8 +18,10 @@ pub(crate) async fn connect() -> crate::Result<Pool<Sqlite>> {
crate::util::io::create_dir_all(&settings_dir).await?;
}
- let uri = format!("sqlite:{}", settings_dir.join("app.db").display());
+ let db_path = settings_dir.join("app.db");
+ let db_exists = db_path.exists();
+ let uri = format!("sqlite:{}", db_path.display());
let conn_options = SqliteConnectOptions::from_str(&uri)?
.busy_timeout(Duration::from_secs(30))
.journal_mode(SqliteJournalMode::Wal)
@@ -30,10 +33,16 @@ pub(crate) async fn connect() -> crate::Result<Pool<Sqlite>> {
.connect_with(conn_options)
.await?;
- fix_migration_20240711194701(&pool).await?; // Patch by AstralRinth - 08.07.2025
+ 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}"
@@ -66,8 +75,17 @@ async fn stale_data_cleanup(pool: &Pool<Sqlite>) -> crate::Result<()> {
}
/*
// Patch by AstralRinth - 08.07.2025
+Problem files:
+/packages/app-lib/migrations/20240711194701_init.sql !eol
+/packages/app-lib/migrations/20240813205023_drop-active-unique.sql !eol
+/packages/app-lib/migrations/20240930001852_disable-personalized-ads.sql !eol
+/packages/app-lib/migrations/20241222013857_feature-flags.sql !eol
*/
-async fn fix_migration_20240711194701(pool: &Pool<Sqlite>) -> crate::Result<()> {
+async fn fix_modrinth_issued_migrations(
+ pool: &Pool<Sqlite>,
+) -> crate::Result<()> {
+ let started = Instant::now();
+ tracing::info!("Fixing modrinth issued migrations");
sqlx::query(
r#"
UPDATE "_sqlx_migrations"
@@ -77,5 +95,41 @@ async fn fix_migration_20240711194701(pool: &Pool<Sqlite>) -> crate::Result<()>
)
.execute(pool)
.await?;
+ tracing::info!("⚙️ Fixed first migration");
+ sqlx::query(
+ r#"
+ UPDATE "_sqlx_migrations"
+ SET checksum = X'5b53534a7ffd74eebede234222be47e1d37bd0cc5fee4475212491b0c0379c16e3079e08eee0af959b1fa20835eeb206'
+ WHERE version = '20240813205023';
+ "#,
+ )
+ .execute(pool)
+ .await?;
+ tracing::info!("⚙️ Fixed second migration");
+ sqlx::query(
+ r#"
+ UPDATE "_sqlx_migrations"
+ SET checksum = X'c0de804f171b5530010edae087a6e75645c0e90177e28365f935c9fdd9a5c68e24850b8c1498e386a379d525d520bc57'
+ WHERE version = '20240930001852';
+ "#,
+ )
+ .execute(pool)
+ .await?;
+ tracing::info!("⚙️ Fixed third migration");
+ sqlx::query(
+ r#"
+ UPDATE "_sqlx_migrations"
+ SET checksum = X'c17542cb989a0466153e695bfa4717f8970feee185ca186a2caa1f2f6c5d4adb990ab97c26cacfbbe09c39ac81551704'
+ WHERE version = '20241222013857';
+ "#,
+ )
+ .execute(pool)
+ .await?;
+ tracing::info!("⚙️ Fixed fourth migration");
+ let elapsed = started.elapsed();
+ tracing::info!(
+ "✅ Fixed all known modrinth-issued migrations in {:.2?}",
+ elapsed
+ );
Ok(())
}