Fixed a bunch of issues
This commit is contained in:
parent
fc13db72ff
commit
0e5f315773
7 changed files with 111 additions and 58 deletions
|
@ -1,6 +1,6 @@
|
|||
# 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)
|
||||
|
||||
Core libraries for the Angel Framework.
|
|
@ -73,19 +73,30 @@ class Controller {
|
|||
var arg = req.params[name];
|
||||
|
||||
if (arg == null) {
|
||||
if (parameter.type.reflectedType != dynamic) {
|
||||
if (req.injections.containsKey(name)) {
|
||||
args.add(req.injections[name]);
|
||||
continue;
|
||||
}
|
||||
|
||||
final type = parameter.type.reflectedType;
|
||||
|
||||
if (req.injections.containsKey(type)) {
|
||||
args.add(req.injections[type]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type != dynamic) {
|
||||
try {
|
||||
arg = app.container.make(parameter.type.reflectedType);
|
||||
if (arg != null) {
|
||||
args.add(arg);
|
||||
continue;
|
||||
}
|
||||
args.add(app.container.make(type));
|
||||
continue;
|
||||
} catch (e) {
|
||||
//
|
||||
print(e);
|
||||
print(req.injections);
|
||||
}
|
||||
}
|
||||
|
||||
if (!exposeMirror.reflectee.allowNull.contain(name))
|
||||
if (!exposeMirror.reflectee.allowNull.contains(name))
|
||||
throw new AngelHttpException.BadRequest(
|
||||
message: "Missing parameter '$name'");
|
||||
} else
|
||||
|
|
|
@ -10,26 +10,32 @@ import 'angel_base.dart';
|
|||
class RequestContext extends Extensible {
|
||||
BodyParseResult _body;
|
||||
ContentType _contentType;
|
||||
HttpRequest _io;
|
||||
String _path;
|
||||
HttpRequest _underlyingRequest;
|
||||
|
||||
/// The [Angel] instance that is responding to this request.
|
||||
AngelBase app;
|
||||
|
||||
/// 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.
|
||||
HttpHeaders get headers => underlyingRequest.headers;
|
||||
HttpHeaders get headers => io.headers;
|
||||
|
||||
/// 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.
|
||||
String get ip => remoteAddress.address;
|
||||
|
||||
/// This request's HTTP method.
|
||||
String get method => underlyingRequest.method;
|
||||
String get method => io.method;
|
||||
|
||||
/// All post data submitted to the server.
|
||||
Map get body => _body.body;
|
||||
|
@ -51,24 +57,27 @@ class RequestContext extends Extensible {
|
|||
|
||||
/// The remote address requesting this resource.
|
||||
InternetAddress get remoteAddress =>
|
||||
underlyingRequest.connectionInfo.remoteAddress;
|
||||
io.connectionInfo.remoteAddress;
|
||||
|
||||
/// 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.
|
||||
Uri get uri => underlyingRequest.uri;
|
||||
Uri get uri => io.uri;
|
||||
|
||||
/// Is this an **XMLHttpRequest**?
|
||||
bool get xhr =>
|
||||
underlyingRequest.headers
|
||||
io.headers
|
||||
.value("X-Requested-With")
|
||||
?.trim()
|
||||
?.toLowerCase() ==
|
||||
'xmlhttprequest';
|
||||
|
||||
/// The underlying [HttpRequest] instance underneath this context.
|
||||
HttpRequest get underlyingRequest => _underlyingRequest;
|
||||
@deprecated
|
||||
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].
|
||||
static Future<RequestContext> from(HttpRequest request, AngelBase app) async {
|
||||
|
@ -80,10 +89,14 @@ class RequestContext extends Extensible {
|
|||
.toString()
|
||||
.replaceAll("?" + request.uri.query, "")
|
||||
.replaceAll(new RegExp(r'/+$'), '');
|
||||
ctx._underlyingRequest = request;
|
||||
ctx._io = request;
|
||||
|
||||
ctx._body = await parseBody(request);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void inject(Type type, value) {
|
||||
injections[type] = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,16 +25,22 @@ class ResponseContext extends Extensible {
|
|||
|
||||
/// Sets the status code to be sent with this response.
|
||||
void status(int code) {
|
||||
underlyingResponse.statusCode = code;
|
||||
io.statusCode = code;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
List<Cookie> get cookies => underlyingResponse.cookies;
|
||||
List<Cookie> get cookies => io.cookies;
|
||||
|
||||
/// Set this to true if you will manually close the response.
|
||||
bool willCloseItself = false;
|
||||
|
@ -57,9 +63,9 @@ class ResponseContext extends Extensible {
|
|||
/// Sets a response header to the given value, or retrieves its value.
|
||||
header(String key, [String value]) {
|
||||
if (value == null)
|
||||
return underlyingResponse.headers[key];
|
||||
return io.headers[key];
|
||||
else
|
||||
underlyingResponse.headers.set(key, value);
|
||||
io.headers.set(key, value);
|
||||
}
|
||||
|
||||
/// Serializes JSON to the response.
|
||||
|
@ -163,7 +169,7 @@ class ResponseContext extends Extensible {
|
|||
|
||||
header(HttpHeaders.CONTENT_TYPE, lookupMimeType(file.path));
|
||||
willCloseItself = true;
|
||||
await file.openRead().pipe(underlyingResponse);
|
||||
await file.openRead().pipe(io);
|
||||
}
|
||||
|
||||
/// Writes data to the response.
|
||||
|
|
|
@ -105,6 +105,8 @@ class Angel extends AngelBase {
|
|||
/// Loads some base dependencies into the service container.
|
||||
void bootstrapContainer() {
|
||||
container.singleton(this, as: AngelBase);
|
||||
container.singleton(this, as: Routable);
|
||||
container.singleton(this, as: Router);
|
||||
container.singleton(this);
|
||||
|
||||
if (runtimeType != Angel) container.singleton(this, as: Angel);
|
||||
|
@ -130,7 +132,7 @@ class Angel extends AngelBase {
|
|||
}
|
||||
|
||||
if (handler is RawRequestHandler) {
|
||||
var result = await handler(req.underlyingRequest);
|
||||
var result = await handler(req.io);
|
||||
if (result is bool)
|
||||
return result == true;
|
||||
else if (result != null) {
|
||||
|
@ -167,8 +169,8 @@ class Angel extends AngelBase {
|
|||
}
|
||||
|
||||
res.willCloseItself = true;
|
||||
res.underlyingResponse.write(god.serialize(handler));
|
||||
await res.underlyingResponse.close();
|
||||
res.io.write(god.serialize(handler));
|
||||
await res.io.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -177,23 +179,34 @@ class Angel extends AngelBase {
|
|||
|
||||
final req = await RequestContext.from(request, this);
|
||||
final res = new ResponseContext(request.response, this);
|
||||
String requestedUrl = request.uri
|
||||
.path
|
||||
.replaceAll(_straySlashes, '');
|
||||
String requestedUrl = request.uri.path.replaceAll(_straySlashes, '');
|
||||
|
||||
if (requestedUrl.isEmpty) requestedUrl = '/';
|
||||
|
||||
final route = resolve(requestedUrl, method: request.method);
|
||||
_printDebug('Resolved ${requestedUrl} -> $route');
|
||||
req.params.addAll(route?.parseParameters(requestedUrl) ?? {});
|
||||
final resolved = [];
|
||||
|
||||
final handlerSequence = []..addAll(before);
|
||||
if (route != null) handlerSequence.addAll(route.handlerSequence);
|
||||
handlerSequence.addAll(after);
|
||||
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.inject(Match, route.match(requestedUrl));
|
||||
}
|
||||
|
||||
_printDebug('Handler sequence on $requestedUrl: $handlerSequence');
|
||||
final pipeline = []..addAll(before);
|
||||
|
||||
for (final handler in handlerSequence) {
|
||||
if (resolved.isNotEmpty) {
|
||||
for (final route in resolved) {
|
||||
pipeline.addAll(route.handlerSequence);
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.addAll(after);
|
||||
|
||||
_printDebug('Handler sequence on $requestedUrl: $pipeline');
|
||||
|
||||
for (final handler in pipeline) {
|
||||
try {
|
||||
_printDebug('Executing handler: $handler');
|
||||
final result = await executeHandler(handler, req, res);
|
||||
|
@ -249,8 +262,7 @@ class Angel extends AngelBase {
|
|||
|
||||
// Run a function after injecting from service container
|
||||
Future runContained(Function handler, RequestContext req, ResponseContext res,
|
||||
{Map<String, dynamic> namedParameters,
|
||||
Map<Type, dynamic> injecting}) async {
|
||||
{Map<String, dynamic> namedParameters}) async {
|
||||
ClosureMirror closureMirror = reflect(handler);
|
||||
List args = [];
|
||||
|
||||
|
@ -261,9 +273,9 @@ class Angel extends AngelBase {
|
|||
args.add(res);
|
||||
else {
|
||||
// First, search to see if we can map this to a type
|
||||
if (parameter.type.reflectedType != dynamic) {
|
||||
args.add(container.make(parameter.type.reflectedType,
|
||||
namedParameters: namedParameters, injecting: injecting));
|
||||
if (req.injections.containsKey(parameter.type.reflectedType)) {
|
||||
args.add(req.injections[parameter.type.reflectedType]);
|
||||
continue;
|
||||
} else {
|
||||
String name = MirrorSystem.getName(parameter.simpleName);
|
||||
|
||||
|
@ -273,7 +285,12 @@ class Angel extends AngelBase {
|
|||
args.add(req);
|
||||
else if (name == "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(
|
||||
"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).
|
||||
/// If no password is provided, a random one will be generated upon running
|
||||
/// the server.
|
||||
Angel.secure(String certificateChainPath, String serverKeyPath,
|
||||
{bool debug: false, String password})
|
||||
: super(debug: debug) {
|
||||
bootstrapContainer();
|
||||
_serverGenerator = (InternetAddress address, int port) async {
|
||||
factory Angel.secure(String certificateChainPath, String serverKeyPath,
|
||||
{bool debug: false, String password}) {
|
||||
final app = new Angel(debug: debug);
|
||||
|
||||
app._serverGenerator = (InternetAddress address, int port) async {
|
||||
var certificateChain =
|
||||
Platform.script.resolve(certificateChainPath).toFilePath();
|
||||
var serverKey = Platform.script.resolve(serverKeyPath).toFilePath();
|
||||
var serverContext = new SecurityContext();
|
||||
serverContext.useCertificateChain(certificateChain);
|
||||
serverContext.usePrivateKey(serverKey,
|
||||
password: password ?? _randomString(8));
|
||||
password: password ?? app._randomString(8));
|
||||
|
||||
return await HttpServer.bindSecure(address, port, serverContext);
|
||||
};
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: angel_framework
|
||||
version: 1.0.0-dev.23
|
||||
version: 1.0.0-dev.24
|
||||
description: Core libraries for the Angel framework.
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_framework
|
||||
|
|
12
test/di.dart
12
test/di.dart
|
@ -22,12 +22,12 @@ main() {
|
|||
app.container.singleton(new Todo(text: TEXT, over: OVER));
|
||||
|
||||
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 ErrandController());
|
||||
|
||||
server = await app.startServer();
|
||||
print('server: $server, httpServer: ${app.httpServer}');
|
||||
url = "http://${server.address.host}:${server.port}";
|
||||
});
|
||||
|
||||
|
@ -77,7 +77,11 @@ class SingletonController extends Controller {
|
|||
@Expose("/errands4")
|
||||
class ErrandController extends Controller {
|
||||
@Expose("/")
|
||||
errand(Errand errand) => errand.text;
|
||||
errand(Errand errand, Match match) {
|
||||
expect(match, isNotNull);
|
||||
print('Match: ${match.group(0)}');
|
||||
return errand.text;
|
||||
}
|
||||
}
|
||||
|
||||
class Errand {
|
||||
|
@ -85,4 +89,4 @@ class Errand {
|
|||
String get text => todo.text;
|
||||
|
||||
Errand(this.todo);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue