Skeleton for ResponseCache
This commit is contained in:
parent
ad077502fc
commit
d4226ab83f
5 changed files with 91 additions and 22 deletions
|
@ -8,4 +8,8 @@ Support for server-side caching in [Angel](https://angel-dart.github.io).
|
||||||
*TODO: Documentation*
|
*TODO: Documentation*
|
||||||
|
|
||||||
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 Redis.
|
An imaginable use case is storing results from MongoDB or another database in
|
||||||
|
MemcacheD/Redis.
|
||||||
|
|
||||||
|
## `Cache`
|
||||||
|
*TODO: Documentation*
|
|
@ -1,21 +1,2 @@
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
export 'src/cache.dart';
|
||||||
import 'package:meta/meta.dart';
|
export 'src/cache_service.dart';
|
||||||
|
|
||||||
/// An Angel [Service] that caches data from another service.
|
|
||||||
///
|
|
||||||
/// This is useful for applications of scale, where network latency
|
|
||||||
/// can have real implications on application performance.
|
|
||||||
class CacheService extends Service {
|
|
||||||
/// The underlying [Service] that represents the original data store.
|
|
||||||
final Service database;
|
|
||||||
|
|
||||||
/// The [Service] used to interface with a caching layer.
|
|
||||||
///
|
|
||||||
/// If not provided, this defaults to a [MapService].
|
|
||||||
final Service cache;
|
|
||||||
|
|
||||||
CacheService({@required this.database, Service cache})
|
|
||||||
: this.cache = cache ?? new MapService() {
|
|
||||||
assert(database != null);
|
|
||||||
}
|
|
||||||
}
|
|
61
lib/src/cache.dart
Normal file
61
lib/src/cache.dart
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
final DateFormat _fmt = new DateFormat('EEE, d MMM yyyy HH:mm:ss');
|
||||||
|
|
||||||
|
/// Formats a date (converted to UTC), ex: `Sun, 03 May 2015 23:02:37 GMT`.
|
||||||
|
String _formatDateForHttp(DateTime dt) => _fmt.format(dt.toUtc()) + ' GMT';
|
||||||
|
|
||||||
|
class ResponseCache {
|
||||||
|
final List<Pattern> patterns = [];
|
||||||
|
final Duration timeout;
|
||||||
|
final Map<String, _CachedResponse> _cache = {};
|
||||||
|
|
||||||
|
ResponseCache({this.timeout});
|
||||||
|
|
||||||
|
Future<bool> handleRequest(RequestContext req, ResponseContext res) async {
|
||||||
|
var now = new DateTime.now().toUtc();
|
||||||
|
|
||||||
|
// Check if there is a cache entry.
|
||||||
|
for (var pattern in patterns) {
|
||||||
|
if (pattern.allMatches(req.uri.path).isNotEmpty && _cache.containsKey(req.uri.path)) {
|
||||||
|
var response = _cache[req.uri.path];
|
||||||
|
|
||||||
|
// Only send a cached response if it is valid.
|
||||||
|
if (timeout == null || now.difference(response.timestamp) >= timeout) {
|
||||||
|
// TODO: If-Last-Modified
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> responseFinalizer(RequestContext req, ResponseContext res) async {
|
||||||
|
var now = new DateTime.now().toUtc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCachedHeaders(
|
||||||
|
DateTime modified, RequestContext req, ResponseContext res) {
|
||||||
|
var privacy = 'public';
|
||||||
|
|
||||||
|
res.headers
|
||||||
|
..['cache-control'] = '$privacy, max-age=${timeout?.inSeconds ?? 0}'
|
||||||
|
..['last-modified'] = _formatDateForHttp(modified);
|
||||||
|
|
||||||
|
if (timeout != null) {
|
||||||
|
var expiry = new DateTime.now().add(timeout);
|
||||||
|
res.headers['expires'] = _formatDateForHttp(expiry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CachedResponse {
|
||||||
|
final Map<String, String> headers;
|
||||||
|
final List<int> body;
|
||||||
|
final DateTime timestamp;
|
||||||
|
|
||||||
|
_CachedResponse({this.headers, this.body, this.timestamp});
|
||||||
|
}
|
21
lib/src/cache_service.dart
Normal file
21
lib/src/cache_service.dart
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
|
/// An Angel [Service] that caches data from another service.
|
||||||
|
///
|
||||||
|
/// This is useful for applications of scale, where network latency
|
||||||
|
/// can have real implications on application performance.
|
||||||
|
class CacheService extends Service {
|
||||||
|
/// The underlying [Service] that represents the original data store.
|
||||||
|
final Service database;
|
||||||
|
|
||||||
|
/// The [Service] used to interface with a caching layer.
|
||||||
|
///
|
||||||
|
/// If not provided, this defaults to a [MapService].
|
||||||
|
final Service cache;
|
||||||
|
|
||||||
|
CacheService({@required this.database, Service cache})
|
||||||
|
: this.cache = cache ?? new MapService() {
|
||||||
|
assert(database != null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
name: angel_cache
|
name: angel_cache
|
||||||
dependencies:
|
dependencies:
|
||||||
angel_framework: ">=1.0.0-dev <2.0.0"
|
angel_framework: ">=1.0.0-dev <2.0.0"
|
||||||
|
intl: ^0.15.0
|
||||||
meta: ^1.0.0
|
meta: ^1.0.0
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel_test: ^1.1.0
|
angel_test: ^1.1.0
|
||||||
|
glob: ^1.0.0
|
||||||
test: ^0.12.0
|
test: ^0.12.0
|
Loading…
Reference in a new issue