Fixed preprocessing?
This commit is contained in:
parent
b05fc64f1f
commit
ce28fa338b
2 changed files with 61 additions and 49 deletions
|
@ -3,12 +3,11 @@ library angel_framework.http.controller;
|
|||
import 'dart:async';
|
||||
import 'dart:mirrors';
|
||||
import 'package:angel_route/angel_route.dart';
|
||||
import 'angel_http_exception.dart';
|
||||
import 'metadata.dart';
|
||||
import 'request_context.dart';
|
||||
import 'response_context.dart';
|
||||
import 'routable.dart';
|
||||
import 'server.dart' show Angel;
|
||||
import 'server.dart' show Angel, preInject;
|
||||
|
||||
/// Contains a list of the data required for a DI-enabled method to run.
|
||||
///
|
||||
|
@ -30,7 +29,6 @@ class Controller {
|
|||
final bool debug;
|
||||
List middleware = [];
|
||||
Map<String, Route> routeMappings = {};
|
||||
Expose exposeDecl;
|
||||
|
||||
Controller({this.debug: false});
|
||||
|
||||
|
@ -39,9 +37,7 @@ class Controller {
|
|||
|
||||
// Load global expose decl
|
||||
ClassMirror classMirror = reflectClass(this.runtimeType);
|
||||
Expose exposeDecl = classMirror.metadata
|
||||
.map((m) => m.reflectee)
|
||||
.firstWhere((r) => r is Expose, orElse: () => null);
|
||||
Expose exposeDecl = findExpose();
|
||||
|
||||
if (exposeDecl == null) {
|
||||
throw new Exception(
|
||||
|
@ -83,7 +79,6 @@ class Controller {
|
|||
|
||||
var reflectedMethod = instanceMirror.getField(methodName).reflectee;
|
||||
var middleware = []..addAll(handlers)..addAll(exposeDecl.middleware);
|
||||
var injection = new InjectionRequest();
|
||||
|
||||
// Check if normal
|
||||
if (method.parameters.length == 2 &&
|
||||
|
@ -95,26 +90,8 @@ class Controller {
|
|||
return;
|
||||
}
|
||||
|
||||
// Load parameters
|
||||
for (var parameter in method.parameters) {
|
||||
var name = MirrorSystem.getName(parameter.simpleName);
|
||||
var type = parameter.type.reflectedType;
|
||||
|
||||
if (type == RequestContext || type == ResponseContext) {
|
||||
injection.required.add(type);
|
||||
} else if (name == 'req') {
|
||||
injection.required.add(RequestContext);
|
||||
} else if (name == 'res') {
|
||||
injection.required.add(ResponseContext);
|
||||
} else if (type == dynamic) {
|
||||
injection.required.add(name);
|
||||
} else {
|
||||
injection.required.add([name, type]);
|
||||
}
|
||||
}
|
||||
|
||||
routable.addRoute(exposeDecl.method, exposeDecl.path,
|
||||
handleContained(reflectedMethod, injection),
|
||||
handleContained(reflectedMethod, preInject(reflectedMethod)),
|
||||
middleware: middleware);
|
||||
}
|
||||
};
|
||||
|
@ -122,6 +99,12 @@ class Controller {
|
|||
|
||||
/// Used to add additional routes to the router from within a [Controller].
|
||||
void configureRoutes(Routable routable) {}
|
||||
|
||||
/// Finds the [Expose] declaration for this class.
|
||||
Expose findExpose() => reflectClass(runtimeType)
|
||||
.metadata
|
||||
.map((m) => m.reflectee)
|
||||
.firstWhere((r) => r is Expose, orElse: () => null);
|
||||
}
|
||||
|
||||
/// Handles a request with a DI-enabled handler.
|
||||
|
@ -140,7 +123,7 @@ RequestHandler handleContained(handler, InjectionRequest injection) {
|
|||
.containsKey(requirement))
|
||||
args.add(req.injections[requirement]);
|
||||
else {
|
||||
throw new Exception(
|
||||
throw new ArgumentError(
|
||||
"Cannot resolve parameter '$requirement' within handler.");
|
||||
}
|
||||
args.add(req.params[requirement]);
|
||||
|
|
|
@ -126,6 +126,7 @@ class Angel extends AngelBase {
|
|||
Future<HttpServer> startServer([InternetAddress address, int port]) async {
|
||||
final host = address ?? InternetAddress.LOOPBACK_IP_V4;
|
||||
this.httpServer = await _serverGenerator(host, port ?? 0);
|
||||
preprocessRoutes();
|
||||
return httpServer..listen(handleRequest);
|
||||
}
|
||||
|
||||
|
@ -284,6 +285,27 @@ class Angel extends AngelBase {
|
|||
}
|
||||
}
|
||||
|
||||
/// Preprocesses all routes, and eliminates the burden of reflecting handlers
|
||||
/// at run-time.
|
||||
void preprocessRoutes() {
|
||||
_add(v) {
|
||||
if (v is Function && !_preContained.containsKey(v)) {
|
||||
_preContained[v] = preInject(v);
|
||||
}
|
||||
}
|
||||
|
||||
void _walk(Router router) {
|
||||
router.requestMiddleware.forEach((k, v) => _add(v));
|
||||
router.middleware.forEach(_add);
|
||||
router.routes
|
||||
.where((r) => r is SymlinkRoute)
|
||||
.map((SymlinkRoute r) => r.router)
|
||||
.forEach(_walk);
|
||||
}
|
||||
|
||||
_walk(this);
|
||||
}
|
||||
|
||||
/// Run a function after injecting from service container.
|
||||
/// If this function has been reflected before, then
|
||||
/// the execution will be faster, as the injection requirements were stored beforehand.
|
||||
|
@ -299,26 +321,7 @@ class Angel extends AngelBase {
|
|||
/// Runs with DI, and *always* reflects. Prefer [runContained].
|
||||
Future runReflected(
|
||||
Function handler, RequestContext req, ResponseContext res) async {
|
||||
ClosureMirror closureMirror = reflect(handler);
|
||||
var injection = new InjectionRequest();
|
||||
|
||||
// Load parameters
|
||||
for (var parameter in closureMirror.function.parameters) {
|
||||
var name = MirrorSystem.getName(parameter.simpleName);
|
||||
var type = parameter.type.reflectedType;
|
||||
|
||||
if (type == RequestContext || type == ResponseContext) {
|
||||
injection.required.add(type);
|
||||
} else if (name == 'req') {
|
||||
injection.required.add(RequestContext);
|
||||
} else if (name == 'res') {
|
||||
injection.required.add(ResponseContext);
|
||||
} else if (type == dynamic) {
|
||||
injection.required.add(name);
|
||||
} else {
|
||||
injection.required.add([name, type]);
|
||||
}
|
||||
}
|
||||
var injection = preInjection(handler);
|
||||
|
||||
_preContained[handler] = injection;
|
||||
return handleContained(handler, injection);
|
||||
|
@ -330,13 +333,13 @@ class Angel extends AngelBase {
|
|||
await configurer(this);
|
||||
|
||||
if (configurer is Controller)
|
||||
_onController.add(controllers[configurer.exposeDecl.path] = configurer);
|
||||
_onController.add(controllers[configurer.findExpose().path] = configurer);
|
||||
}
|
||||
|
||||
/// Fallback when an error is thrown while handling a request.
|
||||
void failSilently(HttpRequest request, ResponseContext res) {}
|
||||
|
||||
/// Starts the server.
|
||||
/// Starts the server, wrapped in a [runZoned] call.
|
||||
void listen({InternetAddress address, int port: 3000}) {
|
||||
runZoned(() async {
|
||||
await startServer(address, port);
|
||||
|
@ -433,3 +436,29 @@ class Angel extends AngelBase {
|
|||
return app;
|
||||
}
|
||||
}
|
||||
|
||||
/// Predetermines what needs to be injected for a handler to run.
|
||||
InjectionRequest preInject(Function handler) {
|
||||
ClosureMirror closureMirror = reflect(handler);
|
||||
var injection = new InjectionRequest();
|
||||
|
||||
// Load parameters
|
||||
for (var parameter in closureMirror.function.parameters) {
|
||||
var name = MirrorSystem.getName(parameter.simpleName);
|
||||
var type = parameter.type.reflectedType;
|
||||
|
||||
if (type == RequestContext || type == ResponseContext) {
|
||||
injection.required.add(type);
|
||||
} else if (name == 'req') {
|
||||
injection.required.add(RequestContext);
|
||||
} else if (name == 'res') {
|
||||
injection.required.add(ResponseContext);
|
||||
} else if (type == dynamic) {
|
||||
injection.required.add(name);
|
||||
} else {
|
||||
injection.required.add([name, type]);
|
||||
}
|
||||
}
|
||||
|
||||
return injection;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue