2016-09-15 19:53:01 +00:00
|
|
|
library angel_framework.http.controller;
|
|
|
|
|
|
|
|
import 'dart:async';
|
|
|
|
import 'dart:mirrors';
|
2016-10-22 20:41:36 +00:00
|
|
|
import 'package:angel_route/angel_route.dart';
|
2016-09-15 19:53:01 +00:00
|
|
|
import 'angel_base.dart';
|
|
|
|
import 'angel_http_exception.dart';
|
|
|
|
import 'metadata.dart';
|
|
|
|
import 'request_context.dart';
|
|
|
|
import 'response_context.dart';
|
|
|
|
import 'routable.dart';
|
2016-06-27 00:20:42 +00:00
|
|
|
|
|
|
|
class Controller {
|
2016-09-15 19:53:01 +00:00
|
|
|
AngelBase app;
|
2016-06-27 00:20:42 +00:00
|
|
|
List middleware = [];
|
2016-09-15 19:53:01 +00:00
|
|
|
Map<String, Route> routeMappings = {};
|
2016-06-27 00:20:42 +00:00
|
|
|
Expose exposeDecl;
|
|
|
|
|
2016-10-22 20:41:36 +00:00
|
|
|
Future call(AngelBase app) async {
|
|
|
|
this.app = app;
|
|
|
|
|
2016-06-27 00:20:42 +00:00
|
|
|
// Load global expose decl
|
|
|
|
ClassMirror classMirror = reflectClass(this.runtimeType);
|
|
|
|
|
|
|
|
for (InstanceMirror metadatum in classMirror.metadata) {
|
|
|
|
if (metadatum.reflectee is Expose) {
|
|
|
|
exposeDecl = metadatum.reflectee;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-22 20:41:36 +00:00
|
|
|
if (exposeDecl == null) {
|
2016-06-27 00:20:42 +00:00
|
|
|
throw new Exception(
|
|
|
|
"All controllers must carry an @Expose() declaration.");
|
2016-10-22 20:41:36 +00:00
|
|
|
}
|
|
|
|
|
2016-11-28 21:48:00 +00:00
|
|
|
final routable = new Routable(debug: true);
|
|
|
|
configureRoutes(routable);
|
|
|
|
|
|
|
|
app.use(exposeDecl.path, routable);
|
2016-11-23 09:10:47 +00:00
|
|
|
TypeMirror typeMirror = reflectType(this.runtimeType);
|
|
|
|
String name = exposeDecl.as;
|
2016-06-27 00:20:42 +00:00
|
|
|
|
2016-11-23 09:10:47 +00:00
|
|
|
if (name == null || name.isEmpty)
|
|
|
|
name = MirrorSystem.getName(typeMirror.simpleName);
|
|
|
|
|
|
|
|
app.controllers[name] = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
_callback(InstanceMirror instanceMirror, Routable routable, List handlers) {
|
|
|
|
return (Symbol key, MethodMirror methodMirror) {
|
2016-10-22 20:41:36 +00:00
|
|
|
if (methodMirror.isRegularMethod &&
|
|
|
|
key != #toString &&
|
|
|
|
key != #noSuchMethod &&
|
|
|
|
key != #call &&
|
|
|
|
key != #equals &&
|
2016-06-27 00:20:42 +00:00
|
|
|
key != #==) {
|
2016-10-22 20:41:36 +00:00
|
|
|
InstanceMirror exposeMirror = methodMirror.metadata.firstWhere(
|
|
|
|
(mirror) => mirror.reflectee is Expose,
|
|
|
|
orElse: () => null);
|
2016-06-27 00:20:42 +00:00
|
|
|
|
|
|
|
if (exposeMirror != null) {
|
2016-10-22 20:41:36 +00:00
|
|
|
RequestHandler handler =
|
|
|
|
(RequestContext req, ResponseContext res) async {
|
2016-06-27 00:20:42 +00:00
|
|
|
List args = [];
|
|
|
|
|
2016-07-04 18:06:31 +00:00
|
|
|
// Load parameters, and execute
|
|
|
|
for (int i = 0; i < methodMirror.parameters.length; i++) {
|
|
|
|
ParameterMirror parameter = methodMirror.parameters[i];
|
|
|
|
if (parameter.type.reflectedType == RequestContext)
|
|
|
|
args.add(req);
|
|
|
|
else if (parameter.type.reflectedType == ResponseContext)
|
|
|
|
args.add(res);
|
2016-10-22 20:41:36 +00:00
|
|
|
else {
|
|
|
|
String name = MirrorSystem.getName(parameter.simpleName);
|
2016-07-04 18:06:31 +00:00
|
|
|
var arg = req.params[name];
|
|
|
|
|
2016-09-17 16:12:25 +00:00
|
|
|
if (arg == null) {
|
2016-11-23 19:50:17 +00:00
|
|
|
if (req.injections.containsKey(name)) {
|
|
|
|
args.add(req.injections[name]);
|
|
|
|
continue;
|
2016-12-21 23:40:18 +00:00
|
|
|
} else if (name == "req") {
|
|
|
|
args.add(req);
|
|
|
|
continue;
|
|
|
|
} else if (name == "res") {
|
|
|
|
args.add(res);
|
|
|
|
continue;
|
2016-11-23 19:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
final type = parameter.type.reflectedType;
|
|
|
|
|
|
|
|
if (req.injections.containsKey(type)) {
|
|
|
|
args.add(req.injections[type]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != dynamic) {
|
2016-09-17 16:12:25 +00:00
|
|
|
try {
|
2016-11-23 19:50:17 +00:00
|
|
|
args.add(app.container.make(type));
|
|
|
|
continue;
|
2016-10-22 20:41:36 +00:00
|
|
|
} catch (e) {
|
2016-09-17 16:12:25 +00:00
|
|
|
//
|
2016-11-23 19:50:17 +00:00
|
|
|
print(e);
|
|
|
|
print(req.injections);
|
2016-09-17 16:12:25 +00:00
|
|
|
}
|
|
|
|
}
|
2016-06-27 00:20:42 +00:00
|
|
|
|
2016-11-23 19:50:17 +00:00
|
|
|
if (!exposeMirror.reflectee.allowNull.contains(name))
|
2016-10-22 20:41:36 +00:00
|
|
|
throw new AngelHttpException.BadRequest(
|
|
|
|
message: "Missing parameter '$name'");
|
|
|
|
} else
|
|
|
|
args.add(arg);
|
2016-07-04 18:06:31 +00:00
|
|
|
}
|
2016-06-27 00:20:42 +00:00
|
|
|
}
|
2016-07-04 18:06:31 +00:00
|
|
|
|
2016-10-22 20:41:36 +00:00
|
|
|
return await instanceMirror.invoke(key, args).reflectee;
|
2016-06-27 00:20:42 +00:00
|
|
|
};
|
2016-10-22 20:41:36 +00:00
|
|
|
|
2016-11-23 09:10:47 +00:00
|
|
|
final middleware = []
|
|
|
|
..addAll(handlers)
|
|
|
|
..addAll(exposeMirror.reflectee.middleware);
|
|
|
|
|
2016-10-22 20:41:36 +00:00
|
|
|
final route = routable.addRoute(exposeMirror.reflectee.method,
|
|
|
|
exposeMirror.reflectee.path, handler,
|
2016-11-23 09:10:47 +00:00
|
|
|
middleware: middleware);
|
2016-06-27 00:20:42 +00:00
|
|
|
|
|
|
|
String name = exposeMirror.reflectee.as;
|
|
|
|
|
2016-10-22 20:41:36 +00:00
|
|
|
if (name == null || name.isEmpty) name = MirrorSystem.getName(key);
|
2016-06-27 00:20:42 +00:00
|
|
|
|
2016-09-15 19:53:01 +00:00
|
|
|
routeMappings[name] = route;
|
2016-06-27 00:20:42 +00:00
|
|
|
}
|
|
|
|
}
|
2016-11-23 09:10:47 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-11-28 21:48:00 +00:00
|
|
|
void configureRoutes(Routable routable) {
|
|
|
|
ClassMirror classMirror = reflectClass(this.runtimeType);
|
2016-11-23 09:10:47 +00:00
|
|
|
InstanceMirror instanceMirror = reflect(this);
|
2016-11-28 21:48:00 +00:00
|
|
|
final handlers = []..addAll(exposeDecl.middleware)..addAll(middleware);
|
2016-11-23 09:10:47 +00:00
|
|
|
final callback = _callback(instanceMirror, routable, handlers);
|
|
|
|
classMirror.instanceMembers.forEach(callback);
|
2016-09-15 19:53:01 +00:00
|
|
|
}
|
2016-10-22 20:41:36 +00:00
|
|
|
}
|