OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import 'dart:async'; | |
6 import 'dart:io'; | |
7 import 'logger.dart'; | |
8 import 'try.dart'; | |
9 | |
10 typedef Future<String> Call(); | |
Johnni Winther
2017/08/23 12:40:46
Rename to [ReadResultFunction] and variables of th
| |
11 typedef Future<String> WithCache(Call call, [String key]); | |
12 typedef WithCache PerformWithCache({String overrideKey, Duration duration}); | |
Johnni Winther
2017/08/23 12:40:47
Rename to [CreateCacheFunction] and variables of t
| |
13 | |
14 PerformWithCache initCache(Uri baseUri, [Logger logger]) { | |
15 if (logger == null) { | |
16 logger = new StdOutLogger(Level.warning); | |
Johnni Winther
2017/08/23 12:40:47
Just write this as:
logger ??= new StdOutLogger(L
| |
17 } | |
18 | |
19 final cache = new Cache(baseUri, logger); | |
20 | |
21 return ({String overrideKey, Duration duration}) { | |
22 if (duration == null) { | |
23 duration = new Duration(hours: 24); | |
24 } | |
25 | |
26 return (Call call, [String key]) async { | |
27 if (overrideKey != null) { | |
28 key = overrideKey; | |
29 } | |
30 | |
31 if (key == null || key.isEmpty) { | |
32 logger.warning("Key is null or empty - cannot cache result"); | |
33 } else { | |
34 // format key | |
35 key = key.replaceAll("/", "_").replaceAll(".", "_"); | |
36 | |
37 Try<ReadFromCacheResult> readResult = | |
Johnni Winther
2017/08/23 12:40:46
Rename to [cacheResult].
| |
38 await cache.tryRead(key, duration); | |
39 if (!readResult.isError() && readResult.get().hasResult) { | |
40 logger.debug("Found key $key in cache"); | |
41 return readResult.get().res; | |
42 } | |
43 if (readResult.isError()) { | |
44 logger.error("Error when reading from cache", readResult.getError(), | |
45 readResult.getStackTrace()); | |
46 } | |
47 } | |
48 | |
49 logger.debug("Could not find key $key in cache"); | |
50 | |
51 // we have to make a call | |
52 String result = await call(); | |
53 | |
54 // insert/update the cache | |
55 if (key != null && !key.isEmpty) { | |
56 await cache.write(key, result); | |
57 } | |
58 | |
59 return result; | |
60 }; | |
61 }; | |
62 } | |
63 | |
64 PerformWithCache noCache() { | |
65 return ({String overrideKey, Duration duration}) { | |
66 return (Call call, [String key]) { | |
67 return call(); | |
68 }; | |
69 }; | |
70 } | |
71 | |
72 /// Simple cache for caching data. | |
73 class Cache { | |
Johnni Winther
2017/08/23 12:40:46
Add a TODO (for me?) to use this instead of the Ca
| |
74 Uri base; | |
75 Logger logger; | |
76 | |
77 Cache(this.base, this.logger); | |
78 | |
79 Map<String, String> memoryCache = <String, String>{}; | |
80 | |
81 /// Checks if key [path] is in cache | |
82 Future<bool> containsKey(String path, [Duration duration]) async { | |
83 if (memoryCache.containsKey(path)) return true; | |
84 | |
85 File file = new File.fromUri(base.resolve(path)); | |
86 if (await file.exists()) { | |
87 return duration == null | |
88 ? true | |
89 : new DateTime.now().difference(await file.lastModified()) <= | |
90 duration; | |
91 } | |
92 | |
93 return false; | |
94 } | |
95 | |
96 /// Try reading [path] from cache | |
97 Future<Try<ReadFromCacheResult>> tryRead(String path, | |
Johnni Winther
2017/08/23 12:40:46
Rename to [read] (since we always just try)
| |
98 [Duration duration]) async { | |
99 if (memoryCache.containsKey(path)) { | |
100 logger.debug('Found $path in memory cache'); | |
101 return new Try.from(new ReadFromCacheResult.result(memoryCache[path])); | |
102 } | |
103 | |
104 File file = new File.fromUri(base.resolve(path)); | |
105 | |
106 if (!await file.exists()) { | |
107 logger.debug('Could not find file $path in file cache'); | |
108 return new Try.from(new ReadFromCacheResult.noResult()); | |
109 } | |
110 | |
111 if (duration != null && | |
112 new DateTime.now().difference(await file.lastModified()) > duration) { | |
113 logger.debug( | |
114 'File $path was found but the information is too stale, for the durati on: $duration'); | |
Johnni Winther
2017/08/23 12:40:47
Split long strings manual:
logger.debug(
'Fil
| |
115 return new Try.from(new ReadFromCacheResult.noResult()); | |
116 } | |
117 | |
118 return tryStartAsync(() async { | |
119 logger.debug('Found $path in file cache'); | |
120 var text = await file.readAsString(); | |
121 memoryCache[path] = text; | |
122 return new ReadFromCacheResult.result(text); | |
123 }); | |
124 } | |
125 | |
126 /// Store [text] as the cache data for [path]. | |
127 Future write(String path, String text) async { | |
128 logger.debug('Creating $path in file cache'); | |
129 File file = new File.fromUri(base.resolve(path)); | |
130 if (!await file.exists()) { | |
131 await file.create(recursive: true); | |
132 } | |
133 await file.writeAsString(text); | |
134 memoryCache[path] = text; | |
135 } | |
136 | |
137 /// Clears cache | |
138 Future clearCache(Uri baseUri) async { | |
139 // needs to be done | |
Johnni Winther
2017/08/23 12:40:47
Write this as
// TODO(mkroghj): Implement this.
| |
140 } | |
141 } | |
142 | |
143 class ReadFromCacheResult { | |
Johnni Winther
2017/08/23 12:40:46
Rename to [CacheResult] (the correctly name reads
| |
144 bool hasResult; | |
Johnni Winther
2017/08/23 12:40:47
Make the fields final.
| |
145 String res; | |
Johnni Winther
2017/08/23 12:40:47
Rename to [result]. We generally use unabbreviated
Bill Hesse
2017/08/23 15:41:25
I agree - alway use full, correctly-spelled words
| |
146 | |
147 ReadFromCacheResult.noResult() { | |
148 hasResult = false; | |
149 res = null; | |
150 } | |
151 | |
152 ReadFromCacheResult.result(String result) { | |
Johnni Winther
2017/08/23 12:40:47
Rename to the no-name constructor and use initiali
| |
153 hasResult = true; | |
154 this.res = result; | |
155 } | |
156 } | |
OLD | NEW |