import { MD5 } from '@pura/harmony-utils'; import { WebdavManager } from '../util/WebdavManager'; import FileManager, { merge2paths } from '../util/FileManager'; import { WebDavAccount } from '../../viewmodel/WebDavAccount'; import nativeBridge from 'libentry.so'; interface SmbDownloadBinding { downloadSmbFile(host: string, share: string, username: string, password: string, domain: string | undefined, remotePath: string, localPath: string): void; } const smbBinding: SmbDownloadBinding = nativeBridge as SmbDownloadBinding; async function buildCacheFileName(relativePath: string): Promise { const hash = await MD5.digestSync(relativePath ?? ''); const lastSlash = relativePath.lastIndexOf('/'); const originalName = lastSlash >= 0 ? relativePath.substring(lastSlash + 1) : relativePath; const safeName = originalName ? originalName.replace(/[^a-zA-Z0-9_.-]/g, '_') : 'remote'; return `${hash}_${safeName}`; } export async function ensureSmbFileCached(account: WebDavAccount, relativePath: string): Promise { const manager = WebdavManager.getInstance(); if (!manager.context) { throw new Error('App context is not initialized'); } if (!account.smbShare) { throw new Error('SMB account missing share name'); } const baseDir = manager.context.filesDir ?? manager.context.cacheDir; if (!baseDir) { throw new Error('Cache directory unavailable'); } const cacheRoot = merge2paths(baseDir, 'smb_cache'); await FileManager.createDir(cacheRoot); const accountDir = merge2paths(cacheRoot, account.id?.toString() ?? 'default'); await FileManager.createDir(accountDir); const normalizedRelative = relativePath?.startsWith('/') ? relativePath : `/${relativePath}`; const cacheFileName = await buildCacheFileName(normalizedRelative); const localPath = merge2paths(accountDir, cacheFileName); let exists = await FileManager.isExist(localPath); if (exists) { const currentSize = await FileManager.getFileSize(localPath); if (currentSize <= 0) { await FileManager.deleteFile(localPath); exists = false; } } if (!exists) { const host = account.isUseLocalHost && account.localHost ? account.localHost : account.host; try { smbBinding.downloadSmbFile( host, account.smbShare, account.account, account.password, account.smbDomain, normalizedRelative, localPath ); } catch (error) { await FileManager.deleteFile(localPath); const err = error as Error; throw err; } } return localPath; }