refactor(ipc): complete tauri-specta typed-IPC cutover, contract guards, and layering cleanup (#1230)

This commit is contained in:
Psychotoxical
2026-07-04 16:00:31 +02:00
committed by GitHub
parent fdbb9deac6
commit 77ab95170d
199 changed files with 3691 additions and 1252 deletions
@@ -12,6 +12,12 @@ import { cancelledDownloads, useOfflineJobStore } from '@/features/offline/store
import { useFavoritesOfflineSyncStore } from '@/features/offline/store/favoritesOfflineSyncStore';
import { useLocalPlaybackStore } from '@/store/localPlaybackStore';
import { getMediaDir } from '@/lib/media/mediaDir';
import {
cancelOfflineDownloads,
clearOfflineCancel,
deleteMediaFile,
pruneEmptyMediaTierDirs,
} from '@/lib/api/syncfs';
import { resolveIndexKey, serverIndexKeyForProfile } from '@/lib/server/serverIndexKey';
import { FAVORITES_OFFLINE_JOB_ID } from '@/features/offline/utils/favoritesOfflineConstants';
import { isActiveServerReachable } from '@/lib/network/activeServerReachability';
@@ -49,9 +55,9 @@ function cancelInFlightFavoritesDownloads(): void {
cancelledDownloads.add(FAVORITES_OFFLINE_JOB_ID);
const downloadIds = rustDownloadIdsForFavoritesJobs();
if (downloadIds.length > 0) {
invoke('cancel_offline_downloads', { downloadIds }).catch(() => {});
cancelOfflineDownloads({ downloadIds }).catch(() => {});
for (const id of downloadIds) {
invoke('clear_offline_cancel', { downloadId: id }).catch(() => {});
clearOfflineCancel({ downloadId: id }).catch(() => {});
}
}
activeFavoritesDownloadId = null;
@@ -149,10 +155,10 @@ async function pruneOrphanFavoriteAuto(
if (entry.tier !== 'favorite-auto') continue;
if (!entryBelongsToServer(entry, serverId)) continue;
if (targetIds.has(entry.trackId)) continue;
await invoke('delete_media_file', { localPath: entry.localPath, mediaDir }).catch(() => {});
await deleteMediaFile({ localPath: entry.localPath, mediaDir }).catch(() => {});
lp.removeEntry(entry.trackId, entry.serverIndexKey, 'favorite-unstar-prune');
}
await invoke('prune_empty_media_tier_dirs', { tier: 'favorite-auto', mediaDir }).catch(() => {});
await pruneEmptyMediaTierDirs({ tier: 'favorite-auto', mediaDir }).catch(() => {});
}
export async function disableFavoritesOfflineSync(): Promise<void> {
@@ -284,8 +290,8 @@ async function runFavoritesOfflineSyncOneServer(serverId: string, token: number)
jobStore.setState(state => ({
jobs: state.jobs.filter(j => j.albumId !== FAVORITES_OFFLINE_JOB_ID),
}));
invoke('cancel_offline_downloads', { downloadIds: [downloadId] }).catch(() => {});
invoke('clear_offline_cancel', { downloadId }).catch(() => {});
cancelOfflineDownloads({ downloadIds: [downloadId] }).catch(() => {});
clearOfflineCancel({ downloadId }).catch(() => {});
activeFavoritesDownloadId = null;
return;
}
@@ -329,7 +335,7 @@ async function runFavoritesOfflineSyncOneServer(serverId: string, token: number)
|| cancelledDownloads.has(FAVORITES_OFFLINE_JOB_ID)
|| !targetIds.has(song.id)
) {
await invoke('delete_media_file', { localPath: res.path, mediaDir }).catch(() => {});
await deleteMediaFile({ localPath: res.path, mediaDir }).catch(() => {});
return { song, error: 'CANCELLED' };
}
useLocalPlaybackStore.getState().upsertEntry({
@@ -371,10 +377,10 @@ async function runFavoritesOfflineSyncOneServer(serverId: string, token: number)
),
}));
if (activeFavoritesDownloadId === downloadId) {
invoke('clear_offline_cancel', { downloadId }).catch(() => {});
clearOfflineCancel({ downloadId }).catch(() => {});
activeFavoritesDownloadId = null;
}
await invoke('prune_empty_media_tier_dirs', { tier: 'favorite-auto', mediaDir }).catch(() => {});
await pruneEmptyMediaTierDirs({ tier: 'favorite-auto', mediaDir }).catch(() => {});
}
} catch (err) {
if (token === runToken) {
@@ -1,4 +1,4 @@
import { invoke } from '@tauri-apps/api/core';
import { frontendDebugLog } from '@/lib/api/debugLog';
import { libraryGetTracksBatch } from '@/lib/api/library';
import { useAuthStore } from '@/store/authStore';
import { useOfflineStore, type OfflineAlbumMeta } from '@/features/offline/store/offlineStore';
@@ -6,18 +6,10 @@ import { useLocalPlaybackStore, type LocalPlaybackEntry, type PinSource } from '
import { localPlaybackEntryKey } from '@/store/localPlaybackKeys';
import { importLegacyLocalPlayback } from '@/store/localPlaybackMigration';
import { getMediaDir } from '@/lib/media/mediaDir';
import { migrateLegacyOfflineDisk } from '@/lib/api/syncfs';
import { resolveServerIdForIndexKey } from '@/lib/server/serverLookup';
import { resolveIndexKey } from '@/lib/server/serverIndexKey';
interface LegacyOfflineMigrationResult {
trackId: string;
serverIndexKey: string;
path: string;
size: number;
layoutFingerprint: string;
relocated: boolean;
skippedReason?: string | null;
}
import type { LegacyOfflineMigrationResult } from '@/generated/bindings';
type PersistCapableStore = {
persist: {
@@ -44,10 +36,7 @@ function waitForStoreHydration(store: PersistCapableStore): Promise<void> {
function migrationDebug(payload: Record<string, unknown>): void {
if (useAuthStore.getState().loggingMode !== 'debug') return;
void invoke('frontend_debug_log', {
scope: 'legacy-offline-migration',
message: JSON.stringify(payload),
}).catch(() => {});
frontendDebugLog('legacy-offline-migration', JSON.stringify(payload));
}
function resolveIndexKeyForServerId(serverId: string): string {
@@ -192,7 +181,7 @@ export async function runLegacyOfflineFileMigration(serverIndexKey?: string): Pr
const customOfflineDir = useAuthStore.getState().offlineDownloadDir?.trim() || null;
let relocated = 0;
try {
const results = await invoke<LegacyOfflineMigrationResult[]>('migrate_legacy_offline_disk', {
const results = await migrateLegacyOfflineDisk({
mediaDir: getMediaDir(),
customOfflineDir,
serverIndexKeyFilter: serverIndexKey ?? null,
@@ -1,17 +1,18 @@
import { libraryUpsertSongsFromApi } from '@/lib/api/library';
import { librarySqlServerId } from '@/lib/api/coverCache';
import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import { invoke } from '@tauri-apps/api/core';
import { useAuthStore } from '@/store/authStore';
import type { LocalPlaybackEntry, PinSource } from '@/store/localPlaybackStore';
import { useLocalPlaybackStore } from '@/store/localPlaybackStore';
import { getMediaDir } from '@/lib/media/mediaDir';
import { discoverLibraryTierOnDisk, pruneOrphanLibraryTierFiles } from '@/lib/api/syncfs';
import { resolveIndexKey, serverIndexKeyForProfile } from '@/lib/server/serverIndexKey';
import {
entryBelongsToServer,
findLocalPlaybackEntry,
indexKeyBelongsToServer,
} from '@/store/localPlaybackResolve';
import type { LibraryTierDiskHit } from '@/generated/bindings';
interface LibraryTrackProbeResult {
path: string;
@@ -20,14 +21,6 @@ interface LibraryTrackProbeResult {
exists: boolean;
}
interface LibraryTierDiskHit {
trackId: string;
path: string;
size: number;
layoutFingerprint: string;
suffix: string;
}
export interface LibraryTierReconcileResult {
syncedFromDisk: number;
removedStaleIndex: number;
@@ -93,7 +86,7 @@ async function discoverLibraryTierHits(
const serverIndexKey = serverIndexKeyForServerId(serverId);
const libraryServerId = librarySqlServerId(serverId);
try {
return await invoke<LibraryTierDiskHit[]>('discover_library_tier_on_disk', {
return await discoverLibraryTierOnDisk({
serverIndexKey,
libraryServerId,
candidateTrackIds,
@@ -186,7 +179,7 @@ export async function reconcileLibraryTierForServer(
let orphansRemoved: number;
try {
const removed = await invoke<string[]>('prune_orphan_library_tier_files', {
const removed = await pruneOrphanLibraryTierFiles({
serverIndexKey,
keepPaths: [...keepPaths],
mediaDir: getMediaDir(),
@@ -258,7 +251,7 @@ export async function reconcileLibraryTierForAlbum(
let orphansRemoved: number;
try {
const removed = await invoke<string[]>('prune_orphan_library_tier_files', {
const removed = await pruneOrphanLibraryTierFiles({
serverIndexKey,
keepPaths: [...keepPaths],
mediaDir: getMediaDir(),
@@ -3,7 +3,6 @@ import { getAlbumForServer, filterSongsToServerLibrary } from '@/lib/api/subsoni
import { getPlaylistForServer } from '@/lib/api/subsonicPlaylists';
import { getArtistForServer } from '@/lib/api/subsonicArtists';
import type { SubsonicSong } from '@/lib/api/subsonicTypes';
import { invoke } from '@tauri-apps/api/core';
import { useAuthStore } from '@/store/authStore';
import type { PinSource } from '@/store/localPlaybackStore';
import { useLocalPlaybackStore } from '@/store/localPlaybackStore';
@@ -11,6 +10,7 @@ import { useOfflineStore } from '@/features/offline/store/offlineStore';
import { usePlaylistStore } from '@/features/playlist';
import { isSmartPlaylistName } from '@/lib/format/playlistDetailHelpers';
import { getMediaDir } from '@/lib/media/mediaDir';
import { deleteMediaFile } from '@/lib/api/syncfs';
import {
isActiveServerReachable,
onActiveServerBecameReachable,
@@ -123,7 +123,7 @@ async function pruneRemovedPinTracks(
if (!entry?.localPath || entry.tier !== 'library') continue;
if (entry.pinSource?.kind !== kind || entry.pinSource.sourceId !== sourceId) continue;
await invoke('delete_media_file', { localPath: entry.localPath, mediaDir }).catch(() => {});
await deleteMediaFile({ localPath: entry.localPath, mediaDir }).catch(() => {});
lp.removeEntry(trackId, entry.serverIndexKey, `${kind}-sync-prune`);
}
}