From 530eb11bf8fca4db8d28fda65d7657c62fe3fde3 Mon Sep 17 00:00:00 2001 From: thosakwe Date: Wed, 21 Dec 2016 13:18:26 -0500 Subject: [PATCH] :) --- README.md | 2 +- lib/src/http/base_middleware.dart | 5 +++ lib/src/http/response_context.dart | 28 ++++++++++++-- lib/src/http/server.dart | 61 ++++++++++++++++++++++++++++-- pubspec.yaml | 2 +- 5 files changed, 89 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7023539d..d86522b1 100644 --- a/README.md +++ b/README.md @@ -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. \ No newline at end of file diff --git a/lib/src/http/base_middleware.dart b/lib/src/http/base_middleware.dart index ca3c5282..662749f6 100644 --- a/lib/src/http/base_middleware.dart +++ b/lib/src/http/base_middleware.dart @@ -4,6 +4,11 @@ import 'dart:async'; import 'request_context.dart'; import 'response_context.dart'; +abstract class AngelMiddleware { + Future call(RequestContext req, ResponseContext res); +} + +@Deprecated('Use AngelMiddleware instead') abstract class BaseMiddleware { Future call(RequestContext req, ResponseContext res); } \ No newline at end of file diff --git a/lib/src/http/response_context.dart b/lib/src/http/response_context.dart index 41db6b77..3ba795fc 100644 --- a/lib/src/http/response_context.dart +++ b/lib/src/http/response_context.dart @@ -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> 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. diff --git a/lib/src/http/server.dart b/lib/src/http/server.dart index a0d08df0..c56a461b 100644 --- a/lib/src/http/server.dart +++ b/lib/src/http/server.dart @@ -38,6 +38,8 @@ class Angel extends AngelBase { new StreamController.broadcast(); StreamController _onController = new StreamController.broadcast(); + final List _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 get beforeProcessed => _beforeProcessed.stream; + /// All child application mounted on this instance. + List get children => new List.unmodifiable(_children); + /// Fired on fatal errors. Stream 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 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) { diff --git a/pubspec.yaml b/pubspec.yaml index f71fcdd6..3587899b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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 homepage: https://github.com/angel-dart/angel_framework