diff --git a/flutter_cache_manager/lib/src/cache_store.dart b/flutter_cache_manager/lib/src/cache_store.dart index ca6e9188..d1521ecc 100644 --- a/flutter_cache_manager/lib/src/cache_store.dart +++ b/flutter_cache_manager/lib/src/cache_store.dart @@ -151,13 +151,19 @@ class CacheStore { Future emptyCache() async { final provider = await _cacheInfoRepository; - final toRemove = []; final allObjects = await provider.getAllObjects(); - var futures = []; + + // Remove the cache files from the filesystem + await _removeCacheDir(); + + // Delete objects from store + final toRemove = {}; for (final cacheObject in allObjects) { - futures.add(_removeCachedFile(cacheObject, toRemove)); + if (cacheObject.id != null) { + toRemove.add(cacheObject.id!); + } } - await Future.wait(futures); + await provider.deleteAll(toRemove); } @@ -195,6 +201,18 @@ class CacheStore { } } + Future _removeCacheDir() async { + _memCache.clear(); + _futureCache.clear(); + + try { + await fileSystem.deleteCacheDir(); + } on FileSystemException { + // If the filesystem implementation doesn't check if the file + // exists before deleting it could fail + } + } + bool memoryCacheContainsKey(String key) { return _memCache.containsKey(key); } diff --git a/flutter_cache_manager/lib/src/storage/file_system/file_system.dart b/flutter_cache_manager/lib/src/storage/file_system/file_system.dart index 2cd9764b..3f7a77a6 100644 --- a/flutter_cache_manager/lib/src/storage/file_system/file_system.dart +++ b/flutter_cache_manager/lib/src/storage/file_system/file_system.dart @@ -4,6 +4,10 @@ export 'file_system_web.dart'; import 'package:file/file.dart'; +/// FileSystem works in the context of a directory where filenames are stored. abstract class FileSystem { Future createFile(String name); + + /// Deletes the directory that contains all the cached filed in the current context. + Future deleteCacheDir(); } diff --git a/flutter_cache_manager/lib/src/storage/file_system/file_system_io.dart b/flutter_cache_manager/lib/src/storage/file_system/file_system_io.dart index 15ab3901..861aeb60 100644 --- a/flutter_cache_manager/lib/src/storage/file_system/file_system_io.dart +++ b/flutter_cache_manager/lib/src/storage/file_system/file_system_io.dart @@ -28,4 +28,13 @@ class IOFileSystem implements FileSystem { } return directory.childFile(name); } + + @override + Future deleteCacheDir() async { + final directory = await _fileDir; + + if (await directory.exists()) { + await directory.delete(recursive: true); + } + } } diff --git a/flutter_cache_manager/lib/src/storage/file_system/file_system_web.dart b/flutter_cache_manager/lib/src/storage/file_system/file_system_web.dart index ac080452..b660f006 100644 --- a/flutter_cache_manager/lib/src/storage/file_system/file_system_web.dart +++ b/flutter_cache_manager/lib/src/storage/file_system/file_system_web.dart @@ -1,12 +1,33 @@ -import 'package:file/file.dart' show File; +import 'package:file/file.dart' show File, Directory; import 'package:file/memory.dart'; import 'package:flutter_cache_manager/src/storage/file_system/file_system.dart'; class MemoryCacheSystem implements FileSystem { - final directory = MemoryFileSystem().systemTempDirectory.createTemp('cache'); + Future _fileDir; + + MemoryCacheSystem() : _fileDir = _createTempDirectory(); @override Future createFile(String name) async { - return (await directory).childFile(name); + Directory directory = await _fileDir; + if (!(await directory.exists())) { + // Because _createTempDirectory assigns a new name we need to reassing the future + _fileDir = _createTempDirectory(); + directory = await _fileDir; + } + + return directory.childFile(name); + } + + static Future _createTempDirectory() async { + return MemoryFileSystem().systemTempDirectory.createTemp('cache'); + } + + @override + Future deleteCacheDir() async { + final dir = await _fileDir; + if (await dir.exists()) { + await dir.delete(recursive: true); + } } } diff --git a/flutter_cache_manager/test/cache_store_test.dart b/flutter_cache_manager/test/cache_store_test.dart index ddc693a9..ac480975 100644 --- a/flutter_cache_manager/test/cache_store_test.dart +++ b/flutter_cache_manager/test/cache_store_test.dart @@ -373,7 +373,6 @@ void main() { var config = createTestConfig(); var store = CacheStore(config); store.cleanupRunMinInterval = const Duration(milliseconds: 1); - await config.returnsFile('testimage.png'); var co1 = CacheObject( 'baseflow.com/test.png', @@ -394,11 +393,30 @@ void main() { validTill: clock.now().add(const Duration(days: 7)), ); + final cacheObjects = [co1, co2, co3]; + + // Write the cache files to the filesystem + final List cacheFiles = []; + for (var cacheObject in cacheObjects) { + final f = await config.returnsFile(cacheObject.relativePath); + cacheFiles.add(f); + } + + // Include an extra file + // This could be a desync between the store and the filesystem + cacheFiles + .add(await config.returnsFile("non-existent-file-in-store.png")); + when(config.mockRepo.getAllObjects()) - .thenAnswer((_) => Future.value([co1, co2, co3])); + .thenAnswer((_) => Future.value(cacheObjects)); await store.emptyCache(); + // make sure that all cached files in the filesystem are deleted + for (var cacheFile in cacheFiles) { + expect(await cacheFile.exists(), isFalse); + } + verify(config.mockRepo .deleteAll(argThat(containsAll([co1.id, co2.id, co3.id])))).called(1); }); diff --git a/flutter_cache_manager/test/helpers/test_configuration.dart b/flutter_cache_manager/test/helpers/test_configuration.dart index 151fbd2a..8da959b1 100644 --- a/flutter_cache_manager/test/helpers/test_configuration.dart +++ b/flutter_cache_manager/test/helpers/test_configuration.dart @@ -25,4 +25,12 @@ class TestFileSystem extends FileSystem { await dir.create(recursive: true); return dir.childFile(name); } + + @override + Future deleteCacheDir() async { + var dir = await directoryFuture; + if (await dir.exists()) { + await dir.delete(recursive: true); + } + } }