diff --git a/CHANGELOG.md b/CHANGELOG.md index 561082ab..d16a8a41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# 2.0.0-rc.6 +* Make `redirect` and `download` methods asynchronous. + # 2.0.0-rc.5 * Make `serializer` `FutureOr Function(Object)`. * Make `ResponseContext.serialize` return `Future`. diff --git a/lib/src/core/response_context.dart b/lib/src/core/response_context.dart index 67eebcba..57775285 100644 --- a/lib/src/core/response_context.dart +++ b/lib/src/core/response_context.dart @@ -139,7 +139,7 @@ abstract class ResponseContext new StateError('Cannot modify a closed response.'); /// Sends a download as a response. - void download(File file, {String filename}) { + Future download(File file, {String filename}) async { if (!isOpen) throw closed(); headers["Content-Disposition"] = @@ -148,15 +148,15 @@ abstract class ResponseContext headers['content-length'] = file.lengthSync().toString(); if (!isBuffered) { - file.openRead().pipe(this); + await file.openRead().pipe(this); } else { buffer.add(file.readAsBytesSync()); - close(); + await close(); } } /// Prevents more data from being written to the response, and locks it entire from further editing. - Future close() { + Future close() { if (buffer is LockableBytesBuilder) { (buffer as LockableBytesBuilder).lock(); } @@ -173,16 +173,17 @@ abstract class ResponseContext /// Returns a JSONP response. /// /// You can override the [contentType] sent; by default it is `application/javascript`. - void jsonp(value, {String callbackName = "callback", MediaType contentType}) { + Future jsonp(value, + {String callbackName = "callback", MediaType contentType}) { if (!isOpen) throw closed(); this.contentType = contentType ?? new MediaType('application', 'javascript'); write("$callbackName(${serializer(value)})"); - close(); + return close(); } /// Renders a view to the response stream, and closes the response. - Future render(String view, [Map data]) { + Future render(String view, [Map data]) { if (!isOpen) throw closed(); contentType = new MediaType('text', 'html', {'charset': 'utf-8'}); return Future.sync(() => app.viewGenerator( @@ -190,7 +191,7 @@ abstract class ResponseContext new Map.from(renderParams) ..addAll(data ?? {}))).then((content) { write(content); - close(); + return close(); }); } @@ -201,7 +202,7 @@ abstract class ResponseContext /// based on the provided params. /// /// See [Router]#navigate for more. :) - void redirect(url, {bool absolute = true, int code = 302}) { + Future redirect(url, {bool absolute = true, int code = 302}) { if (!isOpen) throw closed(); headers ..['content-type'] = 'text/html' @@ -226,11 +227,11 @@ abstract class ResponseContext '''); - close(); + return close(); } /// Redirects to the given named [Route]. - void redirectTo(String name, [Map params, int code]) { + Future redirectTo(String name, [Map params, int code]) async { if (!isOpen) throw closed(); Route _findRoute(Router r) { for (Route route in r.routes) { @@ -247,7 +248,7 @@ abstract class ResponseContext Route matched = _findRoute(app); if (matched != null) { - redirect( + await redirect( matched.makeUri(params.keys.fold>({}, (out, k) { return out..[k.toString()] = params[k]; })), @@ -259,7 +260,7 @@ abstract class ResponseContext } /// Redirects to the given [Controller] action. - void redirectToAction(String action, [Map params, int code]) { + Future redirectToAction(String action, [Map params, int code]) { if (!isOpen) throw closed(); // UserController@show List split = action.split("@"); @@ -291,7 +292,7 @@ abstract class ResponseContext })) .replaceAll(_straySlashes, ''); - redirect('$head/$tail'.replaceAll(_straySlashes, ''), code: code); + return redirect('$head/$tail'.replaceAll(_straySlashes, ''), code: code); } /// Serializes data to the response. diff --git a/pubspec.yaml b/pubspec.yaml index 35018389..d2fca7fe 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_framework -version: 2.0.0-rc.5 +version: 2.0.0-rc.6 description: A high-powered HTTP server with dependency injection, routing and much more. author: Tobe O homepage: https://github.com/angel-dart/angel_framework diff --git a/test/hooked_test.dart b/test/hooked_test.dart index a153ac29..db162309 100644 --- a/test/hooked_test.dart +++ b/test/hooked_test.dart @@ -99,6 +99,12 @@ main() { expect(result[0]["angel"], equals("framework")); }); + test('asStream() fires', () async { + var stream = todoService.afterCreated.asStream(); + await todoService.create({'angel': 'framework'}); + expect(await stream.first.then((e) => e.result['angel']), 'framework'); + }); + test('metadata', () async { final service = new HookedService(new IncrementService())..addHooks(app); expect(service.inner, isNot(const IsInstanceOf())); diff --git a/test/routing_test.dart b/test/routing_test.dart index 15424b19..fb4c0a38 100644 --- a/test/routing_test.dart +++ b/test/routing_test.dart @@ -85,7 +85,7 @@ main() { (RequestContext req, res) async => "Hello ${req.params['name']}") .name = 'Named routes'; app.get('/named', (req, ResponseContext res) async { - res.redirectTo('Named routes', {'name': 'tests'}); + await res.redirectTo('Named routes', {'name': 'tests'}); }); app.get('/log', (RequestContext req, res) async { print("Query: ${req.queryParameters}");