diff --git a/apps/app-frontend/src/helpers/instance.ts b/apps/app-frontend/src/helpers/instance.ts index de112f2d27..57bbb0c75f 100644 --- a/apps/app-frontend/src/helpers/instance.ts +++ b/apps/app-frontend/src/helpers/instance.ts @@ -77,6 +77,10 @@ export async function get_content_items( return await invoke('plugin:instance|instance_get_content_items', { instanceId, cacheBehaviour }) } +export async function refresh_content_updates(instanceId: string): Promise { + return await invoke('plugin:instance|instance_refresh_content_updates', { instanceId }) +} + // Linked modpack info returned from backend export interface LinkedModpackInfo { project: Labrinth.Projects.v2.Project diff --git a/apps/app-frontend/src/pages/instance/layout.vue b/apps/app-frontend/src/pages/instance/layout.vue index c2dd0ede78..5a903e1ce5 100644 --- a/apps/app-frontend/src/pages/instance/layout.vue +++ b/apps/app-frontend/src/pages/instance/layout.vue @@ -142,7 +142,7 @@ import { isSharedInstanceUnavailableError, type SharedInstanceUnavailableReason, } from '@/helpers/install' -import { get_full_path, kill, remove, run } from '@/helpers/instance' +import { get_full_path, kill, refresh_content_updates, remove, run } from '@/helpers/instance' import { useSharedInstanceErrors } from '@/helpers/shared-instance-errors' import type { GameInstance } from '@/helpers/types' import { createInstanceShortcut, showInstanceInFolder } from '@/helpers/utils.js' @@ -194,6 +194,23 @@ useQuery( })), ) const instance = computed(() => instanceQuery.data.value) +useQuery( + computed(() => ({ + queryKey: instanceKeys.contentUpdateCheck(instanceId.value), + queryFn: async () => { + const targetInstanceId = instanceId.value + await refresh_content_updates(targetInstanceId) + await queryClient.invalidateQueries({ + queryKey: instanceKeys.content(targetInstanceId), + }) + return targetInstanceId + }, + enabled: !!instanceId.value && !offline.value && instance.value?.install_stage === 'installed', + staleTime: 10 * 60_000, + gcTime: 30 * 60_000, + retry: false, + })), +) const linkedProjectId = computed(() => instance.value?.link?.project_id ?? '') const linkedProjectQuery = useQuery( computed(() => ({ diff --git a/apps/app-frontend/src/pages/instance/query-options.ts b/apps/app-frontend/src/pages/instance/query-options.ts index 93f4ee81c8..6848ccb7ac 100644 --- a/apps/app-frontend/src/pages/instance/query-options.ts +++ b/apps/app-frontend/src/pages/instance/query-options.ts @@ -11,6 +11,8 @@ export const instanceKeys = { detail: (instanceId: string) => [...instanceKeys.all, 'summary', instanceId] as const, processes: (instanceId: string) => [...instanceKeys.all, 'processes', instanceId] as const, content: (instanceId: string) => [...instanceKeys.all, 'content', instanceId] as const, + contentUpdateCheck: (instanceId: string) => + [...instanceKeys.all, 'content-update-check', instanceId] as const, rootPath: (instanceId: string) => [...instanceKeys.detail(instanceId), 'root-path'] as const, files: (instanceId: string, path: string) => [...instanceKeys.detail(instanceId), 'files', path] as const, diff --git a/apps/app/build.rs b/apps/app/build.rs index 2d2bfc899b..0a92cd2346 100644 --- a/apps/app/build.rs +++ b/apps/app/build.rs @@ -200,6 +200,7 @@ fn main() { "instance_get_install_candidates", "instance_content", "instance_get_content_items", + "instance_refresh_content_updates", "instance_get_dependencies_as_content_items", "instance_get_linked_modpack_info", "instance_get_linked_modpack_content", diff --git a/apps/app/src/api/instance.rs b/apps/app/src/api/instance.rs index 29db061fd1..5425415d50 100644 --- a/apps/app/src/api/instance.rs +++ b/apps/app/src/api/instance.rs @@ -30,6 +30,7 @@ pub fn init() -> tauri::plugin::TauriPlugin { instance_get_install_candidates, instance_content, instance_get_content_items, + instance_refresh_content_updates, instance_get_dependencies_as_content_items, instance_get_linked_modpack_info, instance_get_linked_modpack_content, @@ -524,6 +525,11 @@ pub async fn instance_get_content_items( ) } +#[tauri::command] +pub async fn instance_refresh_content_updates(instance_id: &str) -> Result<()> { + Ok(theseus::instance::refresh_content_updates(instance_id).await?) +} + #[tauri::command] pub async fn instance_get_dependencies_as_content_items( dependencies: Vec, diff --git a/packages/app-lib/src/api/instance.rs b/packages/app-lib/src/api/instance.rs index 872020863e..c49d327d98 100644 --- a/packages/app-lib/src/api/instance.rs +++ b/packages/app-lib/src/api/instance.rs @@ -16,7 +16,7 @@ pub use self::content::{ get_content_items, get_dependencies_as_content_items, get_install_candidates, get_installed_project_ids, get_linked_modpack_content, get_linked_modpack_info, get_projects, - list_content_sets, sync_content_files, + list_content_sets, refresh_content_updates, sync_content_files, }; pub use self::export_mrpack::{ PackExportCandidate, create_mrpack_json, export_mrpack, diff --git a/packages/app-lib/src/api/instance/content.rs b/packages/app-lib/src/api/instance/content.rs index 9adb2734cb..29d2fbef27 100644 --- a/packages/app-lib/src/api/instance/content.rs +++ b/packages/app-lib/src/api/instance/content.rs @@ -74,6 +74,12 @@ pub async fn get_content_items( crate::state::list_content(instance_id, None, cache_behaviour, &state).await } +#[tracing::instrument] +pub async fn refresh_content_updates(instance_id: &str) -> crate::Result<()> { + let state = State::get().await?; + crate::state::refresh_content_updates(instance_id, &state).await +} + #[tracing::instrument] pub async fn get_linked_modpack_content( instance_id: &str, diff --git a/packages/app-lib/src/state/instances/commands/check_content_updates.rs b/packages/app-lib/src/state/instances/commands/check_content_updates.rs index 771ae806b9..3384dad5df 100644 --- a/packages/app-lib/src/state/instances/commands/check_content_updates.rs +++ b/packages/app-lib/src/state/instances/commands/check_content_updates.rs @@ -30,6 +30,36 @@ pub(crate) async fn check_content_updates( instance_id: &str, cache_behaviour: Option, state: &State, +) -> crate::Result> { + check_content_updates_with_cache_behaviours( + instance_id, + cache_behaviour, + cache_behaviour, + state, + ) + .await +} + +pub(crate) async fn refresh_content_updates( + instance_id: &str, + state: &State, +) -> crate::Result<()> { + check_content_updates_with_cache_behaviours( + instance_id, + None, + Some(CacheBehaviour::Bypass), + state, + ) + .await?; + + Ok(()) +} + +async fn check_content_updates_with_cache_behaviours( + instance_id: &str, + cache_behaviour: Option, + update_cache_behaviour: Option, + state: &State, ) -> crate::Result> { let instance = instance_rows::get_instance_by_id(instance_id, &state.pool) .await? @@ -113,7 +143,7 @@ pub(crate) async fn check_content_updates( .collect::>(); let updates = CachedEntry::get_file_update_many( &update_key_refs, - cache_behaviour, + update_cache_behaviour, &state.pool, &state.api_semaphore, ) diff --git a/packages/app-lib/src/state/instances/commands/mod.rs b/packages/app-lib/src/state/instances/commands/mod.rs index ff79b14d2d..b969a1c44b 100644 --- a/packages/app-lib/src/state/instances/commands/mod.rs +++ b/packages/app-lib/src/state/instances/commands/mod.rs @@ -38,6 +38,7 @@ mod apply_content_install; pub(crate) use self::apply_content_install::*; mod check_content_updates; +pub(crate) use self::check_content_updates::refresh_content_updates; mod apply_content_update; pub(crate) use self::apply_content_update::*; diff --git a/packages/app-lib/src/state/instances/mod.rs b/packages/app-lib/src/state/instances/mod.rs index 4a9195c1fb..5469e9e898 100644 --- a/packages/app-lib/src/state/instances/mod.rs +++ b/packages/app-lib/src/state/instances/mod.rs @@ -22,6 +22,6 @@ pub(crate) use self::commands::{ dependencies_to_content_items, get_content_projects, get_installed_project_ids_for_instance, get_instance_install_candidates, get_linked_modpack_info, list_content, list_content_sets, - list_linked_modpack_content, sync_content_files, + list_linked_modpack_content, refresh_content_updates, sync_content_files, }; pub(crate) mod watcher;