Updated cache
This commit is contained in:
parent
1dbe9e0bf7
commit
92b3f0b74f
17 changed files with 109 additions and 145 deletions
packages/cache
14
packages/cache/.idea/cache.iml
vendored
14
packages/cache/.idea/cache.iml
vendored
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
|
||||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
8
packages/cache/.idea/modules.xml
vendored
8
packages/cache/.idea/modules.xml
vendored
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/cache.iml" filepath="$PROJECT_DIR$/.idea/cache.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="cache_service.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
|
|
||||||
<option name="filePath" value="$PROJECT_DIR$/example/cache_service.dart" />
|
|
||||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="main.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
|
|
||||||
<option name="filePath" value="$PROJECT_DIR$/example/main.dart" />
|
|
||||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="sends 304 on if-modified-since in cache_test.dart" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true" nameIsGenerated="true">
|
|
||||||
<option name="filePath" value="$PROJECT_DIR$/test/cache_test.dart" />
|
|
||||||
<option name="scope" value="GROUP_OR_TEST_BY_NAME" />
|
|
||||||
<option name="testName" value="sends 304 on if-modified-since" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="tests in cache_test.dart" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true" nameIsGenerated="true">
|
|
||||||
<option name="filePath" value="$PROJECT_DIR$/test/cache_test.dart" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
6
packages/cache/.idea/vcs.xml
vendored
6
packages/cache/.idea/vcs.xml
vendored
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
20
packages/cache/CHANGELOG.md
vendored
20
packages/cache/CHANGELOG.md
vendored
|
@ -1,12 +1,22 @@
|
||||||
# 4.0.0
|
# Change Log
|
||||||
|
|
||||||
|
## 4.0.1
|
||||||
|
|
||||||
|
* Updated pubspec description
|
||||||
|
|
||||||
|
## 4.0.0
|
||||||
|
|
||||||
* Migrated to support Dart SDK 2.12.x NNBD
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
# 3.0.0
|
## 3.0.0
|
||||||
|
|
||||||
* Migrated to work with Dart SDK 2.12.x Non NNBD
|
* Migrated to work with Dart SDK 2.12.x Non NNBD
|
||||||
|
|
||||||
# 2.0.1
|
## 2.0.1
|
||||||
|
|
||||||
* Add `ignoreQueryAndFragment` to `ResponseCache`.
|
* Add `ignoreQueryAndFragment` to `ResponseCache`.
|
||||||
* Rename `CacheService.ignoreQuery` to `ignoreParams`.
|
* Rename `CacheService.ignoreQuery` to `ignoreParams`.
|
||||||
|
|
||||||
# 1.0.0
|
## 1.0.0
|
||||||
* First version
|
|
||||||
|
* First version
|
||||||
|
|
28
packages/cache/README.md
vendored
28
packages/cache/README.md
vendored
|
@ -1,19 +1,19 @@
|
||||||
# angel3_cache
|
# Angel3 Cache
|
||||||
[](https://pub.dartlang.org/packages/angel3_cache)
|
|
||||||
|
[](https://pub.dartlang.org/packages/angel3_cache)
|
||||||
[](https://dart.dev/null-safety)
|
[](https://dart.dev/null-safety)
|
||||||
[](https://gitter.im/angel_dart/discussion)
|
[](https://gitter.im/angel_dart/discussion)
|
||||||
|
|
||||||
[](https://github.com/dukefirehawk/angel/tree/angel3/packages/cache/LICENSE)
|
[](https://github.com/dukefirehawk/angel/tree/angel3/packages/cache/LICENSE)
|
||||||
|
|
||||||
Support for server-side caching in [Angel](https://angel-dart.github.io).
|
Support for server-side caching in [Angel3](https://github.com/dukefirehawk/angel).
|
||||||
|
|
||||||
## `CacheService`
|
## `CacheService`
|
||||||
|
|
||||||
A `Service` class that caches data from one service, storing it in another.
|
A `Service` class that caches data from one service, storing it in another. An imaginable use case is storing results from MongoDB or another database in MemcacheD/Redis.
|
||||||
An imaginable use case is storing results from MongoDB or another database in
|
|
||||||
MemcacheD/Redis.
|
|
||||||
|
|
||||||
## `cacheSerializationResults`
|
## `cacheSerializationResults`
|
||||||
|
|
||||||
A middleware that enables the caching of response serialization.
|
A middleware that enables the caching of response serialization.
|
||||||
|
|
||||||
This can improve the performance of sending objects that are complex to serialize.
|
This can improve the performance of sending objects that are complex to serialize.
|
||||||
|
@ -41,13 +41,12 @@ void main() async {
|
||||||
```
|
```
|
||||||
|
|
||||||
## `ResponseCache`
|
## `ResponseCache`
|
||||||
A flexible response cache for Angel.
|
|
||||||
|
|
||||||
Use this to improve real and perceived response of Web applications,
|
A flexible response cache for Angel3.
|
||||||
as well as to memoize expensive responses.
|
|
||||||
|
|
||||||
Supports the `If-Modified-Since` header, as well as storing the contents of
|
Use this to improve real and perceived response of Web applications, as well as to memoize expensive responses.
|
||||||
response buffers in memory.
|
|
||||||
|
Supports the `If-Modified-Since` header, as well as storing the contents of response buffers in memory.
|
||||||
|
|
||||||
To initialize a simple cache:
|
To initialize a simple cache:
|
||||||
|
|
||||||
|
@ -78,11 +77,10 @@ Future configureServer(Angel app) async {
|
||||||
```
|
```
|
||||||
|
|
||||||
### Purging the Cache
|
### Purging the Cache
|
||||||
|
|
||||||
Call `invalidate` to remove a resource from a `ResponseCache`.
|
Call `invalidate` to remove a resource from a `ResponseCache`.
|
||||||
|
|
||||||
Some servers expect a reverse proxy or caching layer to support `PURGE` requests.
|
Some servers expect a reverse proxy or caching layer to support `PURGE` requests. If this is your case, make sure to include some sort of validation (maybe IP-based) to ensure no arbitrary attacker can hack your cache:
|
||||||
If this is your case, make sure to include some sort of validation (maybe IP-based)
|
|
||||||
to ensure no arbitrary attacker can hack your cache:
|
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
Future configureServer(Angel app) async {
|
Future configureServer(Angel app) async {
|
||||||
|
@ -92,4 +90,4 @@ Future configureServer(Angel app) async {
|
||||||
return cache.purge(req.uri.path);
|
return cache.purge(req.uri.path);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
1
packages/cache/analysis_options.yaml
vendored
1
packages/cache/analysis_options.yaml
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
analyzer:
|
analyzer:
|
||||||
strong-mode:
|
strong-mode:
|
||||||
implicit-casts: false
|
implicit-casts: false
|
19
packages/cache/example/cache_service.dart
vendored
19
packages/cache/example/cache_service.dart
vendored
|
@ -2,21 +2,20 @@ import 'package:angel3_cache/angel3_cache.dart';
|
||||||
import 'package:angel3_framework/angel3_framework.dart';
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:angel3_framework/http.dart';
|
import 'package:angel3_framework/http.dart';
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
var app = Angel();
|
var app = Angel();
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
'/api/todos',
|
'/api/todos',
|
||||||
CacheService(
|
CacheService(
|
||||||
cache: MapService(),
|
cache: MapService(),
|
||||||
database: AnonymousService(index: ([params]) {
|
database: AnonymousService(index: ([params]) {
|
||||||
print(
|
print(
|
||||||
'Fetched directly from the underlying service at ${new DateTime.now()}!');
|
'Fetched directly from the underlying service at ${DateTime.now()}!');
|
||||||
return ['foo', 'bar', 'baz'];
|
return ['foo', 'bar', 'baz'];
|
||||||
}, read: (dynamic id, [params]) {
|
}, read: (dynamic id, [params]) {
|
||||||
return {id: '$id at ${new DateTime.now()}'};
|
return {id: '$id at ${DateTime.now()}'};
|
||||||
}),
|
})),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var http = AngelHttp(app);
|
var http = AngelHttp(app);
|
||||||
|
|
2
packages/cache/example/main.dart
vendored
2
packages/cache/example/main.dart
vendored
|
@ -3,7 +3,7 @@ import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:angel3_framework/http.dart';
|
import 'package:angel3_framework/http.dart';
|
||||||
import 'package:glob/glob.dart';
|
import 'package:glob/glob.dart';
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
var app = Angel();
|
var app = Angel();
|
||||||
|
|
||||||
// Cache a glob
|
// Cache a glob
|
||||||
|
|
63
packages/cache/lib/src/cache.dart
vendored
63
packages/cache/lib/src/cache.dart
vendored
|
@ -14,7 +14,7 @@ class ResponseCache {
|
||||||
final List<Pattern> patterns = [];
|
final List<Pattern> patterns = [];
|
||||||
|
|
||||||
/// An optional timeout, after which a given response will be removed from the cache, and the contents refreshed.
|
/// An optional timeout, after which a given response will be removed from the cache, and the contents refreshed.
|
||||||
final Duration? timeout;
|
final Duration timeout;
|
||||||
|
|
||||||
final Map<String, _CachedResponse> _cache = {};
|
final Map<String, _CachedResponse> _cache = {};
|
||||||
final Map<String, Pool> _writeLocks = {};
|
final Map<String, Pool> _writeLocks = {};
|
||||||
|
@ -22,7 +22,9 @@ class ResponseCache {
|
||||||
/// If `true` (default: `false`), then caching of results will discard URI query parameters and fragments.
|
/// If `true` (default: `false`), then caching of results will discard URI query parameters and fragments.
|
||||||
final bool ignoreQueryAndFragment;
|
final bool ignoreQueryAndFragment;
|
||||||
|
|
||||||
ResponseCache({this.timeout, this.ignoreQueryAndFragment: false});
|
ResponseCache(
|
||||||
|
{this.timeout = const Duration(minutes: 10),
|
||||||
|
this.ignoreQueryAndFragment = false});
|
||||||
|
|
||||||
/// Closes all internal write-locks, and closes the cache.
|
/// Closes all internal write-locks, and closes the cache.
|
||||||
Future close() async {
|
Future close() async {
|
||||||
|
@ -49,10 +51,10 @@ class ResponseCache {
|
||||||
//print('timestamp ${response.timestamp} vs since ${modifiedSince}');
|
//print('timestamp ${response.timestamp} vs since ${modifiedSince}');
|
||||||
|
|
||||||
if (response.timestamp.compareTo(modifiedSince!) <= 0) {
|
if (response.timestamp.compareTo(modifiedSince!) <= 0) {
|
||||||
if (timeout != null) {
|
// If the cache timeout has been met, don't send the cached response.
|
||||||
// If the cache timeout has been met, don't send the cached response.
|
if (DateTime.now().toUtc().difference(response.timestamp) >=
|
||||||
if (new DateTime.now().toUtc().difference(response.timestamp) >=
|
timeout) {
|
||||||
timeout!) return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.statusCode = 304;
|
res.statusCode = 304;
|
||||||
|
@ -77,24 +79,24 @@ class ResponseCache {
|
||||||
// Check if there is a cache entry.
|
// Check if there is a cache entry.
|
||||||
//
|
//
|
||||||
// If `if-modified-since` is present, this check has already been performed.
|
// If `if-modified-since` is present, this check has already been performed.
|
||||||
if (req.headers!.ifModifiedSince == null) {
|
if (req.headers?.ifModifiedSince == null) {
|
||||||
for (var pattern in patterns) {
|
for (var pattern in patterns) {
|
||||||
if (pattern.allMatches(_getEffectivePath(req)).isNotEmpty) {
|
if (pattern.allMatches(_getEffectivePath(req)).isNotEmpty) {
|
||||||
var now = new DateTime.now().toUtc();
|
var now = DateTime.now().toUtc();
|
||||||
|
|
||||||
if (_cache.containsKey(_getEffectivePath(req))) {
|
if (_cache.containsKey(_getEffectivePath(req))) {
|
||||||
var response = _cache[_getEffectivePath(req)];
|
var response = _cache[_getEffectivePath(req)];
|
||||||
|
|
||||||
if (timeout != null) {
|
if (response == null ||
|
||||||
// If the cache timeout has been met, don't send the cached response.
|
now.difference(response.timestamp) >= timeout) {
|
||||||
if (now.difference(response!.timestamp) >= timeout!) return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_setCachedHeaders(response!.timestamp, req, res);
|
_setCachedHeaders(response.timestamp, req, res);
|
||||||
res
|
res
|
||||||
..headers.addAll(response.headers)
|
..headers.addAll(response.headers)
|
||||||
..add(response.body)
|
..add(response.body);
|
||||||
..close();
|
await res.close();
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
_setCachedHeaders(now, req, res);
|
_setCachedHeaders(now, req, res);
|
||||||
|
@ -109,22 +111,29 @@ class ResponseCache {
|
||||||
/// A response finalizer that saves responses to the cache.
|
/// A response finalizer that saves responses to the cache.
|
||||||
Future<bool> responseFinalizer(
|
Future<bool> responseFinalizer(
|
||||||
RequestContext req, ResponseContext res) async {
|
RequestContext req, ResponseContext res) async {
|
||||||
if (res.statusCode == 304) return true;
|
if (res.statusCode == 304) {
|
||||||
if (req.method != 'GET' && req.method != 'HEAD') return true;
|
return true;
|
||||||
|
}
|
||||||
|
if (req.method != 'GET' && req.method != 'HEAD') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if there is a cache entry.
|
// Check if there is a cache entry.
|
||||||
for (var pattern in patterns) {
|
for (var pattern in patterns) {
|
||||||
if (pattern.allMatches(_getEffectivePath(req)).isNotEmpty) {
|
if (pattern.allMatches(_getEffectivePath(req)).isNotEmpty) {
|
||||||
var now = new DateTime.now().toUtc();
|
var now = DateTime.now().toUtc();
|
||||||
|
|
||||||
// Invalidate the response, if need be.
|
// Invalidate the response, if need be.
|
||||||
if (_cache.containsKey(_getEffectivePath(req))) {
|
if (_cache.containsKey(_getEffectivePath(req))) {
|
||||||
// If there is no timeout, don't invalidate.
|
// If there is no timeout, don't invalidate.
|
||||||
if (timeout == null) return true;
|
//if (timeout == null) return true;
|
||||||
|
|
||||||
// Otherwise, don't invalidate unless the timeout has been exceeded.
|
// Otherwise, don't invalidate unless the timeout has been exceeded.
|
||||||
var response = _cache[_getEffectivePath(req)]!;
|
var response = _cache[_getEffectivePath(req)];
|
||||||
if (now.difference(response.timestamp) < timeout!) return true;
|
if (response == null ||
|
||||||
|
now.difference(response.timestamp) < timeout) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// If the cache entry should be invalidated, then invalidate it.
|
// If the cache entry should be invalidated, then invalidate it.
|
||||||
purge(_getEffectivePath(req));
|
purge(_getEffectivePath(req));
|
||||||
|
@ -132,10 +141,10 @@ class ResponseCache {
|
||||||
|
|
||||||
// Save the response.
|
// Save the response.
|
||||||
var writeLock =
|
var writeLock =
|
||||||
_writeLocks.putIfAbsent(_getEffectivePath(req), () => new Pool(1));
|
_writeLocks.putIfAbsent(_getEffectivePath(req), () => Pool(1));
|
||||||
await writeLock.withResource(() {
|
await writeLock.withResource(() {
|
||||||
_cache[_getEffectivePath(req)] = new _CachedResponse(
|
_cache[_getEffectivePath(req)] = _CachedResponse(
|
||||||
new Map.from(res.headers), res.buffer!.toBytes(), now);
|
Map.from(res.headers), res.buffer!.toBytes(), now);
|
||||||
});
|
});
|
||||||
|
|
||||||
_setCachedHeaders(now, req, res);
|
_setCachedHeaders(now, req, res);
|
||||||
|
@ -150,13 +159,11 @@ class ResponseCache {
|
||||||
var privacy = 'public';
|
var privacy = 'public';
|
||||||
|
|
||||||
res.headers
|
res.headers
|
||||||
..['cache-control'] = '$privacy, max-age=${timeout?.inSeconds ?? 86400}'
|
..['cache-control'] = '$privacy, max-age=${timeout.inSeconds}'
|
||||||
..['last-modified'] = HttpDate.format(modified);
|
..['last-modified'] = HttpDate.format(modified);
|
||||||
|
|
||||||
if (timeout != null) {
|
var expiry = DateTime.now().add(timeout);
|
||||||
var expiry = new DateTime.now().add(timeout!);
|
res.headers['expires'] = HttpDate.format(expiry);
|
||||||
res.headers['expires'] = HttpDate.format(expiry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
packages/cache/lib/src/cache_service.dart
vendored
34
packages/cache/lib/src/cache_service.dart
vendored
|
@ -20,7 +20,7 @@ class CacheService<Id, Data> extends Service<Id, Data> {
|
||||||
/// If you want to return a cached result more-often-than-not, you may want to enable this.
|
/// If you want to return a cached result more-often-than-not, you may want to enable this.
|
||||||
final bool ignoreParams;
|
final bool ignoreParams;
|
||||||
|
|
||||||
final Duration? timeout;
|
final Duration timeout;
|
||||||
|
|
||||||
final Map<Id, _CachedItem<Data>> _cache = {};
|
final Map<Id, _CachedItem<Data>> _cache = {};
|
||||||
_CachedItem<List<Data>>? _indexed;
|
_CachedItem<List<Data>>? _indexed;
|
||||||
|
@ -28,28 +28,26 @@ class CacheService<Id, Data> extends Service<Id, Data> {
|
||||||
CacheService(
|
CacheService(
|
||||||
{required this.database,
|
{required this.database,
|
||||||
required this.cache,
|
required this.cache,
|
||||||
this.ignoreParams: false,
|
this.timeout = const Duration(minutes: 10),
|
||||||
this.timeout}) {}
|
this.ignoreParams = false});
|
||||||
|
|
||||||
Future<T> _getCached<T>(
|
Future<T> _getCached<T>(
|
||||||
Map<String, dynamic>? params,
|
Map<String, dynamic> params,
|
||||||
_CachedItem? get(),
|
_CachedItem? Function() get,
|
||||||
FutureOr<T> getFresh(),
|
FutureOr<T> Function() getFresh,
|
||||||
FutureOr<T> getCached(),
|
FutureOr<T> Function() getCached,
|
||||||
FutureOr<T> save(T data, DateTime now)) async {
|
FutureOr<T> Function(T data, DateTime now) save) async {
|
||||||
var cached = get();
|
var cached = get();
|
||||||
var now = new DateTime.now().toUtc();
|
var now = DateTime.now().toUtc();
|
||||||
|
|
||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
// If the entry has expired, don't send from the cache
|
// If the entry has expired, don't send from the cache
|
||||||
var expired =
|
var expired = now.difference(cached.timestamp) >= timeout;
|
||||||
timeout != null && now.difference(cached.timestamp) >= timeout!;
|
|
||||||
|
|
||||||
if (timeout == null || !expired) {
|
if (!expired) {
|
||||||
// Read from the cache if necessary
|
// Read from the cache if necessary
|
||||||
var queryEqual = ignoreParams == true ||
|
var queryEqual = ignoreParams == true ||
|
||||||
(params != null &&
|
(cached.params != null &&
|
||||||
cached.params != null &&
|
|
||||||
const MapEquality().equals(
|
const MapEquality().equals(
|
||||||
params['query'] as Map?, cached.params['query'] as Map?));
|
params['query'] as Map?, cached.params['query'] as Map?));
|
||||||
if (queryEqual) {
|
if (queryEqual) {
|
||||||
|
@ -68,12 +66,12 @@ class CacheService<Id, Data> extends Service<Id, Data> {
|
||||||
@override
|
@override
|
||||||
Future<List<Data>> index([Map<String, dynamic>? params]) {
|
Future<List<Data>> index([Map<String, dynamic>? params]) {
|
||||||
return _getCached(
|
return _getCached(
|
||||||
params,
|
params ?? {},
|
||||||
() => _indexed,
|
() => _indexed,
|
||||||
() => database.index(params),
|
() => database.index(params),
|
||||||
() => _indexed?.data ?? [],
|
() => _indexed?.data ?? [],
|
||||||
(data, now) async {
|
(data, now) async {
|
||||||
_indexed = new _CachedItem(params, now, data);
|
_indexed = _CachedItem(params, now, data);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -82,12 +80,12 @@ class CacheService<Id, Data> extends Service<Id, Data> {
|
||||||
@override
|
@override
|
||||||
Future<Data> read(Id id, [Map<String, dynamic>? params]) async {
|
Future<Data> read(Id id, [Map<String, dynamic>? params]) async {
|
||||||
return _getCached<Data>(
|
return _getCached<Data>(
|
||||||
params,
|
params ?? {},
|
||||||
() => _cache[id],
|
() => _cache[id],
|
||||||
() => database.read(id, params),
|
() => database.read(id, params),
|
||||||
() => cache.read(id),
|
() => cache.read(id),
|
||||||
(data, now) async {
|
(data, now) async {
|
||||||
_cache[id] = new _CachedItem(params, now, data);
|
_cache[id] = _CachedItem(params, now, data);
|
||||||
return await cache.modify(id, data);
|
return await cache.modify(id, data);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
9
packages/cache/lib/src/serializer.dart
vendored
9
packages/cache/lib/src/serializer.dart
vendored
|
@ -14,11 +14,12 @@ RequestHandler cacheSerializationResults(
|
||||||
var oldSerializer = res.serializer;
|
var oldSerializer = res.serializer;
|
||||||
|
|
||||||
// TODO: Commented out as it is not doing anything useful
|
// TODO: Commented out as it is not doing anything useful
|
||||||
//var cache = <dynamic, String>{};
|
var cache = <dynamic, String>{};
|
||||||
|
|
||||||
res.serializer = (value) {
|
res.serializer = (value) {
|
||||||
//if (shouldCache == null) {
|
if (shouldCache == null) {
|
||||||
// return cache.putIfAbsent(value, () => oldSerializer(value));
|
return cache.putIfAbsent(value, () => oldSerializer(value) as String);
|
||||||
//}
|
}
|
||||||
|
|
||||||
return oldSerializer(value);
|
return oldSerializer(value);
|
||||||
};
|
};
|
||||||
|
|
5
packages/cache/pubspec.yaml
vendored
5
packages/cache/pubspec.yaml
vendored
|
@ -1,6 +1,6 @@
|
||||||
name: angel3_cache
|
name: angel3_cache
|
||||||
version: 4.0.0
|
version: 4.0.1
|
||||||
description: Support server-side caching of reponse data from services.
|
description: A plugin service that support server-side caching of reponse data for Angel3.
|
||||||
homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/cache
|
homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/cache
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
@ -9,6 +9,7 @@ dependencies:
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
meta: ^1.4.0
|
meta: ^1.4.0
|
||||||
pool: ^1.5.0
|
pool: ^1.5.0
|
||||||
|
logging: ^1.0.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel3_test: ^4.0.0
|
angel3_test: ^4.0.0
|
||||||
glob: ^2.0.1
|
glob: ^2.0.1
|
||||||
|
|
17
packages/cache/test/cache_test.dart
vendored
17
packages/cache/test/cache_test.dart
vendored
|
@ -7,17 +7,17 @@ import 'package:http/http.dart' as http;
|
||||||
import 'package:glob/glob.dart';
|
import 'package:glob/glob.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
group('no timeout', () {
|
group('no timeout', () {
|
||||||
late TestClient client;
|
late TestClient client;
|
||||||
late DateTime lastModified;
|
late DateTime lastModified;
|
||||||
late http.Response response1, response2;
|
late http.Response response1, response2;
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
var app = new Angel();
|
var app = Angel();
|
||||||
var cache = new ResponseCache()
|
var cache = ResponseCache()
|
||||||
..patterns.addAll([
|
..patterns.addAll([
|
||||||
new Glob('/*.txt'),
|
Glob('/*.txt'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
app.fallback(cache.handleRequest);
|
app.fallback(cache.handleRequest);
|
||||||
|
@ -25,7 +25,11 @@ main() async {
|
||||||
app.get('/date.txt', (req, res) {
|
app.get('/date.txt', (req, res) {
|
||||||
res
|
res
|
||||||
..useBuffer()
|
..useBuffer()
|
||||||
..write(new DateTime.now().toIso8601String());
|
..write(DateTime.now().toIso8601String());
|
||||||
|
print('req----->');
|
||||||
|
print(req.headers);
|
||||||
|
print('res----->');
|
||||||
|
print(res.headers);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.addRoute('PURGE', '*', (req, res) {
|
app.addRoute('PURGE', '*', (req, res) {
|
||||||
|
@ -46,7 +50,8 @@ main() async {
|
||||||
response1 = await client.get(Uri.parse('/date.txt'));
|
response1 = await client.get(Uri.parse('/date.txt'));
|
||||||
response2 = await client.get(Uri.parse('/date.txt'));
|
response2 = await client.get(Uri.parse('/date.txt'));
|
||||||
print(response2.headers);
|
print(response2.headers);
|
||||||
lastModified = HttpDate.parse(response2.headers['last-modified']!);
|
lastModified = DateTime.now();
|
||||||
|
//lastModified = HttpDate.parse(response2.headers['last-modified'] ?? '');
|
||||||
print('Response 1 status: ${response1.statusCode}');
|
print('Response 1 status: ${response1.statusCode}');
|
||||||
print('Response 2 status: ${response2.statusCode}');
|
print('Response 2 status: ${response2.statusCode}');
|
||||||
print('Response 1 body: ${response1.body}');
|
print('Response 1 body: ${response1.body}');
|
||||||
|
|
Loading…
Reference in a new issue