Index: tools/gardening/lib/src/cache_new.dart |
diff --git a/tools/gardening/lib/src/cache_new.dart b/tools/gardening/lib/src/cache_new.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..cafd893e1758355fffe94dcbacad121cc5928045 |
--- /dev/null |
+++ b/tools/gardening/lib/src/cache_new.dart |
@@ -0,0 +1,150 @@ |
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+import 'dart:async'; |
+import 'dart:io'; |
+import 'logger.dart'; |
+import 'try.dart'; |
+ |
+typedef Future<String> FetchDataFunction(); |
+typedef Future<String> WithCacheFunction(FetchDataFunction fetchData, |
+ [String key]); |
+typedef WithCacheFunction CreateCacheFunction( |
+ {String overrideKey, Duration duration}); |
+ |
+CreateCacheFunction initCache(Uri baseUri, [Logger logger]) { |
+ final cache = new Cache(baseUri, logger); |
+ logger ??= new StdOutLogger(Level.warning); |
+ |
+ return ({String overrideKey, Duration duration}) { |
+ if (duration == null) { |
+ duration = new Duration(hours: 24); |
+ } |
+ |
+ return (FetchDataFunction call, [String key]) async { |
+ if (overrideKey != null) { |
+ key = overrideKey; |
+ } |
+ |
+ if (key == null || key.isEmpty) { |
+ logger.warning("Key is null or empty - cannot cache result"); |
+ } else { |
+ // format key |
+ key = key.replaceAll("/", "_").replaceAll(".", "_"); |
+ |
+ Try<CacheResult> readResult = await cache.read(key, duration); |
+ if (!readResult.isError && readResult.value.hasResult) { |
+ logger.debug("Found key $key in cache"); |
+ return readResult.value.result; |
+ } |
+ if (readResult.isError) { |
+ logger.error("Error when reading from cache", readResult.error, |
+ readResult.stackTrace); |
+ } |
+ } |
+ |
+ logger.debug("Could not find key $key in cache"); |
+ |
+ // we have to make a call |
+ String result = await call(); |
+ |
+ // insert/update the cache |
+ if (key != null && !key.isEmpty) { |
+ await cache.write(key, result); |
+ } |
+ |
+ return result; |
+ }; |
+ }; |
+} |
+ |
+CreateCacheFunction noCache() { |
+ return ({String overrideKey, Duration duration}) { |
+ return (FetchDataFunction fetchData, [String key]) { |
+ return fetchData(); |
+ }; |
+ }; |
+} |
+ |
+/// Simple cache for caching data. |
+class Cache { |
+ // TODO(mkroghj) use this instead of cache.dart |
+ Uri base; |
+ Logger logger; |
+ |
+ Cache(this.base, this.logger); |
+ |
+ Map<String, String> memoryCache = <String, String>{}; |
+ |
+ /// Checks if key [path] is in cache |
+ Future<bool> containsKey(String path, [Duration duration]) async { |
+ if (memoryCache.containsKey(path)) return true; |
+ |
+ File file = new File.fromUri(base.resolve(path)); |
+ if (await file.exists()) { |
+ return duration == null |
+ ? true |
+ : new DateTime.now().difference(await file.lastModified()) <= |
+ duration; |
+ } |
+ |
+ return false; |
+ } |
+ |
+ /// Try reading [path] from cache |
+ Future<Try<CacheResult>> read(String path, [Duration duration]) async { |
+ if (memoryCache.containsKey(path)) { |
+ logger.debug('Found $path in memory cache'); |
+ return new Try.from(new CacheResult(memoryCache[path])); |
+ } |
+ |
+ File file = new File.fromUri(base.resolve(path)); |
+ |
+ if (!(await file.exists())) { |
+ logger.debug('Could not find file $path in file cache'); |
+ return new Try.from(new CacheResult.noResult()); |
+ } |
+ |
+ if (duration != null && |
+ new DateTime.now().difference(await file.lastModified()) > duration) { |
+ logger.debug('File $path was found but the information is too stale,' |
+ 'for the duration: $duration'); |
+ return new Try.from(new CacheResult.noResult()); |
+ } |
+ |
+ return tryStartAsync(() async { |
+ logger.debug('Found $path in file cache'); |
+ var text = await file.readAsString(); |
+ memoryCache[path] = text; |
+ return new CacheResult(text); |
+ }); |
+ } |
+ |
+ /// Store [text] as the cache data for [path]. |
+ Future write(String path, String text) async { |
+ logger.debug('Creating $path in file cache'); |
+ File file = new File.fromUri(base.resolve(path)); |
+ if (!await file.exists()) { |
+ await file.create(recursive: true); |
+ } |
+ await file.writeAsString(text); |
+ memoryCache[path] = text; |
+ } |
+ |
+ /// Clears the cache at [baseUri] |
+ Future clearCache(Uri baseUri) async { |
+ await new Directory(baseUri.toFilePath()).delete(recursive: true); |
+ } |
+} |
+ |
+class CacheResult { |
+ final bool hasResult; |
+ final String result; |
+ |
+ CacheResult.noResult() |
+ : hasResult = false, |
+ result = null {} |
+ |
+ CacheResult(this.result) : hasResult = true {} |
+} |