Fixed a bunch of issues

This commit is contained in:
thosakwe 2016-11-23 14:50:17 -05:00
parent fc13db72ff
commit 0e5f315773
7 changed files with 111 additions and 58 deletions

View file

@ -1,6 +1,6 @@
# angel_framework # angel_framework
![version 1.0.0-dev](https://img.shields.io/badge/version-1.0.0--dev.23-red.svg) ![version 1.0.0-dev.24](https://img.shields.io/badge/version-1.0.0--dev.24-red.svg)
![build status](https://travis-ci.org/angel-dart/framework.svg) ![build status](https://travis-ci.org/angel-dart/framework.svg)
Core libraries for the Angel Framework. Core libraries for the Angel Framework.

View file

@ -73,19 +73,30 @@ class Controller {
var arg = req.params[name]; var arg = req.params[name];
if (arg == null) { if (arg == null) {
if (parameter.type.reflectedType != dynamic) { if (req.injections.containsKey(name)) {
try { args.add(req.injections[name]);
arg = app.container.make(parameter.type.reflectedType);
if (arg != null) {
args.add(arg);
continue; continue;
} }
final type = parameter.type.reflectedType;
if (req.injections.containsKey(type)) {
args.add(req.injections[type]);
continue;
}
if (type != dynamic) {
try {
args.add(app.container.make(type));
continue;
} catch (e) { } catch (e) {
// //
print(e);
print(req.injections);
} }
} }
if (!exposeMirror.reflectee.allowNull.contain(name)) if (!exposeMirror.reflectee.allowNull.contains(name))
throw new AngelHttpException.BadRequest( throw new AngelHttpException.BadRequest(
message: "Missing parameter '$name'"); message: "Missing parameter '$name'");
} else } else

View file

@ -10,26 +10,32 @@ import 'angel_base.dart';
class RequestContext extends Extensible { class RequestContext extends Extensible {
BodyParseResult _body; BodyParseResult _body;
ContentType _contentType; ContentType _contentType;
HttpRequest _io;
String _path; String _path;
HttpRequest _underlyingRequest;
/// The [Angel] instance that is responding to this request. /// The [Angel] instance that is responding to this request.
AngelBase app; AngelBase app;
/// Any cookies sent with this request. /// Any cookies sent with this request.
List<Cookie> get cookies => underlyingRequest.cookies; List<Cookie> get cookies => io.cookies;
/// All HTTP headers sent with this request. /// All HTTP headers sent with this request.
HttpHeaders get headers => underlyingRequest.headers; HttpHeaders get headers => io.headers;
/// The requested hostname. /// The requested hostname.
String get hostname => underlyingRequest.headers.value(HttpHeaders.HOST); String get hostname => io.headers.value(HttpHeaders.HOST);
/// A [Map] of values that should be DI'd.
final Map injections = {};
/// The underlying [HttpRequest] instance underneath this context.
HttpRequest get io => _io;
/// The user's IP. /// The user's IP.
String get ip => remoteAddress.address; String get ip => remoteAddress.address;
/// This request's HTTP method. /// This request's HTTP method.
String get method => underlyingRequest.method; String get method => io.method;
/// All post data submitted to the server. /// All post data submitted to the server.
Map get body => _body.body; Map get body => _body.body;
@ -51,24 +57,27 @@ class RequestContext extends Extensible {
/// The remote address requesting this resource. /// The remote address requesting this resource.
InternetAddress get remoteAddress => InternetAddress get remoteAddress =>
underlyingRequest.connectionInfo.remoteAddress; io.connectionInfo.remoteAddress;
/// The user's HTTP session. /// The user's HTTP session.
HttpSession get session => underlyingRequest.session; HttpSession get session => io.session;
/// The [Uri] instance representing the path this request is responding to. /// The [Uri] instance representing the path this request is responding to.
Uri get uri => underlyingRequest.uri; Uri get uri => io.uri;
/// Is this an **XMLHttpRequest**? /// Is this an **XMLHttpRequest**?
bool get xhr => bool get xhr =>
underlyingRequest.headers io.headers
.value("X-Requested-With") .value("X-Requested-With")
?.trim() ?.trim()
?.toLowerCase() == ?.toLowerCase() ==
'xmlhttprequest'; 'xmlhttprequest';
/// The underlying [HttpRequest] instance underneath this context. @deprecated
HttpRequest get underlyingRequest => _underlyingRequest; HttpRequest get underlyingRequest {
throw new Exception(
'`RequestContext#underlyingRequest` is deprecated. Please update your application to use the newer `RequestContext#io`.');
}
/// Magically transforms an [HttpRequest] into a [RequestContext]. /// Magically transforms an [HttpRequest] into a [RequestContext].
static Future<RequestContext> from(HttpRequest request, AngelBase app) async { static Future<RequestContext> from(HttpRequest request, AngelBase app) async {
@ -80,10 +89,14 @@ class RequestContext extends Extensible {
.toString() .toString()
.replaceAll("?" + request.uri.query, "") .replaceAll("?" + request.uri.query, "")
.replaceAll(new RegExp(r'/+$'), ''); .replaceAll(new RegExp(r'/+$'), '');
ctx._underlyingRequest = request; ctx._io = request;
ctx._body = await parseBody(request); ctx._body = await parseBody(request);
return ctx; return ctx;
} }
void inject(Type type, value) {
injections[type] = value;
}
} }

View file

@ -25,16 +25,22 @@ class ResponseContext extends Extensible {
/// Sets the status code to be sent with this response. /// Sets the status code to be sent with this response.
void status(int code) { void status(int code) {
underlyingResponse.statusCode = code; io.statusCode = code;
} }
/// The underlying [HttpResponse] under this instance. /// The underlying [HttpResponse] under this instance.
final HttpResponse underlyingResponse; final HttpResponse io;
ResponseContext(this.underlyingResponse, this.app); @deprecated
HttpResponse get underlyingRequest {
throw new Exception(
'`ResponseContext#underlyingResponse` is deprecated. Please update your application to use the newer `ResponseContext#io`.');
}
ResponseContext(this.io, this.app);
/// Any and all cookies to be sent to the user. /// Any and all cookies to be sent to the user.
List<Cookie> get cookies => underlyingResponse.cookies; List<Cookie> get cookies => io.cookies;
/// Set this to true if you will manually close the response. /// Set this to true if you will manually close the response.
bool willCloseItself = false; bool willCloseItself = false;
@ -57,9 +63,9 @@ class ResponseContext extends Extensible {
/// Sets a response header to the given value, or retrieves its value. /// Sets a response header to the given value, or retrieves its value.
header(String key, [String value]) { header(String key, [String value]) {
if (value == null) if (value == null)
return underlyingResponse.headers[key]; return io.headers[key];
else else
underlyingResponse.headers.set(key, value); io.headers.set(key, value);
} }
/// Serializes JSON to the response. /// Serializes JSON to the response.
@ -163,7 +169,7 @@ class ResponseContext extends Extensible {
header(HttpHeaders.CONTENT_TYPE, lookupMimeType(file.path)); header(HttpHeaders.CONTENT_TYPE, lookupMimeType(file.path));
willCloseItself = true; willCloseItself = true;
await file.openRead().pipe(underlyingResponse); await file.openRead().pipe(io);
} }
/// Writes data to the response. /// Writes data to the response.

View file

@ -105,6 +105,8 @@ class Angel extends AngelBase {
/// Loads some base dependencies into the service container. /// Loads some base dependencies into the service container.
void bootstrapContainer() { void bootstrapContainer() {
container.singleton(this, as: AngelBase); container.singleton(this, as: AngelBase);
container.singleton(this, as: Routable);
container.singleton(this, as: Router);
container.singleton(this); container.singleton(this);
if (runtimeType != Angel) container.singleton(this, as: Angel); if (runtimeType != Angel) container.singleton(this, as: Angel);
@ -130,7 +132,7 @@ class Angel extends AngelBase {
} }
if (handler is RawRequestHandler) { if (handler is RawRequestHandler) {
var result = await handler(req.underlyingRequest); var result = await handler(req.io);
if (result is bool) if (result is bool)
return result == true; return result == true;
else if (result != null) { else if (result != null) {
@ -167,8 +169,8 @@ class Angel extends AngelBase {
} }
res.willCloseItself = true; res.willCloseItself = true;
res.underlyingResponse.write(god.serialize(handler)); res.io.write(god.serialize(handler));
await res.underlyingResponse.close(); await res.io.close();
return false; return false;
} }
@ -177,23 +179,34 @@ class Angel extends AngelBase {
final req = await RequestContext.from(request, this); final req = await RequestContext.from(request, this);
final res = new ResponseContext(request.response, this); final res = new ResponseContext(request.response, this);
String requestedUrl = request.uri String requestedUrl = request.uri.path.replaceAll(_straySlashes, '');
.path
.replaceAll(_straySlashes, '');
if (requestedUrl.isEmpty) requestedUrl = '/'; if (requestedUrl.isEmpty) requestedUrl = '/';
final route = resolve(requestedUrl, method: request.method); final resolved = [];
_printDebug('Resolved ${requestedUrl} -> $route');
if (requestedUrl == '/') {
resolved.add(root.indexRoute);
} else {
resolved.addAll(resolveAll(requestedUrl, method: request.method));
final route = resolved.first;
req.params.addAll(route?.parseParameters(requestedUrl) ?? {}); req.params.addAll(route?.parseParameters(requestedUrl) ?? {});
req.inject(Match, route.match(requestedUrl));
}
final handlerSequence = []..addAll(before); final pipeline = []..addAll(before);
if (route != null) handlerSequence.addAll(route.handlerSequence);
handlerSequence.addAll(after);
_printDebug('Handler sequence on $requestedUrl: $handlerSequence'); if (resolved.isNotEmpty) {
for (final route in resolved) {
pipeline.addAll(route.handlerSequence);
}
}
for (final handler in handlerSequence) { pipeline.addAll(after);
_printDebug('Handler sequence on $requestedUrl: $pipeline');
for (final handler in pipeline) {
try { try {
_printDebug('Executing handler: $handler'); _printDebug('Executing handler: $handler');
final result = await executeHandler(handler, req, res); final result = await executeHandler(handler, req, res);
@ -249,8 +262,7 @@ class Angel extends AngelBase {
// Run a function after injecting from service container // Run a function after injecting from service container
Future runContained(Function handler, RequestContext req, ResponseContext res, Future runContained(Function handler, RequestContext req, ResponseContext res,
{Map<String, dynamic> namedParameters, {Map<String, dynamic> namedParameters}) async {
Map<Type, dynamic> injecting}) async {
ClosureMirror closureMirror = reflect(handler); ClosureMirror closureMirror = reflect(handler);
List args = []; List args = [];
@ -261,9 +273,9 @@ class Angel extends AngelBase {
args.add(res); args.add(res);
else { else {
// First, search to see if we can map this to a type // First, search to see if we can map this to a type
if (parameter.type.reflectedType != dynamic) { if (req.injections.containsKey(parameter.type.reflectedType)) {
args.add(container.make(parameter.type.reflectedType, args.add(req.injections[parameter.type.reflectedType]);
namedParameters: namedParameters, injecting: injecting)); continue;
} else { } else {
String name = MirrorSystem.getName(parameter.simpleName); String name = MirrorSystem.getName(parameter.simpleName);
@ -273,7 +285,12 @@ class Angel extends AngelBase {
args.add(req); args.add(req);
else if (name == "res") else if (name == "res")
args.add(res); args.add(res);
else { else if (req.injections.containsKey(name))
args.add(req.injections[name]);
else if (parameter.type.reflectedType != dynamic) {
args.add(container.make(parameter.type.reflectedType,
injecting: req.injections));
} else {
throw new Exception( throw new Exception(
"Cannot resolve parameter '$name' within handler."); "Cannot resolve parameter '$name' within handler.");
} }
@ -324,20 +341,22 @@ class Angel extends AngelBase {
/// Provide paths to a certificate chain and server key (both .pem). /// Provide paths to a certificate chain and server key (both .pem).
/// If no password is provided, a random one will be generated upon running /// If no password is provided, a random one will be generated upon running
/// the server. /// the server.
Angel.secure(String certificateChainPath, String serverKeyPath, factory Angel.secure(String certificateChainPath, String serverKeyPath,
{bool debug: false, String password}) {bool debug: false, String password}) {
: super(debug: debug) { final app = new Angel(debug: debug);
bootstrapContainer();
_serverGenerator = (InternetAddress address, int port) async { app._serverGenerator = (InternetAddress address, int port) async {
var certificateChain = var certificateChain =
Platform.script.resolve(certificateChainPath).toFilePath(); Platform.script.resolve(certificateChainPath).toFilePath();
var serverKey = Platform.script.resolve(serverKeyPath).toFilePath(); var serverKey = Platform.script.resolve(serverKeyPath).toFilePath();
var serverContext = new SecurityContext(); var serverContext = new SecurityContext();
serverContext.useCertificateChain(certificateChain); serverContext.useCertificateChain(certificateChain);
serverContext.usePrivateKey(serverKey, serverContext.usePrivateKey(serverKey,
password: password ?? _randomString(8)); password: password ?? app._randomString(8));
return await HttpServer.bindSecure(address, port, serverContext); return await HttpServer.bindSecure(address, port, serverContext);
}; };
return app;
} }
} }

View file

@ -1,5 +1,5 @@
name: angel_framework name: angel_framework
version: 1.0.0-dev.23 version: 1.0.0-dev.24
description: Core libraries for the Angel framework. description: Core libraries for the Angel framework.
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_framework homepage: https://github.com/angel-dart/angel_framework

View file

@ -22,12 +22,12 @@ main() {
app.container.singleton(new Todo(text: TEXT, over: OVER)); app.container.singleton(new Todo(text: TEXT, over: OVER));
app.get("/errands", (Todo singleton) => singleton); app.get("/errands", (Todo singleton) => singleton);
app.get("/errands3", (Errand singleton, Todo foo, RequestContext req) => singleton.text); app.get("/errands3",
(Errand singleton, Todo foo, RequestContext req) => singleton.text);
await app.configure(new SingletonController()); await app.configure(new SingletonController());
await app.configure(new ErrandController()); await app.configure(new ErrandController());
server = await app.startServer(); server = await app.startServer();
print('server: $server, httpServer: ${app.httpServer}');
url = "http://${server.address.host}:${server.port}"; url = "http://${server.address.host}:${server.port}";
}); });
@ -77,7 +77,11 @@ class SingletonController extends Controller {
@Expose("/errands4") @Expose("/errands4")
class ErrandController extends Controller { class ErrandController extends Controller {
@Expose("/") @Expose("/")
errand(Errand errand) => errand.text; errand(Errand errand, Match match) {
expect(match, isNotNull);
print('Match: ${match.group(0)}');
return errand.text;
}
} }
class Errand { class Errand {