Optimizations + caching
This commit is contained in:
parent
4357a102da
commit
685205adde
3 changed files with 63 additions and 18 deletions
|
@ -39,6 +39,7 @@ String _pathify(String path) {
|
|||
|
||||
/// Represents a virtual location within an application.
|
||||
class Route {
|
||||
final Map<String, Match> _cache = {};
|
||||
final List<Route> _children = [];
|
||||
final List _handlers = [];
|
||||
RegExp _head;
|
||||
|
@ -329,7 +330,7 @@ class Route {
|
|||
|
||||
/// Attempts to match a path against this route.
|
||||
Match match(String path) =>
|
||||
matcher.firstMatch(path.replaceAll(_straySlashes, ''));
|
||||
_cache.putIfAbsent(path, () => matcher.firstMatch(path.replaceAll(_straySlashes, '')));
|
||||
|
||||
/// Extracts route parameters from a given path.
|
||||
Map<String, String> parseParameters(String requestPath) {
|
||||
|
|
|
@ -16,10 +16,12 @@ final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
|
|||
|
||||
/// An abstraction over complex [Route] trees. Use this instead of the raw API. :)
|
||||
class Router {
|
||||
final List<_ChainedRouter> _chained = [];
|
||||
final Map<String, Iterable<RoutingResult>> _cache = {};
|
||||
//final List<_ChainedRouter> _chained = [];
|
||||
final List _middleware = [];
|
||||
final Map<Pattern, Router> _mounted = {};
|
||||
final List<Route> _routes = [];
|
||||
bool _useCache = false;
|
||||
|
||||
/// Set to `true` to print verbose debug output when interacting with this route.
|
||||
bool debug = false;
|
||||
|
@ -53,11 +55,19 @@ class Router {
|
|||
/// Not recommended.
|
||||
Router({this.debug: false});
|
||||
|
||||
/// Enables the use of a cache to eliminate the overhead of consecutive resolutions of the same path.
|
||||
void enableCache() {
|
||||
_useCache = true;
|
||||
}
|
||||
|
||||
/// Adds a route that responds to the given path
|
||||
/// for requests with the given method (case-insensitive).
|
||||
/// Provide '*' as the method to respond to all methods.
|
||||
Route addRoute(String method, Pattern path, Object handler,
|
||||
{List middleware: const []}) {
|
||||
if (_useCache == true)
|
||||
throw new StateError('Cannot add routes after caching is enabled.');
|
||||
|
||||
// Check if any mounted routers can match this
|
||||
final handlers = [handler];
|
||||
|
||||
|
@ -258,26 +268,22 @@ class Router {
|
|||
requestMiddleware[name] = middleware;
|
||||
}
|
||||
|
||||
RoutingResult _dumpResult(String path, RoutingResult result) {
|
||||
// _printDebug('Resolved "/$path" to ${result.route}');
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Finds the first [Route] that matches the given path,
|
||||
/// with the given method.
|
||||
bool resolve(String absolute, String relative, List<RoutingResult> out,
|
||||
{String method: 'GET', bool strip: true}) {
|
||||
final cleanAbsolute =
|
||||
strip == false ? absolute : stripStraySlashes(absolute);
|
||||
//final cleanAbsolute =
|
||||
// strip == false ? absolute : stripStraySlashes(absolute);
|
||||
final cleanRelative =
|
||||
strip == false ? relative : stripStraySlashes(relative);
|
||||
final segments = cleanRelative.split('/').where((str) => str.isNotEmpty);
|
||||
//final segments = cleanRelative.split('/').where((str) => str.isNotEmpty);
|
||||
bool success = false;
|
||||
//print(
|
||||
// 'Now resolving $method "/$cleanRelative", absolute: $cleanAbsolute');
|
||||
//print('Path segments: ${segments.toList()}');
|
||||
|
||||
for (Route route in routes) {
|
||||
/* // No longer necessary
|
||||
if (route is SymlinkRoute && route._head != null && segments.isNotEmpty) {
|
||||
final s = [];
|
||||
|
||||
|
@ -313,18 +319,17 @@ class Router {
|
|||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (route.method == '*' || route.method == method) {
|
||||
final match = route.match(cleanRelative);
|
||||
|
||||
if (match != null) {
|
||||
var result = _dumpResult(
|
||||
cleanRelative,
|
||||
new RoutingResult(
|
||||
match: match,
|
||||
params: route.parseParameters(cleanRelative),
|
||||
shallowRoute: route,
|
||||
shallowRouter: this));
|
||||
var result = new RoutingResult(
|
||||
match: match,
|
||||
params: route.parseParameters(cleanRelative),
|
||||
shallowRoute: route,
|
||||
shallowRouter: this);
|
||||
out.add(result);
|
||||
success = true;
|
||||
}
|
||||
|
@ -345,6 +350,16 @@ class Router {
|
|||
/// with the given method.
|
||||
Iterable<RoutingResult> resolveAll(String absolute, String relative,
|
||||
{String method: 'GET', bool strip: true}) {
|
||||
if (_useCache == true) {
|
||||
return _cache.putIfAbsent(absolute,
|
||||
() => _resolveAll(absolute, relative, method: method, strip: strip));
|
||||
}
|
||||
|
||||
return _resolveAll(absolute, relative, method: method, strip: strip);
|
||||
}
|
||||
|
||||
Iterable<RoutingResult> _resolveAll(String absolute, String relative,
|
||||
{String method: 'GET', bool strip: true}) {
|
||||
final List<RoutingResult> results = [];
|
||||
resolve(absolute, relative, results, method: method, strip: strip);
|
||||
|
||||
|
@ -475,3 +490,32 @@ class _ChainedRouter extends Router {
|
|||
return piped;
|
||||
}
|
||||
}
|
||||
|
||||
/// Optimizes a router by condensing all its routes into one level.
|
||||
Router flatten(Router router) {
|
||||
var flattened = new Router(debug: router.debug == true)
|
||||
..requestMiddleware.addAll(router.requestMiddleware)
|
||||
..enableCache();
|
||||
|
||||
for (var route in router.routes) {
|
||||
if (route is SymlinkRoute) {
|
||||
var base = route.path.replaceAll(_straySlashes, '');
|
||||
var child = flatten(route.router);
|
||||
flattened.requestMiddleware.addAll(child.requestMiddleware);
|
||||
|
||||
for (var route in child.routes) {
|
||||
var path = route.path.replaceAll(_straySlashes, '');
|
||||
var joined = '$base/$path'.replaceAll(_straySlashes, '');
|
||||
flattened.addRoute(route.method, joined.replaceAll(_straySlashes, ''),
|
||||
route.handlers.last,
|
||||
middleware:
|
||||
route.handlers.take(route.handlers.length - 1).toList());
|
||||
}
|
||||
} else {
|
||||
flattened.addRoute(route.method, route.path, route.handlers.last,
|
||||
middleware: route.handlers.take(route.handlers.length - 1).toList());
|
||||
}
|
||||
}
|
||||
|
||||
return flattened;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: angel_route
|
||||
description: A powerful, isomorphic routing library for Dart.
|
||||
version: 2.0.0
|
||||
version: 2.0.2
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_route
|
||||
dev_dependencies:
|
||||
|
|
Loading…
Reference in a new issue