This commit is contained in:
thosakwe 2016-12-21 13:18:26 -05:00
parent 0057f11661
commit 530eb11bf8
5 changed files with 89 additions and 9 deletions

View file

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

View file

@ -4,6 +4,11 @@ import 'dart:async';
import 'request_context.dart';
import 'response_context.dart';
abstract class AngelMiddleware {
Future<bool> call(RequestContext req, ResponseContext res);
}
@Deprecated('Use AngelMiddleware instead')
abstract class BaseMiddleware {
Future<bool> call(RequestContext req, ResponseContext res);
}

View file

@ -79,6 +79,8 @@ class ResponseContext extends Extensible {
ResponseContext(this.io, this.app);
/// Set this to true if you will manually close the response.
///
/// If `true`, all response finalizers will be skipped.
bool willCloseItself = false;
/// Sends a download as a response.
@ -209,14 +211,34 @@ class ResponseContext extends Extensible {
redirect('$head/$tail'.replaceAll(_straySlashes, ''), code: code);
}
/// Streams a file to this response as chunked data.
Future streamFile(File file,
/// Copies a file's contents into the response buffer.
Future sendFile(File file,
{int chunkSize, int sleepMs: 0, bool resumable: true}) async {
if (!isOpen) return;
headers[HttpHeaders.CONTENT_TYPE] = lookupMimeType(file.path);
end();
buffer.add(await file.readAsBytes());
end();
}
/// Streams a file to this response.
///
/// You can optionally transform the file stream with a [codec].
Future streamFile(File file,
{int chunkSize,
int sleepMs: 0,
bool resumable: true,
Codec<List<int>, List<int>> codec}) async {
if (!isOpen) return;
headers[HttpHeaders.CONTENT_TYPE] = lookupMimeType(file.path);
end();
willCloseItself = true;
var stream = codec != null
? file.openRead().transform(codec.encoder)
: file.openRead();
await stream.pipe(io);
}
/// Writes data to the response.

View file

@ -38,6 +38,8 @@ class Angel extends AngelBase {
new StreamController<AngelFatalError>.broadcast();
StreamController<Controller> _onController =
new StreamController<Controller>.broadcast();
final List<Angel> _children = [];
Angel _parent;
final Random _rand = new Random.secure();
ServerGenerator _serverGenerator = HttpServer.bind;
@ -48,14 +50,26 @@ class Angel extends AngelBase {
/// Fired before a request is processed. Always runs.
Stream<HttpRequest> get beforeProcessed => _beforeProcessed.stream;
/// All child application mounted on this instance.
List<Angel> get children => new List<Angel>.unmodifiable(_children);
/// Fired on fatal errors.
Stream<AngelFatalError> get fatalErrorStream => _fatalErrorStream.stream;
/// Indicates whether the application is running in a production environment.
///
/// The criteria for this is the `ANGEL_ENV` environment variable being set to
/// `'production'`.
bool get isProduction => Platform.environment['ANGEL_ENV'] == 'production';
/// Fired whenever a controller is added to this instance.
///
/// **NOTE**: This is a broadcast stream.
Stream<Controller> get onController => _onController.stream;
/// Returns the parent instance of this application, if any.
Angel get parent => _parent;
/// Always run before responses are sent.
///
/// These will only not run if an [AngelFatalError] occurs.
@ -79,10 +93,10 @@ class Angel extends AngelBase {
AngelErrorHandler get errorHandler => _errorHandler;
/// [RequestMiddleware] to be run before all requests.
List before = [];
final List before = [];
/// [RequestMiddleware] to be run after all requests.
List after = [];
final List after = [];
/// The native HttpServer running this instancce.
HttpServer httpServer;
@ -254,7 +268,7 @@ class Angel extends AngelBase {
for (var key in res.headers.keys) {
request.response.headers.set(key, res.headers[key]);
}
request.response.headers.chunkedTransferEncoding = res.chunked ?? true;
request.response
@ -327,16 +341,55 @@ class Angel extends AngelBase {
}, onError: _onError);
}
/// Mounts the child on this router.
///
/// If the router is an [Angel] instance, all controllers
/// will be copied, as well as services and response finalizers.
///
/// [before] and [after] will be preserved.
///
/// NOTE: The above will not be properly copied if [path] is
/// a [RegExp].
@override
use(Pattern path, Routable routable,
{bool hooked: true, String namespace: null}) {
final head = path.toString().replaceAll(_straySlashes, '');
if (routable is Angel) {
final head = path.toString().replaceAll(_straySlashes, '');
_children.add(routable.._parent = this);
if (routable.before.isNotEmpty) {
all(path, (req, res) {
return true;
}, middleware: routable.before);
}
if (routable.after.isNotEmpty) {
all(path, (req, res) {
return true;
}, middleware: routable.after);
}
if (routable.responseFinalizers.isNotEmpty) {
responseFinalizers.add((req, res) async {
if (req.path.replaceAll(_straySlashes, '').startsWith(head)) {
for (var finalizer in routable.responseFinalizers)
await finalizer(req, res);
}
return true;
});
}
routable.controllers.forEach((k, v) {
final tail = k.toString().replaceAll(_straySlashes, '');
controllers['$head/$tail'.replaceAll(_straySlashes, '')] = v;
});
routable.services.forEach((k, v) {
final tail = k.toString().replaceAll(_straySlashes, '');
services['$head/$tail'.replaceAll(_straySlashes, '')] = v;
});
}
if (routable is Service) {

View file

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