unnecessary new/const removal

This commit is contained in:
Tobe O 2019-05-02 18:48:31 -04:00
parent 1ed6736257
commit e57de0bd04
58 changed files with 473 additions and 491 deletions

View file

@ -5,6 +5,7 @@ handlers to run, even after the response was closed.
* Call `RequestContext.close` in `Driver.sendResponse`. * Call `RequestContext.close` in `Driver.sendResponse`.
* AngelConfigurer is now `FutureOr<void>`, instead of just `FutureOr`. * AngelConfigurer is now `FutureOr<void>`, instead of just `FutureOr`.
* Use a `Container.has<Stopwatch>` check in `Driver.sendResponse`. * Use a `Container.has<Stopwatch>` check in `Driver.sendResponse`.
* Remove unnecessary `new` and `const`.
# 2.0.0 # 2.0.0
* Angel 2! :angel: :rocket: * Angel 2! :angel: :rocket:
@ -124,7 +125,7 @@ stable, there'll be a conversion, perhaps.
- All calls to `Service.parseId` are now affixed with the `<Id>` argument. - All calls to `Service.parseId` are now affixed with the `<Id>` argument.
- Added `uri` getter to `AngelHttp`. - Added `uri` getter to `AngelHttp`.
- The default for `parseQuery` now wraps query parameters in `new Map<String, dynamic>.from`. - The default for `parseQuery` now wraps query parameters in `Map<String, dynamic>.from`.
This resolves a bug in `package:angel_validate`. This resolves a bug in `package:angel_validate`.
# 2.0.0-alpha.9 # 2.0.0-alpha.9

View file

@ -13,7 +13,7 @@ import 'package:angel_container/mirrors.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
main() async { main() async {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
// Index route. Returns JSON. // Index route. Returns JSON.
app.get('/', (req, res) => res.write('Welcome to Angel!')); app.get('/', (req, res) => res.write('Welcome to Angel!'));
@ -43,12 +43,12 @@ main() async {
// Simple fallback to throw a 404 on unknown paths. // Simple fallback to throw a 404 on unknown paths.
app.fallback((req, res) { app.fallback((req, res) {
throw new AngelHttpException.notFound( throw AngelHttpException.notFound(
message: 'Unknown path: "${req.uri.path}"', message: 'Unknown path: "${req.uri.path}"',
); );
}); });
var http = new AngelHttp(app); var http = AngelHttp(app);
var server = await http.startServer('127.0.0.1', 3000); var server = await http.startServer('127.0.0.1', 3000);
var url = 'http://${server.address.address}:${server.port}'; var url = 'http://${server.address.address}:${server.port}';
print('Listening at $url'); print('Listening at $url');

View file

@ -5,3 +5,5 @@ analyzer:
linter: linter:
rules: rules:
- avoid_slow_async_io - avoid_slow_async_io
- unnecessary_const
- unnecessary_new

View file

@ -6,8 +6,8 @@ import 'package:angel_framework/http.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
main() async { main() async {
var app = new Angel(reflector: MirrorsReflector()) var app = Angel(reflector: MirrorsReflector())
..logger = (new Logger('angel') ..logger = (Logger('angel')
..onRecord.listen((rec) { ..onRecord.listen((rec) {
print(rec); print(rec);
if (rec.error != null) print(rec.error); if (rec.error != null) print(rec.error);
@ -16,9 +16,9 @@ main() async {
..encoders.addAll({'gzip': gzip.encoder}); ..encoders.addAll({'gzip': gzip.encoder});
app.fallback( app.fallback(
(req, res) => new Future.error('Throwing just because I feel like!')); (req, res) => Future.error('Throwing just because I feel like!'));
var http = new AngelHttp(app); var http = AngelHttp(app);
var server = await http.startServer('127.0.0.1', 3000); var server = await http.startServer('127.0.0.1', 3000);
var url = 'http://${server.address.address}:${server.port}'; var url = 'http://${server.address.address}:${server.port}';
print('Listening at $url'); print('Listening at $url');

View file

@ -6,15 +6,15 @@ import 'package:file/local.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
main() async { main() async {
var app = new Angel(); var app = Angel();
app.logger = new Logger('angel') app.logger = Logger('angel')
..onRecord.listen((rec) { ..onRecord.listen((rec) {
print(rec); print(rec);
if (rec.error != null) print(rec.error); if (rec.error != null) print(rec.error);
if (rec.stackTrace != null) print(rec.stackTrace); if (rec.stackTrace != null) print(rec.stackTrace);
}); });
var publicDir = new Directory('example/public'); var publicDir = Directory('example/public');
var indexHtml = var indexHtml =
const LocalFileSystem().file(publicDir.uri.resolve('body_parsing.html')); const LocalFileSystem().file(publicDir.uri.resolve('body_parsing.html'));
@ -22,7 +22,7 @@ main() async {
app.post('/', (req, res) => req.parseBody().then((_) => req.bodyAsMap)); app.post('/', (req, res) => req.parseBody().then((_) => req.bodyAsMap));
var ctx = new SecurityContext() var ctx = SecurityContext()
..useCertificateChain('dev.pem') ..useCertificateChain('dev.pem')
..usePrivateKey('dev.key', password: 'dartdart'); ..usePrivateKey('dev.key', password: 'dartdart');
@ -35,8 +35,8 @@ main() async {
st); st);
} }
var http1 = new AngelHttp(app); var http1 = AngelHttp(app);
var http2 = new AngelHttp2(app, ctx); var http2 = AngelHttp2(app, ctx);
// HTTP/1.x requests will fallback to `AngelHttp` // HTTP/1.x requests will fallback to `AngelHttp`
http2.onHttp1.listen(http1.handleRequest); http2.onHttp1.listen(http1.handleRequest);

View file

@ -6,19 +6,19 @@ import 'package:logging/logging.dart';
import 'common.dart'; import 'common.dart';
main() async { main() async {
var app = new Angel() var app = Angel()
..encoders.addAll({ ..encoders.addAll({
'gzip': gzip.encoder, 'gzip': gzip.encoder,
'deflate': zlib.encoder, 'deflate': zlib.encoder,
}); });
app.logger = new Logger('angel')..onRecord.listen(dumpError); app.logger = Logger('angel')..onRecord.listen(dumpError);
app.get('/', (req, res) => 'Hello HTTP/2!!!'); app.get('/', (req, res) => 'Hello HTTP/2!!!');
app.fallback((req, res) => throw new AngelHttpException.notFound( app.fallback((req, res) => throw AngelHttpException.notFound(
message: 'No file exists at ${req.uri}')); message: 'No file exists at ${req.uri}'));
var ctx = new SecurityContext() var ctx = SecurityContext()
..useCertificateChain('dev.pem') ..useCertificateChain('dev.pem')
..usePrivateKey('dev.key', password: 'dartdart'); ..usePrivateKey('dev.key', password: 'dartdart');
@ -32,8 +32,8 @@ main() async {
); );
} }
var http1 = new AngelHttp(app); var http1 = AngelHttp(app);
var http2 = new AngelHttp2(app, ctx); var http2 = AngelHttp2(app, ctx);
// HTTP/1.x requests will fallback to `AngelHttp` // HTTP/1.x requests will fallback to `AngelHttp`
http2.onHttp1.listen(http1.handleRequest); http2.onHttp1.listen(http1.handleRequest);

View file

@ -6,15 +6,15 @@ import 'package:file/local.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
main() async { main() async {
var app = new Angel(); var app = Angel();
app.logger = new Logger('angel') app.logger = Logger('angel')
..onRecord.listen((rec) { ..onRecord.listen((rec) {
print(rec); print(rec);
if (rec.error != null) print(rec.error); if (rec.error != null) print(rec.error);
if (rec.stackTrace != null) print(rec.stackTrace); if (rec.stackTrace != null) print(rec.stackTrace);
}); });
var publicDir = new Directory('example/http2/public'); var publicDir = Directory('example/http2/public');
var indexHtml = var indexHtml =
const LocalFileSystem().file(publicDir.uri.resolve('index.html')); const LocalFileSystem().file(publicDir.uri.resolve('index.html'));
var styleCss = var styleCss =
@ -38,7 +38,7 @@ main() async {
} }
}); });
var ctx = new SecurityContext() var ctx = SecurityContext()
..useCertificateChain('dev.pem') ..useCertificateChain('dev.pem')
..usePrivateKey('dev.key', password: 'dartdart'); ..usePrivateKey('dev.key', password: 'dartdart');
@ -51,8 +51,8 @@ main() async {
st); st);
} }
var http1 = new AngelHttp(app); var http1 = AngelHttp(app);
var http2 = new AngelHttp2(app, ctx); var http2 = AngelHttp2(app, ctx);
// HTTP/1.x requests will fallback to `AngelHttp` // HTTP/1.x requests will fallback to `AngelHttp`
http2.onHttp1.listen(http1.handleRequest); http2.onHttp1.listen(http1.handleRequest);

View file

@ -6,8 +6,8 @@ import 'package:angel_framework/http.dart';
main() async { main() async {
int x = 0; int x = 0;
var c = new Completer(); var c = Completer();
var exit = new ReceivePort(); var exit = ReceivePort();
List<Isolate> isolates = []; List<Isolate> isolates = [];
exit.listen((_) { exit.listen((_) {
@ -31,9 +31,9 @@ main() async {
} }
serverMain(_) async { serverMain(_) async {
var app = new Angel(); var app = Angel();
var http = var http =
new AngelHttp.custom(app, startShared, useZone: false); // Run a cluster AngelHttp.custom(app, startShared, useZone: false); // Run a cluster
app.get('/', (req, res) { app.get('/', (req, res) {
return res.serialize({ return res.serialize({

View file

@ -2,8 +2,8 @@ import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart'; import 'package:angel_framework/http.dart';
main() async { main() async {
var app = new Angel(); var app = Angel();
var http = new AngelHttp(app); var http = AngelHttp(app);
app.fallback((req, res) { app.fallback((req, res) {
res.statusCode = 304; res.statusCode = 304;

View file

@ -3,7 +3,7 @@ import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart'; import 'package:angel_framework/http.dart';
main() async { main() async {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
app.viewGenerator = (name, [data]) async => app.viewGenerator = (name, [data]) async =>
'View generator invoked with name $name and data: $data'; 'View generator invoked with name $name and data: $data';
@ -11,7 +11,7 @@ main() async {
// Index route. Returns JSON. // Index route. Returns JSON.
app.get('/', (req, res) => res.render('index', {'foo': 'bar'})); app.get('/', (req, res) => res.render('index', {'foo': 'bar'}));
var http = new AngelHttp(app); var http = AngelHttp(app);
var server = await http.startServer('127.0.0.1', 3000); var server = await http.startServer('127.0.0.1', 3000);
var url = 'http://${server.address.address}:${server.port}'; var url = 'http://${server.address.address}:${server.port}';
print('Listening at $url'); print('Listening at $url');

View file

@ -30,30 +30,30 @@ class AnonymousService<Id, Data> extends Service<Id, Data> {
} }
@override @override
index([Map<String, dynamic> params]) => new Future.sync( index([Map<String, dynamic> params]) =>
() => _index != null ? _index(params) : super.index(params)); Future.sync(() => _index != null ? _index(params) : super.index(params));
@override @override
read(Id id, [Map<String, dynamic> params]) => new Future.sync( read(Id id, [Map<String, dynamic> params]) => Future.sync(
() => _read != null ? _read(id, params) : super.read(id, params)); () => _read != null ? _read(id, params) : super.read(id, params));
@override @override
create(Data data, [Map<String, dynamic> params]) => new Future.sync(() => create(Data data, [Map<String, dynamic> params]) => Future.sync(() =>
_create != null ? _create(data, params) : super.create(data, params)); _create != null ? _create(data, params) : super.create(data, params));
@override @override
modify(Id id, Data data, [Map<String, dynamic> params]) => modify(Id id, Data data, [Map<String, dynamic> params]) =>
new Future.sync(() => _modify != null Future.sync(() => _modify != null
? _modify(id, data, params) ? _modify(id, data, params)
: super.modify(id, data, params)); : super.modify(id, data, params));
@override @override
update(Id id, Data data, [Map<String, dynamic> params]) => update(Id id, Data data, [Map<String, dynamic> params]) =>
new Future.sync(() => _update != null Future.sync(() => _update != null
? _update(id, data, params) ? _update(id, data, params)
: super.update(id, data, params)); : super.update(id, data, params));
@override @override
remove(Id id, [Map<String, dynamic> params]) => new Future.sync( remove(Id id, [Map<String, dynamic> params]) => Future.sync(
() => _remove != null ? _remove(id, params) : super.remove(id, params)); () => _remove != null ? _remove(id, params) : super.remove(id, params));
} }

View file

@ -40,11 +40,10 @@ class Controller {
Expose exposeDecl = findExpose(app.container.reflector); Expose exposeDecl = findExpose(app.container.reflector);
if (exposeDecl == null) { if (exposeDecl == null) {
throw new Exception( throw Exception("All controllers must carry an @Expose() declaration.");
"All controllers must carry an @Expose() declaration.");
} }
var routable = new Routable(); var routable = Routable();
app.mount(exposeDecl.path, routable); app.mount(exposeDecl.path, routable);
var typeMirror = app.container.reflector.reflectType(this.runtimeType); var typeMirror = app.container.reflector.reflectType(this.runtimeType);
String name = String name =
@ -60,7 +59,7 @@ class Controller {
final routeBuilder = _routeBuilder(instanceMirror, routable, handlers); final routeBuilder = _routeBuilder(instanceMirror, routable, handlers);
classMirror.declarations.forEach(routeBuilder); classMirror.declarations.forEach(routeBuilder);
configureRoutes(routable); configureRoutes(routable);
return new Future.value(); return Future.value();
} }
void Function(ReflectedDeclaration) _routeBuilder( void Function(ReflectedDeclaration) _routeBuilder(

View file

@ -57,7 +57,7 @@ abstract class Driver<
/// Shuts down the underlying server. /// Shuts down the underlying server.
Future<Server> close() { Future<Server> close() {
if (_closed) return new Future.value(_server); if (_closed) return Future.value(_server);
_closed = true; _closed = true;
_sub?.cancel(); _sub?.cancel();
return app.close().then((_) => return app.close().then((_) =>
@ -102,8 +102,8 @@ abstract class Driver<
var r = app.optimizedRouter; var r = app.optimizedRouter;
var resolved = var resolved =
r.resolveAbsolute(path, method: req.method, strip: false); r.resolveAbsolute(path, method: req.method, strip: false);
var pipeline = new MiddlewarePipeline<RequestHandler>(resolved); var pipeline = MiddlewarePipeline<RequestHandler>(resolved);
return new Tuple4( return Tuple4(
pipeline.handlers, pipeline.handlers,
resolved.fold<Map<String, dynamic>>( resolved.fold<Map<String, dynamic>>(
<String, dynamic>{}, (out, r) => out..addAll(r.allParams)), <String, dynamic>{}, (out, r) => out..addAll(r.allParams)),
@ -132,8 +132,7 @@ abstract class Driver<
..registerSingleton<ParseResult>(tuple.item3); ..registerSingleton<ParseResult>(tuple.item3);
if (!app.environment.isProduction && app.logger != null) { if (!app.environment.isProduction && app.logger != null) {
req.container req.container.registerSingleton<Stopwatch>(Stopwatch()..start());
.registerSingleton<Stopwatch>(new Stopwatch()..start());
} }
return runPipeline(it, req, res, app) return runPipeline(it, req, res, app)
@ -151,9 +150,9 @@ abstract class Driver<
return f.catchError((e, StackTrace st) { return f.catchError((e, StackTrace st) {
if (e is FormatException) if (e is FormatException)
throw new AngelHttpException.badRequest(message: e.message) throw AngelHttpException.badRequest(message: e.message)
..stackTrace = st; ..stackTrace = st;
throw new AngelHttpException(e, throw AngelHttpException(e,
stackTrace: st, stackTrace: st,
statusCode: 500, statusCode: 500,
message: e?.toString() ?? '500 Internal Server Error'); message: e?.toString() ?? '500 Internal Server Error');
@ -163,8 +162,7 @@ abstract class Driver<
if (app.logger != null) { if (app.logger != null) {
var error = e.error ?? e; var error = e.error ?? e;
var trace = var trace = Trace.from(e.stackTrace ?? StackTrace.current).terse;
new Trace.from(e.stackTrace ?? StackTrace.current).terse;
app.logger.severe(e.message ?? e.toString(), error, trace); app.logger.severe(e.message ?? e.toString(), error, trace);
} }
@ -172,7 +170,7 @@ abstract class Driver<
e, e.stackTrace ?? st, req, res, request, response); e, e.stackTrace ?? st, req, res, request, response);
}); });
} else { } else {
var zoneSpec = new ZoneSpecification( var zoneSpec = ZoneSpecification(
print: (self, parent, zone, line) { print: (self, parent, zone, line) {
if (app.logger != null) if (app.logger != null)
app.logger.info(line); app.logger.info(line);
@ -180,18 +178,17 @@ abstract class Driver<
parent.print(zone, line); parent.print(zone, line);
}, },
handleUncaughtError: (self, parent, zone, error, stackTrace) { handleUncaughtError: (self, parent, zone, error, stackTrace) {
var trace = var trace = Trace.from(stackTrace ?? StackTrace.current).terse;
new Trace.from(stackTrace ?? StackTrace.current).terse;
return new Future(() { return Future(() {
AngelHttpException e; AngelHttpException e;
if (error is FormatException) { if (error is FormatException) {
e = new AngelHttpException.badRequest(message: error.message); e = AngelHttpException.badRequest(message: error.message);
} else if (error is AngelHttpException) { } else if (error is AngelHttpException) {
e = error; e = error;
} else { } else {
e = new AngelHttpException(error, e = AngelHttpException(error,
stackTrace: stackTrace, stackTrace: stackTrace,
message: message:
error?.toString() ?? '500 Internal Server Error'); error?.toString() ?? '500 Internal Server Error');
@ -204,7 +201,7 @@ abstract class Driver<
return handleAngelHttpException( return handleAngelHttpException(
e, trace, req, res, request, response); e, trace, req, res, request, response);
}).catchError((e, StackTrace st) { }).catchError((e, StackTrace st) {
var trace = new Trace.from(st ?? StackTrace.current).terse; var trace = Trace.from(st ?? StackTrace.current).terse;
closeResponse(response); closeResponse(response);
// Ideally, we won't be in a position where an absolutely fatal error occurs, // Ideally, we won't be in a position where an absolutely fatal error occurs,
// but if so, we'll need to log it. // but if so, we'll need to log it.
@ -263,11 +260,11 @@ abstract class Driver<
Future handleError; Future handleError;
if (!res.isOpen) if (!res.isOpen)
handleError = new Future.value(); handleError = Future.value();
else { else {
res.statusCode = e.statusCode; res.statusCode = e.statusCode;
handleError = handleError =
new Future.sync(() => app.errorHandler(e, req, res)).then((result) { Future.sync(() => app.errorHandler(e, req, res)).then((result) {
return app.executeHandler(result, req, res).then((_) => res.close()); return app.executeHandler(result, req, res).then((_) => res.close());
}); });
} }
@ -294,7 +291,7 @@ abstract class Driver<
if (!res.isBuffered) return res.close().then(_cleanup); if (!res.isBuffered) return res.close().then(_cleanup);
Future finalizers = ignoreFinalizers == true Future finalizers = ignoreFinalizers == true
? new Future.value() ? Future.value()
: Future.forEach(app.responseFinalizers, (f) => f(req, res)); : Future.forEach(app.responseFinalizers, (f) => f(req, res));
return finalizers.then((_) { return finalizers.then((_) {

View file

@ -1,7 +1,7 @@
import 'dart:io'; import 'dart:io';
/// A constant instance of [AngelEnv]. /// A constant instance of [AngelEnv].
const AngelEnvironment angelEnv = const AngelEnvironment(); const AngelEnvironment angelEnv = AngelEnvironment();
/// Queries the environment's `ANGEL_ENV` value. /// Queries the environment's `ANGEL_ENV` value.
class AngelEnvironment { class AngelEnvironment {

View file

@ -19,29 +19,29 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
final T inner; final T inner;
final HookedServiceEventDispatcher<Id, Data, T> beforeIndexed = final HookedServiceEventDispatcher<Id, Data, T> beforeIndexed =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> beforeRead = final HookedServiceEventDispatcher<Id, Data, T> beforeRead =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> beforeCreated = final HookedServiceEventDispatcher<Id, Data, T> beforeCreated =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> beforeModified = final HookedServiceEventDispatcher<Id, Data, T> beforeModified =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> beforeUpdated = final HookedServiceEventDispatcher<Id, Data, T> beforeUpdated =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> beforeRemoved = final HookedServiceEventDispatcher<Id, Data, T> beforeRemoved =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> afterIndexed = final HookedServiceEventDispatcher<Id, Data, T> afterIndexed =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> afterRead = final HookedServiceEventDispatcher<Id, Data, T> afterRead =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> afterCreated = final HookedServiceEventDispatcher<Id, Data, T> afterCreated =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> afterModified = final HookedServiceEventDispatcher<Id, Data, T> afterModified =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> afterUpdated = final HookedServiceEventDispatcher<Id, Data, T> afterUpdated =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
final HookedServiceEventDispatcher<Id, Data, T> afterRemoved = final HookedServiceEventDispatcher<Id, Data, T> afterRemoved =
new HookedServiceEventDispatcher<Id, Data, T>(); HookedServiceEventDispatcher<Id, Data, T>();
HookedService(this.inner) { HookedService(this.inner) {
// Clone app instance // Clone app instance
@ -89,7 +89,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
afterUpdated._close(); afterUpdated._close();
afterRemoved._close(); afterRemoved._close();
inner.close(); inner.close();
return new Future.value(); return Future.value();
} }
/// Adds hooks to this instance. /// Adds hooks to this instance.
@ -130,7 +130,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
} }
List<RequestHandler> get bootstrappers => List<RequestHandler> get bootstrappers =>
new List<RequestHandler>.from(super.bootstrappers) List<RequestHandler>.from(super.bootstrappers)
..add((RequestContext req, ResponseContext res) { ..add((RequestContext req, ResponseContext res) {
req.serviceParams req.serviceParams
..['__requestctx'] = req ..['__requestctx'] = req
@ -160,7 +160,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
case HookedServiceEvent.removed: case HookedServiceEvent.removed:
return beforeRemoved; return beforeRemoved;
default: default:
throw new ArgumentError('Invalid service method: ${name}'); throw ArgumentError('Invalid service method: ${name}');
} }
}).forEach((HookedServiceEventDispatcher<Id, Data, T> dispatcher) => }).forEach((HookedServiceEventDispatcher<Id, Data, T> dispatcher) =>
dispatcher.listen(listener)); dispatcher.listen(listener));
@ -184,7 +184,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
case HookedServiceEvent.removed: case HookedServiceEvent.removed:
return afterRemoved; return afterRemoved;
default: default:
throw new ArgumentError('Invalid service method: ${name}'); throw ArgumentError('Invalid service method: ${name}');
} }
}).forEach((HookedServiceEventDispatcher<Id, Data, T> dispatcher) => }).forEach((HookedServiceEventDispatcher<Id, Data, T> dispatcher) =>
dispatcher.listen(listener)); dispatcher.listen(listener));
@ -216,7 +216,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
/// that events coming out of this [Stream] will see changes you make within the [Stream] /// that events coming out of this [Stream] will see changes you make within the [Stream]
/// callback. /// callback.
Stream<HookedServiceEvent<Id, Data, T>> beforeAllStream() { Stream<HookedServiceEvent<Id, Data, T>> beforeAllStream() {
var ctrl = new StreamController<HookedServiceEvent<Id, Data, T>>(); var ctrl = StreamController<HookedServiceEvent<Id, Data, T>>();
_ctrl.add(ctrl); _ctrl.add(ctrl);
before(HookedServiceEvent.all, ctrl.add); before(HookedServiceEvent.all, ctrl.add);
return ctrl.stream; return ctrl.stream;
@ -228,7 +228,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
/// that events coming out of this [Stream] will see changes you make within the [Stream] /// that events coming out of this [Stream] will see changes you make within the [Stream]
/// callback. /// callback.
Stream<HookedServiceEvent<Id, Data, T>> afterAllStream() { Stream<HookedServiceEvent<Id, Data, T>> afterAllStream() {
var ctrl = new StreamController<HookedServiceEvent<Id, Data, T>>(); var ctrl = StreamController<HookedServiceEvent<Id, Data, T>>();
_ctrl.add(ctrl); _ctrl.add(ctrl);
before(HookedServiceEvent.all, ctrl.add); before(HookedServiceEvent.all, ctrl.add);
return ctrl.stream; return ctrl.stream;
@ -241,7 +241,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
/// callback. /// callback.
Stream<HookedServiceEvent<Id, Data, T>> beforeStream( Stream<HookedServiceEvent<Id, Data, T>> beforeStream(
Iterable<String> eventNames) { Iterable<String> eventNames) {
var ctrl = new StreamController<HookedServiceEvent<Id, Data, T>>(); var ctrl = StreamController<HookedServiceEvent<Id, Data, T>>();
_ctrl.add(ctrl); _ctrl.add(ctrl);
before(eventNames, ctrl.add); before(eventNames, ctrl.add);
return ctrl.stream; return ctrl.stream;
@ -254,7 +254,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
/// callback. /// callback.
Stream<HookedServiceEvent<Id, Data, T>> afterStream( Stream<HookedServiceEvent<Id, Data, T>> afterStream(
Iterable<String> eventNames) { Iterable<String> eventNames) {
var ctrl = new StreamController<HookedServiceEvent<Id, Data, T>>(); var ctrl = StreamController<HookedServiceEvent<Id, Data, T>>();
_ctrl.add(ctrl); _ctrl.add(ctrl);
after(eventNames, ctrl.add); after(eventNames, ctrl.add);
return ctrl.stream; return ctrl.stream;
@ -271,13 +271,13 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
Future<List<Data>> index([Map<String, dynamic> _params]) { Future<List<Data>> index([Map<String, dynamic> _params]) {
var params = _stripReq(_params); var params = _stripReq(_params);
return beforeIndexed return beforeIndexed
._emit(new HookedServiceEvent(false, _getRequest(_params), ._emit(HookedServiceEvent(false, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.indexed, _getResponse(_params), inner, HookedServiceEvent.indexed,
params: params)) params: params))
.then((before) { .then((before) {
if (before._canceled) { if (before._canceled) {
return afterIndexed return afterIndexed
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.indexed, _getResponse(_params), inner, HookedServiceEvent.indexed,
params: params, result: before.result)) params: params, result: before.result))
.then((after) => after.result as List<Data>); .then((after) => after.result as List<Data>);
@ -285,7 +285,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
return inner.index(params).then((result) { return inner.index(params).then((result) {
return afterIndexed return afterIndexed
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.indexed, _getResponse(_params), inner, HookedServiceEvent.indexed,
params: params, result: result)) params: params, result: result))
.then((after) => after.result as List<Data>); .then((after) => after.result as List<Data>);
@ -297,13 +297,13 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
Future<Data> read(Id id, [Map<String, dynamic> _params]) { Future<Data> read(Id id, [Map<String, dynamic> _params]) {
var params = _stripReq(_params); var params = _stripReq(_params);
return beforeRead return beforeRead
._emit(new HookedServiceEvent(false, _getRequest(_params), ._emit(HookedServiceEvent(false, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.read, _getResponse(_params), inner, HookedServiceEvent.read,
id: id, params: params)) id: id, params: params))
.then((before) { .then((before) {
if (before._canceled) { if (before._canceled) {
return afterRead return afterRead
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.read, _getResponse(_params), inner, HookedServiceEvent.read,
id: id, params: params, result: before.result)) id: id, params: params, result: before.result))
.then((after) => after.result as Data); .then((after) => after.result as Data);
@ -311,7 +311,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
return inner.read(id, params).then((result) { return inner.read(id, params).then((result) {
return afterRead return afterRead
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.read, _getResponse(_params), inner, HookedServiceEvent.read,
id: id, params: params, result: result)) id: id, params: params, result: result))
.then((after) => after.result as Data); .then((after) => after.result as Data);
@ -323,13 +323,13 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
Future<Data> create(Data data, [Map<String, dynamic> _params]) { Future<Data> create(Data data, [Map<String, dynamic> _params]) {
var params = _stripReq(_params); var params = _stripReq(_params);
return beforeCreated return beforeCreated
._emit(new HookedServiceEvent(false, _getRequest(_params), ._emit(HookedServiceEvent(false, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.created, _getResponse(_params), inner, HookedServiceEvent.created,
data: data, params: params)) data: data, params: params))
.then((before) { .then((before) {
if (before._canceled) { if (before._canceled) {
return afterCreated return afterCreated
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.created, _getResponse(_params), inner, HookedServiceEvent.created,
data: before.data, params: params, result: before.result)) data: before.data, params: params, result: before.result))
.then((after) => after.result as Data); .then((after) => after.result as Data);
@ -337,7 +337,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
return inner.create(before.data, params).then((result) { return inner.create(before.data, params).then((result) {
return afterCreated return afterCreated
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.created, _getResponse(_params), inner, HookedServiceEvent.created,
data: before.data, params: params, result: result)) data: before.data, params: params, result: result))
.then((after) => after.result as Data); .then((after) => after.result as Data);
@ -349,13 +349,13 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
Future<Data> modify(Id id, Data data, [Map<String, dynamic> _params]) { Future<Data> modify(Id id, Data data, [Map<String, dynamic> _params]) {
var params = _stripReq(_params); var params = _stripReq(_params);
return beforeModified return beforeModified
._emit(new HookedServiceEvent(false, _getRequest(_params), ._emit(HookedServiceEvent(false, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.modified, _getResponse(_params), inner, HookedServiceEvent.modified,
id: id, data: data, params: params)) id: id, data: data, params: params))
.then((before) { .then((before) {
if (before._canceled) { if (before._canceled) {
return afterModified return afterModified
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.modified, _getResponse(_params), inner, HookedServiceEvent.modified,
id: id, id: id,
data: before.data, data: before.data,
@ -366,7 +366,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
return inner.modify(id, before.data, params).then((result) { return inner.modify(id, before.data, params).then((result) {
return afterModified return afterModified
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.created, _getResponse(_params), inner, HookedServiceEvent.created,
id: id, data: before.data, params: params, result: result)) id: id, data: before.data, params: params, result: result))
.then((after) => after.result as Data); .then((after) => after.result as Data);
@ -378,13 +378,13 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
Future<Data> update(Id id, Data data, [Map<String, dynamic> _params]) { Future<Data> update(Id id, Data data, [Map<String, dynamic> _params]) {
var params = _stripReq(_params); var params = _stripReq(_params);
return beforeUpdated return beforeUpdated
._emit(new HookedServiceEvent(false, _getRequest(_params), ._emit(HookedServiceEvent(false, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.updated, _getResponse(_params), inner, HookedServiceEvent.updated,
id: id, data: data, params: params)) id: id, data: data, params: params))
.then((before) { .then((before) {
if (before._canceled) { if (before._canceled) {
return afterUpdated return afterUpdated
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.updated, _getResponse(_params), inner, HookedServiceEvent.updated,
id: id, id: id,
data: before.data, data: before.data,
@ -395,7 +395,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
return inner.update(id, before.data, params).then((result) { return inner.update(id, before.data, params).then((result) {
return afterUpdated return afterUpdated
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.updated, _getResponse(_params), inner, HookedServiceEvent.updated,
id: id, data: before.data, params: params, result: result)) id: id, data: before.data, params: params, result: result))
.then((after) => after.result as Data); .then((after) => after.result as Data);
@ -407,13 +407,13 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
Future<Data> remove(Id id, [Map<String, dynamic> _params]) { Future<Data> remove(Id id, [Map<String, dynamic> _params]) {
var params = _stripReq(_params); var params = _stripReq(_params);
return beforeRemoved return beforeRemoved
._emit(new HookedServiceEvent(false, _getRequest(_params), ._emit(HookedServiceEvent(false, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.removed, _getResponse(_params), inner, HookedServiceEvent.removed,
id: id, params: params)) id: id, params: params))
.then((before) { .then((before) {
if (before._canceled) { if (before._canceled) {
return afterRemoved return afterRemoved
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.removed, _getResponse(_params), inner, HookedServiceEvent.removed,
id: id, params: params, result: before.result)) id: id, params: params, result: before.result))
.then((after) => after.result) as Data; .then((after) => after.result) as Data;
@ -421,7 +421,7 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
return inner.remove(id, params).then((result) { return inner.remove(id, params).then((result) {
return afterRemoved return afterRemoved
._emit(new HookedServiceEvent(true, _getRequest(_params), ._emit(HookedServiceEvent(true, _getRequest(_params),
_getResponse(_params), inner, HookedServiceEvent.removed, _getResponse(_params), inner, HookedServiceEvent.removed,
id: id, params: params, result: result)) id: id, params: params, result: result))
.then((after) => after.result as Data); .then((after) => after.result as Data);
@ -455,11 +455,11 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
dispatcher = afterRemoved; dispatcher = afterRemoved;
break; break;
default: default:
throw new ArgumentError("Invalid service event name: '$eventName'"); throw ArgumentError("Invalid service event name: '$eventName'");
} }
var ev = var ev =
new HookedServiceEvent<Id, Data, T>(true, null, null, inner, eventName); HookedServiceEvent<Id, Data, T>(true, null, null, inner, eventName);
return fireEvent(dispatcher, ev, callback); return fireEvent(dispatcher, ev, callback);
} }
@ -470,8 +470,8 @@ class HookedService<Id, Data, T extends Service<Id, Data>>
[HookedServiceEventListener<Id, Data, T> callback]) { [HookedServiceEventListener<Id, Data, T> callback]) {
Future f; Future f;
if (callback != null && event?._canceled != true) if (callback != null && event?._canceled != true)
f = new Future.sync(() => callback(event)); f = Future.sync(() => callback(event));
f ??= new Future.value(); f ??= Future.value();
return f.then((_) => dispatcher._emit(event)); return f.then((_) => dispatcher._emit(event));
} }
} }
@ -485,7 +485,7 @@ class HookedServiceEvent<Id, Data, T extends Service<Id, Data>> {
static const String updated = 'updated'; static const String updated = 'updated';
static const String removed = 'removed'; static const String removed = 'removed';
static const List<String> all = const [ static const List<String> all = [
indexed, indexed,
read, read,
created, created,
@ -558,14 +558,14 @@ class HookedServiceEventDispatcher<Id, Data, T extends Service<Id, Data>> {
Future<HookedServiceEvent<Id, Data, T>> _emit( Future<HookedServiceEvent<Id, Data, T>> _emit(
HookedServiceEvent<Id, Data, T> event) { HookedServiceEvent<Id, Data, T> event) {
if (event?._canceled == true || event == null || listeners.isEmpty) if (event?._canceled == true || event == null || listeners.isEmpty)
return new Future.value(event); return Future.value(event);
var f = new Future<HookedServiceEvent<Id, Data, T>>.value(event); var f = Future<HookedServiceEvent<Id, Data, T>>.value(event);
for (var listener in listeners) { for (var listener in listeners) {
f = f.then((event) { f = f.then((event) {
if (event._canceled) return event; if (event._canceled) return event;
return new Future.sync(() => listener(event)).then((_) => event); return Future.sync(() => listener(event)).then((_) => event);
}); });
} }
@ -577,7 +577,7 @@ class HookedServiceEventDispatcher<Id, Data, T extends Service<Id, Data>> {
/// *NOTE*: Callbacks on the returned [Stream] cannot be guaranteed to run before other [listeners]. /// *NOTE*: Callbacks on the returned [Stream] cannot be guaranteed to run before other [listeners].
/// Use this only if you need a read-only stream of events. /// Use this only if you need a read-only stream of events.
Stream<HookedServiceEvent<Id, Data, T>> asStream() { Stream<HookedServiceEvent<Id, Data, T>> asStream() {
var ctrl = new StreamController<HookedServiceEvent<Id, Data, T>>(); var ctrl = StreamController<HookedServiceEvent<Id, Data, T>>();
_ctrl.add(ctrl); _ctrl.add(ctrl);
listen(ctrl.add); listen(ctrl.add);
return ctrl.stream; return ctrl.stream;

View file

@ -48,7 +48,7 @@ resolveInjection(requirement, InjectionRequest injection, RequestContext req,
else if (injection.optional.contains(requirement)) else if (injection.optional.contains(requirement))
return null; return null;
else if (throwOnUnresolved) { else if (throwOnUnresolved) {
throw new ArgumentError( throw ArgumentError(
"Cannot resolve parameter '$requirement' within handler."); "Cannot resolve parameter '$requirement' within handler.");
} }
} else if (requirement is List && } else if (requirement is List &&
@ -76,7 +76,7 @@ resolveInjection(requirement, InjectionRequest injection, RequestContext req,
return await container.make(requirement); return await container.make(requirement);
} else if (throwOnUnresolved) { } else if (throwOnUnresolved) {
throw new ArgumentError( throw ArgumentError(
'$requirement cannot be injected into a request handler.'); '$requirement cannot be injected into a request handler.');
} }
} }
@ -97,8 +97,7 @@ RequestHandler handleContained(Function handler, InjectionRequest injection,
return (RequestContext req, ResponseContext res) async { return (RequestContext req, ResponseContext res) async {
if (injection.parameters.isNotEmpty && if (injection.parameters.isNotEmpty &&
injection.parameters.values.any((p) => p.match != null) && injection.parameters.values.any((p) => p.match != null) &&
!suitableForInjection(req, res, injection)) !suitableForInjection(req, res, injection)) return Future.value(true);
return new Future.value(true);
List args = []; List args = [];
@ -109,7 +108,7 @@ RequestHandler handleContained(Function handler, InjectionRequest injection,
} }
for (var entry in injection.named.entries) { for (var entry in injection.named.entries) {
var name = new Symbol(entry.key); var name = Symbol(entry.key);
named[name] = await resolveInjection( named[name] = await resolveInjection(
[entry.key, entry.value], injection, req, res, false, container); [entry.key, entry.value], injection, req, res, false, container);
} }
@ -153,7 +152,7 @@ class InjectionRequest {
/// Predetermines what needs to be injected for a handler to run. /// Predetermines what needs to be injected for a handler to run.
InjectionRequest preInject(Function handler, Reflector reflector) { InjectionRequest preInject(Function handler, Reflector reflector) {
var injection = new InjectionRequest(); var injection = InjectionRequest();
var closureMirror = reflector.reflectFunction(handler); var closureMirror = reflector.reflectFunction(handler);
@ -172,7 +171,7 @@ InjectionRequest preInject(Function handler, Reflector reflector) {
?.reflectee as Parameter; ?.reflectee as Parameter;
//print(p); //print(p);
if (p != null) { if (p != null) {
injection.parameters[name] = new Parameter( injection.parameters[name] = Parameter(
cookie: p.cookie, cookie: p.cookie,
header: p.header, header: p.header,
query: p.query, query: p.query,

View file

@ -49,11 +49,11 @@ class MapService extends Service<String, Map<String, dynamic>> {
@override @override
Future<List<Map<String, dynamic>>> index([Map<String, dynamic> params]) { Future<List<Map<String, dynamic>>> index([Map<String, dynamic> params]) {
if (allowQuery == false || params == null || params['query'] is! Map) if (allowQuery == false || params == null || params['query'] is! Map)
return new Future.value(items); return Future.value(items);
else { else {
var query = params['query'] as Map; var query = params['query'] as Map;
return new Future.value(items.where((item) { return Future.value(items.where((item) {
for (var key in query.keys) { for (var key in query.keys) {
if (!item.containsKey(key)) if (!item.containsKey(key))
return false; return false;
@ -67,8 +67,8 @@ class MapService extends Service<String, Map<String, dynamic>> {
@override @override
Future<Map<String, dynamic>> read(String id, [Map<String, dynamic> params]) { Future<Map<String, dynamic>> read(String id, [Map<String, dynamic> params]) {
return new Future.value(items.firstWhere(_matchesId(id), return Future.value(items.firstWhere(_matchesId(id),
orElse: () => throw new AngelHttpException.notFound( orElse: () => throw AngelHttpException.notFound(
message: 'No record found for ID $id'))); message: 'No record found for ID $id')));
} }
@ -76,11 +76,11 @@ class MapService extends Service<String, Map<String, dynamic>> {
Future<Map<String, dynamic>> create(Map<String, dynamic> data, Future<Map<String, dynamic>> create(Map<String, dynamic> data,
[Map<String, dynamic> params]) { [Map<String, dynamic> params]) {
if (data is! Map) if (data is! Map)
throw new AngelHttpException.badRequest( throw AngelHttpException.badRequest(
message: message:
'MapService does not support `create` with ${data.runtimeType}.'); 'MapService does not support `create` with ${data.runtimeType}.');
var now = new DateTime.now().toIso8601String(); var now = DateTime.now().toIso8601String();
var result = new Map<String, dynamic>.from(data); var result = Map<String, dynamic>.from(data);
if (autoIdAndDateFields == true) { if (autoIdAndDateFields == true) {
result result
@ -89,14 +89,14 @@ class MapService extends Service<String, Map<String, dynamic>> {
..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = now; ..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = now;
} }
items.add(result); items.add(result);
return new Future.value(result); return Future.value(result);
} }
@override @override
Future<Map<String, dynamic>> modify(String id, Map<String, dynamic> data, Future<Map<String, dynamic>> modify(String id, Map<String, dynamic> data,
[Map<String, dynamic> params]) { [Map<String, dynamic> params]) {
if (data is! Map) if (data is! Map)
throw new AngelHttpException.badRequest( throw AngelHttpException.badRequest(
message: message:
'MapService does not support `modify` with ${data.runtimeType}.'); 'MapService does not support `modify` with ${data.runtimeType}.');
if (!items.any(_matchesId(id))) return create(data, params); if (!items.any(_matchesId(id))) return create(data, params);
@ -104,13 +104,13 @@ class MapService extends Service<String, Map<String, dynamic>> {
return read(id).then((item) { return read(id).then((item) {
var idx = items.indexOf(item); var idx = items.indexOf(item);
if (idx < 0) return create(data, params); if (idx < 0) return create(data, params);
var result = new Map<String, dynamic>.from(item)..addAll(data); var result = Map<String, dynamic>.from(item)..addAll(data);
if (autoIdAndDateFields == true) if (autoIdAndDateFields == true)
result result
..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = ..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] =
new DateTime.now().toIso8601String(); DateTime.now().toIso8601String();
return new Future.value(items[idx] = result); return Future.value(items[idx] = result);
}); });
} }
@ -118,27 +118,27 @@ class MapService extends Service<String, Map<String, dynamic>> {
Future<Map<String, dynamic>> update(String id, Map<String, dynamic> data, Future<Map<String, dynamic>> update(String id, Map<String, dynamic> data,
[Map<String, dynamic> params]) { [Map<String, dynamic> params]) {
if (data is! Map) if (data is! Map)
throw new AngelHttpException.badRequest( throw AngelHttpException.badRequest(
message: message:
'MapService does not support `update` with ${data.runtimeType}.'); 'MapService does not support `update` with ${data.runtimeType}.');
if (!items.any(_matchesId(id))) return create(data, params); if (!items.any(_matchesId(id))) return create(data, params);
return read(id).then((old) { return read(id).then((old) {
if (!items.remove(old)) if (!items.remove(old))
throw new AngelHttpException.notFound( throw AngelHttpException.notFound(
message: 'No record found for ID $id'); message: 'No record found for ID $id');
var result = new Map<String, dynamic>.from(data); var result = Map<String, dynamic>.from(data);
if (autoIdAndDateFields == true) { if (autoIdAndDateFields == true) {
result result
..['id'] = id?.toString() ..['id'] = id?.toString()
..[autoSnakeCaseNames == false ? 'createdAt' : 'created_at'] = ..[autoSnakeCaseNames == false ? 'createdAt' : 'created_at'] =
old[autoSnakeCaseNames == false ? 'createdAt' : 'created_at'] old[autoSnakeCaseNames == false ? 'createdAt' : 'created_at']
..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = ..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] =
new DateTime.now().toIso8601String(); DateTime.now().toIso8601String();
} }
items.add(result); items.add(result);
return new Future.value(result); return Future.value(result);
}); });
} }
@ -153,7 +153,7 @@ class MapService extends Service<String, Map<String, dynamic>> {
message: 'Clients are not allowed to delete all items.'); message: 'Clients are not allowed to delete all items.');
} else { } else {
items.clear(); items.clear();
return new Future.value({}); return Future.value({});
} }
} }
@ -161,7 +161,7 @@ class MapService extends Service<String, Map<String, dynamic>> {
if (items.remove(result)) if (items.remove(result))
return result; return result;
else else
throw new AngelHttpException.notFound( throw AngelHttpException.notFound(
message: 'No record found for ID $id'); message: 'No record found for ID $id');
}); });
} }

View file

@ -71,17 +71,16 @@ class Parameter {
/// Returns an error that can be thrown when the parameter is not present. /// Returns an error that can be thrown when the parameter is not present.
get error { get error {
if (cookie?.isNotEmpty == true) if (cookie?.isNotEmpty == true)
return new AngelHttpException.badRequest( return AngelHttpException.badRequest(
message: 'Missing required cookie "$cookie".'); message: 'Missing required cookie "$cookie".');
if (header?.isNotEmpty == true) if (header?.isNotEmpty == true)
return new AngelHttpException.badRequest( return AngelHttpException.badRequest(
message: 'Missing required header "$header".'); message: 'Missing required header "$header".');
if (query?.isNotEmpty == true) if (query?.isNotEmpty == true)
return new AngelHttpException.badRequest( return AngelHttpException.badRequest(
message: 'Missing required query parameter "$query".'); message: 'Missing required query parameter "$query".');
if (session?.isNotEmpty == true) if (session?.isNotEmpty == true)
return new StateError( return StateError('Session does not contain required key "$session".');
'Session does not contain required key "$session".');
} }
/// Obtains a value for this parameter from a [RequestContext]. /// Obtains a value for this parameter from a [RequestContext].

View file

@ -76,7 +76,7 @@ abstract class RequestContext<RawRequest> {
/// The content type of an incoming request. /// The content type of an incoming request.
MediaType get contentType => MediaType get contentType =>
_contentType ??= new MediaType.parse(headers.contentType.toString()); _contentType ??= MediaType.parse(headers.contentType.toString());
/// The URL parameters extracted from the request URI. /// The URL parameters extracted from the request URI.
Map<String, dynamic> params = <String, dynamic>{}; Map<String, dynamic> params = <String, dynamic>{};
@ -110,9 +110,9 @@ abstract class RequestContext<RawRequest> {
/// Note that [parseBody] must be called first. /// Note that [parseBody] must be called first.
Map<String, dynamic> get bodyAsMap { Map<String, dynamic> get bodyAsMap {
if (!hasParsedBody) { if (!hasParsedBody) {
throw new StateError('The request body has not been parsed yet.'); throw StateError('The request body has not been parsed yet.');
} else if (_bodyFields == null) { } else if (_bodyFields == null) {
throw new StateError('The request body, $_bodyObject, is not a Map.'); throw StateError('The request body, $_bodyObject, is not a Map.');
} }
return _bodyFields; return _bodyFields;
@ -128,9 +128,9 @@ abstract class RequestContext<RawRequest> {
/// Note that [parseBody] must be called first. /// Note that [parseBody] must be called first.
List get bodyAsList { List get bodyAsList {
if (!hasParsedBody) { if (!hasParsedBody) {
throw new StateError('The request body has not been parsed yet.'); throw StateError('The request body has not been parsed yet.');
} else if (_bodyList == null) { } else if (_bodyList == null) {
throw new StateError('The request body, $_bodyObject, is not a List.'); throw StateError('The request body, $_bodyObject, is not a List.');
} }
return _bodyList; return _bodyList;
@ -146,7 +146,7 @@ abstract class RequestContext<RawRequest> {
/// Note that [parseBody] must be called first. /// Note that [parseBody] must be called first.
Object get bodyAsObject { Object get bodyAsObject {
if (!hasParsedBody) { if (!hasParsedBody) {
throw new StateError('The request body has not been parsed yet.'); throw StateError('The request body has not been parsed yet.');
} }
return _bodyObject; return _bodyObject;
@ -172,7 +172,7 @@ abstract class RequestContext<RawRequest> {
/// Note that [parseBody] must be called first. /// Note that [parseBody] must be called first.
List<UploadedFile> get uploadedFiles { List<UploadedFile> get uploadedFiles {
if (!hasParsedBody) { if (!hasParsedBody) {
throw new StateError('The request body has not been parsed yet.'); throw StateError('The request body has not been parsed yet.');
} }
return _uploadedFiles; return _uploadedFiles;
@ -180,7 +180,7 @@ abstract class RequestContext<RawRequest> {
/// Returns a *mutable* map of the fields contained in the query. /// Returns a *mutable* map of the fields contained in the query.
Map<String, dynamic> get queryParameters => Map<String, dynamic> get queryParameters =>
_queryParameters ??= new Map<String, dynamic>.from(uri.queryParameters); _queryParameters ??= Map<String, dynamic>.from(uri.queryParameters);
/// Returns the file extension of the requested path, if any. /// Returns the file extension of the requested path, if any.
/// ///
@ -203,7 +203,7 @@ abstract class RequestContext<RawRequest> {
// Change to assert // Change to assert
if (contentTypeString == null) if (contentTypeString == null)
throw new ArgumentError( throw ArgumentError(
'RequestContext.accepts expects the `contentType` parameter to NOT be null.'); 'RequestContext.accepts expects the `contentType` parameter to NOT be null.');
_acceptHeaderCache ??= headers.value('accept'); _acceptHeaderCache ??= headers.value('accept');
@ -235,7 +235,7 @@ abstract class RequestContext<RawRequest> {
await body.transform(encoding.decoder).join().then(json.decode); await body.transform(encoding.decoder).join().then(json.decode);
if (parsed is Map) { if (parsed is Map) {
_bodyFields = new Map<String, dynamic>.from(parsed); _bodyFields = Map<String, dynamic>.from(parsed);
} else if (parsed is List) { } else if (parsed is List) {
_bodyList = parsed; _bodyList = parsed;
} }
@ -246,12 +246,12 @@ abstract class RequestContext<RawRequest> {
.transform(encoding.decoder) .transform(encoding.decoder)
.join() .join()
.then((s) => Uri.splitQueryString(s, encoding: encoding)); .then((s) => Uri.splitQueryString(s, encoding: encoding));
_bodyFields = new Map<String, dynamic>.from(parsed); _bodyFields = Map<String, dynamic>.from(parsed);
} else if (contentType.type == 'multipart' && } else if (contentType.type == 'multipart' &&
contentType.subtype == 'form-data' && contentType.subtype == 'form-data' &&
contentType.parameters.containsKey('boundary')) { contentType.parameters.containsKey('boundary')) {
var boundary = contentType.parameters['boundary']; var boundary = contentType.parameters['boundary'];
var transformer = new MimeMultipartTransformer(boundary); var transformer = MimeMultipartTransformer(boundary);
var parts = body.transform(transformer).map((part) => var parts = body.transform(transformer).map((part) =>
HttpMultipartFormData.parse(part, defaultEncoding: encoding)); HttpMultipartFormData.parse(part, defaultEncoding: encoding));
_bodyFields = {}; _bodyFields = {};
@ -259,7 +259,7 @@ abstract class RequestContext<RawRequest> {
await for (var part in parts) { await for (var part in parts) {
if (part.isBinary) { if (part.isBinary) {
_uploadedFiles.add(new UploadedFile(part)); _uploadedFiles.add(UploadedFile(part));
} else if (part.isText && } else if (part.isText &&
part.contentDisposition.parameters.containsKey('name')) { part.contentDisposition.parameters.containsKey('name')) {
// If there is no name, then don't parse it. // If there is no name, then don't parse it.
@ -313,7 +313,7 @@ class UploadedFile {
/// Returns [:null:] if not present. /// Returns [:null:] if not present.
MediaType get contentType => _contentType ??= (formData.contentType == null MediaType get contentType => _contentType ??= (formData.contentType == null
? null ? null
: new MediaType.parse(formData.contentType.toString())); : MediaType.parse(formData.contentType.toString()));
/// The parsed [:Content-Transfer-Encoding:] header of the /// The parsed [:Content-Transfer-Encoding:] header of the
/// [:HttpMultipartFormData:]. This field is used to determine how to decode /// [:HttpMultipartFormData:]. This field is used to determine how to decode

View file

@ -14,14 +14,13 @@ import 'controller.dart';
import 'request_context.dart'; import 'request_context.dart';
import 'server.dart' show Angel; import 'server.dart' show Angel;
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)'); final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
/// A convenience wrapper around an outgoing HTTP request. /// A convenience wrapper around an outgoing HTTP request.
abstract class ResponseContext<RawResponse> abstract class ResponseContext<RawResponse>
implements StreamSink<List<int>>, StringSink { implements StreamSink<List<int>>, StringSink {
final Map properties = {}; final Map properties = {};
final CaseInsensitiveMap<String> _headers = final CaseInsensitiveMap<String> _headers = CaseInsensitiveMap<String>.from({
new CaseInsensitiveMap<String>.from({
'content-type': 'text/plain', 'content-type': 'text/plain',
'server': 'angel', 'server': 'angel',
}); });
@ -52,7 +51,7 @@ abstract class ResponseContext<RawResponse>
RequestContext get correspondingRequest; RequestContext get correspondingRequest;
@override @override
Future get done => (_done ?? new Completer()).future; Future get done => (_done ?? Completer()).future;
/// Headers that will be sent to the user. /// Headers that will be sent to the user.
/// ///
@ -124,9 +123,9 @@ abstract class ResponseContext<RawResponse>
/// Gets or sets the content type to send back to a client. /// Gets or sets the content type to send back to a client.
MediaType get contentType { MediaType get contentType {
try { try {
return new MediaType.parse(headers['content-type']); return MediaType.parse(headers['content-type']);
} catch (_) { } catch (_) {
return new MediaType('text', 'plain'); return MediaType('text', 'plain');
} }
} }
@ -135,8 +134,7 @@ abstract class ResponseContext<RawResponse>
headers['content-type'] = value.toString(); headers['content-type'] = value.toString();
} }
static StateError closed() => static StateError closed() => StateError('Cannot modify a closed response.');
new StateError('Cannot modify a closed response.');
/// Sends a download as a response. /// Sends a download as a response.
Future<void> download(File file, {String filename}) async { Future<void> download(File file, {String filename}) async {
@ -162,7 +160,7 @@ abstract class ResponseContext<RawResponse>
} }
if (_done?.isCompleted == false) _done.complete(); if (_done?.isCompleted == false) _done.complete();
return new Future.value(); return Future.value();
} }
/// Serializes JSON to the response. /// Serializes JSON to the response.
@ -176,8 +174,7 @@ abstract class ResponseContext<RawResponse>
Future<void> jsonp(value, Future<void> jsonp(value,
{String callbackName = "callback", MediaType contentType}) { {String callbackName = "callback", MediaType contentType}) {
if (!isOpen) throw closed(); if (!isOpen) throw closed();
this.contentType = this.contentType = contentType ?? MediaType('application', 'javascript');
contentType ?? new MediaType('application', 'javascript');
write("$callbackName(${serializer(value)})"); write("$callbackName(${serializer(value)})");
return close(); return close();
} }
@ -185,10 +182,10 @@ abstract class ResponseContext<RawResponse>
/// Renders a view to the response stream, and closes the response. /// Renders a view to the response stream, and closes the response.
Future<void> render(String view, [Map<String, dynamic> data]) { Future<void> render(String view, [Map<String, dynamic> data]) {
if (!isOpen) throw closed(); if (!isOpen) throw closed();
contentType = new MediaType('text', 'html', {'charset': 'utf-8'}); contentType = MediaType('text', 'html', {'charset': 'utf-8'});
return Future<String>.sync(() => app.viewGenerator( return Future<String>.sync(() => app.viewGenerator(
view, view,
new Map<String, dynamic>.from(renderParams) Map<String, dynamic>.from(renderParams)
..addAll(data ?? <String, dynamic>{}))).then((content) { ..addAll(data ?? <String, dynamic>{}))).then((content) {
write(content); write(content);
return close(); return close();
@ -256,7 +253,7 @@ abstract class ResponseContext<RawResponse>
return; return;
} }
throw new ArgumentError.notNull('Route to redirect to ($name)'); throw ArgumentError.notNull('Route to redirect to ($name)');
} }
/// Redirects to the given [Controller] action. /// Redirects to the given [Controller] action.
@ -266,19 +263,19 @@ abstract class ResponseContext<RawResponse>
List<String> split = action.split("@"); List<String> split = action.split("@");
if (split.length < 2) if (split.length < 2)
throw new Exception( throw Exception(
"Controller redirects must take the form of 'Controller@action'. You gave: $action"); "Controller redirects must take the form of 'Controller@action'. You gave: $action");
Controller controller = Controller controller =
app.controllers[split[0].replaceAll(_straySlashes, '')]; app.controllers[split[0].replaceAll(_straySlashes, '')];
if (controller == null) if (controller == null)
throw new Exception("Could not find a controller named '${split[0]}'"); throw Exception("Could not find a controller named '${split[0]}'");
Route matched = controller.routeMappings[split[1]]; Route matched = controller.routeMappings[split[1]];
if (matched == null) if (matched == null)
throw new Exception( throw Exception(
"Controller '${split[0]}' does not contain any action named '${split[1]}'"); "Controller '${split[0]}' does not contain any action named '${split[1]}'");
final head = controller final head = controller
@ -298,7 +295,7 @@ abstract class ResponseContext<RawResponse>
/// Serializes data to the response. /// Serializes data to the response.
Future<bool> serialize(value, {MediaType contentType}) async { Future<bool> serialize(value, {MediaType contentType}) async {
if (!isOpen) throw closed(); if (!isOpen) throw closed();
this.contentType = contentType ?? new MediaType('application', 'json'); this.contentType = contentType ?? MediaType('application', 'json');
var text = await serializer(value); var text = await serializer(value);
if (text.isEmpty) return true; if (text.isEmpty) return true;
write(text); write(text);
@ -314,7 +311,7 @@ abstract class ResponseContext<RawResponse>
var mimeType = app.mimeTypeResolver.lookup(file.path); var mimeType = app.mimeTypeResolver.lookup(file.path);
contentLength = await file.length(); contentLength = await file.length();
contentType = mimeType == null contentType = mimeType == null
? new MediaType('application', 'octet-stream') ? MediaType('application', 'octet-stream')
: MediaType.parse(mimeType); : MediaType.parse(mimeType);
if (correspondingRequest.method != 'HEAD') if (correspondingRequest.method != 'HEAD')
@ -375,18 +372,18 @@ abstract class ResponseContext<RawResponse>
abstract class LockableBytesBuilder extends BytesBuilder { abstract class LockableBytesBuilder extends BytesBuilder {
factory LockableBytesBuilder() { factory LockableBytesBuilder() {
return new _LockableBytesBuilderImpl(); return _LockableBytesBuilderImpl();
} }
void lock(); void lock();
} }
class _LockableBytesBuilderImpl implements LockableBytesBuilder { class _LockableBytesBuilderImpl implements LockableBytesBuilder {
final BytesBuilder _buf = new BytesBuilder(copy: false); final BytesBuilder _buf = BytesBuilder(copy: false);
bool _closed = false; bool _closed = false;
StateError _deny() => StateError _deny() =>
new StateError('Cannot modified a closed response\'s buffer.'); StateError('Cannot modified a closed response\'s buffer.');
@override @override
void lock() { void lock() {

View file

@ -12,7 +12,7 @@ import 'request_context.dart';
import 'response_context.dart'; import 'response_context.dart';
import 'service.dart'; import 'service.dart';
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)'); final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
/// A function that receives an incoming [RequestContext] and responds to it. /// A function that receives an incoming [RequestContext] and responds to it.
typedef FutureOr RequestHandler(RequestContext req, ResponseContext res); typedef FutureOr RequestHandler(RequestContext req, ResponseContext res);
@ -31,12 +31,12 @@ RequestHandler chain(Iterable<RequestHandler> handlers) {
else { else {
var current = runPipeline; var current = runPipeline;
runPipeline = () => current().then((result) => !res.isOpen runPipeline = () => current().then((result) => !res.isOpen
? new Future.value(result) ? Future.value(result)
: req.app.executeHandler(handler, req, res)); : req.app.executeHandler(handler, req, res));
} }
} }
runPipeline ??= () => new Future.value(); runPipeline ??= () => Future.value();
return runPipeline(); return runPipeline();
}; };
} }
@ -50,7 +50,7 @@ class Routable extends Router<RequestHandler> {
final Container _container; final Container _container;
Routable([Reflector reflector]) Routable([Reflector reflector])
: _container = reflector == null ? null : new Container(reflector), : _container = reflector == null ? null : Container(reflector),
super(); super();
/// A [Container] used to inject dependencies. /// A [Container] used to inject dependencies.
@ -65,8 +65,7 @@ class Routable extends Router<RequestHandler> {
/// A set of [Service] objects that have been mapped into routes. /// A set of [Service] objects that have been mapped into routes.
Map<Pattern, Service> get services => _services; Map<Pattern, Service> get services => _services;
StreamController<Service> _onService = StreamController<Service> _onService = StreamController<Service>.broadcast();
new StreamController<Service>.broadcast();
/// Fired whenever a service is added to this instance. /// Fired whenever a service is added to this instance.
/// ///
@ -119,11 +118,9 @@ class Routable extends Router<RequestHandler> {
/// events dispatched by this service. /// events dispatched by this service.
HookedService<Id, Data, T> use<Id, Data, T extends Service<Id, Data>>( HookedService<Id, Data, T> use<Id, Data, T extends Service<Id, Data>>(
String path, T service) { String path, T service) {
var hooked = new HookedService<Id, Data, T>(service); var hooked = HookedService<Id, Data, T>(service);
_services[path _services[path.toString().trim().replaceAll(RegExp(r'(^/+)|(/+$)'), '')] =
.toString() hooked;
.trim()
.replaceAll(new RegExp(r'(^/+)|(/+$)'), '')] = hooked;
hooked.addRoutes(); hooked.addRoutes();
mount(path.toString(), hooked); mount(path.toString(), hooked);
service.onHooked(hooked); service.onHooked(hooked);

View file

@ -19,7 +19,7 @@ import 'response_context.dart';
import 'routable.dart'; import 'routable.dart';
import 'service.dart'; import 'service.dart';
//final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)'); //final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
/// A function that configures an [Angel] server in some way. /// A function that configures an [Angel] server in some way.
typedef FutureOr<void> AngelConfigurer(Angel app); typedef FutureOr<void> AngelConfigurer(Angel app);
@ -37,7 +37,7 @@ class Angel extends Routable {
final Map< final Map<
String, String,
Tuple4<List, Map<String, dynamic>, ParseResult<RouteResult>, Tuple4<List, Map<String, dynamic>, ParseResult<RouteResult>,
MiddlewarePipeline>> handlerCache = new HashMap(); MiddlewarePipeline>> handlerCache = HashMap();
Router<RequestHandler> _flattened; Router<RequestHandler> _flattened;
Angel _parent; Angel _parent;
@ -48,7 +48,7 @@ class Angel extends Routable {
final Map<dynamic, InjectionRequest> _preContained = {}; final Map<dynamic, InjectionRequest> _preContained = {};
/// A [MimeTypeResolver] that can be used to specify the MIME types of files not known by `package:mime`. /// A [MimeTypeResolver] that can be used to specify the MIME types of files not known by `package:mime`.
final MimeTypeResolver mimeTypeResolver = new MimeTypeResolver(); final MimeTypeResolver mimeTypeResolver = MimeTypeResolver();
/// A middleware to inject a serialize on every request. /// A middleware to inject a serialize on every request.
FutureOr<String> Function(dynamic) serializer; FutureOr<String> Function(dynamic) serializer;
@ -65,7 +65,7 @@ class Angel extends Routable {
bool allowMethodOverrides = true; bool allowMethodOverrides = true;
/// All child application mounted on this instance. /// All child application mounted on this instance.
List<Angel> get children => new List<Angel>.unmodifiable(_children); List<Angel> get children => List<Angel>.unmodifiable(_children);
final Map<Pattern, Controller> _controllers = {}; final Map<Pattern, Controller> _controllers = {};
@ -134,7 +134,7 @@ class Angel extends Routable {
return; return;
} }
res.contentType = new MediaType('text', 'html', {'charset': 'utf8'}); res.contentType = MediaType('text', 'html', {'charset': 'utf8'});
res.statusCode = e.statusCode; res.statusCode = e.statusCode;
res.write("<!DOCTYPE html><html><head><title>${e.message}</title>"); res.write("<!DOCTYPE html><html><head><title>${e.message}</title>");
res.write("</head><body><h1>${e.message}</h1><ul>"); res.write("</head><body><h1>${e.message}</h1><ul>");
@ -211,7 +211,7 @@ class Angel extends Routable {
shutdownHooks.clear(); shutdownHooks.clear();
responseFinalizers.clear(); responseFinalizers.clear();
_flattened = null; _flattened = null;
return new Future.value(); return Future.value();
} }
@override @override
@ -262,7 +262,7 @@ class Angel extends Routable {
return getHandlerResult(handler.toList(), req, res); return getHandlerResult(handler.toList(), req, res);
} }
return new Future.value(handler); return Future.value(handler);
} }
/// Runs some [handler]. Returns `true` if request execution should continue. /// Runs some [handler]. Returns `true` if request execution should continue.
@ -305,7 +305,7 @@ class Angel extends Routable {
/// the execution will be faster, as the injection requirements were stored beforehand. /// the execution will be faster, as the injection requirements were stored beforehand.
Future runContained(Function handler, RequestContext req, ResponseContext res, Future runContained(Function handler, RequestContext req, ResponseContext res,
[Container container]) { [Container container]) {
return new Future.sync(() { return Future.sync(() {
if (_preContained.containsKey(handler)) { if (_preContained.containsKey(handler)) {
return handleContained(handler, _preContained[handler], container)( return handleContained(handler, _preContained[handler], container)(
req, res); req, res);
@ -323,13 +323,13 @@ class Angel extends Routable {
handler, handler,
_preContained[handler] = preInject(handler, container.reflector), _preContained[handler] = preInject(handler, container.reflector),
container); container);
return new Future.sync(() => h(req, res)); return Future.sync(() => h(req, res));
// return closureMirror.apply(args).reflectee; // return closureMirror.apply(args).reflectee;
} }
/// Applies an [AngelConfigurer] to this instance. /// Applies an [AngelConfigurer] to this instance.
Future configure(AngelConfigurer configurer) { Future configure(AngelConfigurer configurer) {
return new Future.sync(() => configurer(this)); return Future.sync(() => configurer(this));
} }
/// Shorthand for using the [container] to instantiate, and then mount a [Controller]. /// Shorthand for using the [container] to instantiate, and then mount a [Controller].

View file

@ -107,10 +107,10 @@ class Service<Id, Data> extends Routable {
String errorMessage = 'No record was found matching the given query.']) { String errorMessage = 'No record was found matching the given query.']) {
return index(params).then((result) { return index(params).then((result) {
if (result == null) { if (result == null) {
throw new AngelHttpException.notFound(message: errorMessage); throw AngelHttpException.notFound(message: errorMessage);
} else { } else {
if (result.isEmpty) { if (result.isEmpty) {
throw new AngelHttpException.notFound(message: errorMessage); throw AngelHttpException.notFound(message: errorMessage);
} else { } else {
return result.first; return result.first;
} }
@ -120,12 +120,12 @@ class Service<Id, Data> extends Routable {
/// Retrieves all resources. /// Retrieves all resources.
Future<List<Data>> index([Map<String, dynamic> params]) { Future<List<Data>> index([Map<String, dynamic> params]) {
throw new AngelHttpException.methodNotAllowed(); throw AngelHttpException.methodNotAllowed();
} }
/// Retrieves the desired resource. /// Retrieves the desired resource.
Future<Data> read(Id id, [Map<String, dynamic> params]) { Future<Data> read(Id id, [Map<String, dynamic> params]) {
throw new AngelHttpException.methodNotAllowed(); throw AngelHttpException.methodNotAllowed();
} }
/// Reads multiple resources at once. /// Reads multiple resources at once.
@ -138,22 +138,22 @@ class Service<Id, Data> extends Routable {
/// Creates a resource. /// Creates a resource.
Future<Data> create(Data data, [Map<String, dynamic> params]) { Future<Data> create(Data data, [Map<String, dynamic> params]) {
throw new AngelHttpException.methodNotAllowed(); throw AngelHttpException.methodNotAllowed();
} }
/// Modifies a resource. /// Modifies a resource.
Future<Data> modify(Id id, Data data, [Map<String, dynamic> params]) { Future<Data> modify(Id id, Data data, [Map<String, dynamic> params]) {
throw new AngelHttpException.methodNotAllowed(); throw AngelHttpException.methodNotAllowed();
} }
/// Overwrites a resource. /// Overwrites a resource.
Future<Data> update(Id id, Data data, [Map<String, dynamic> params]) { Future<Data> update(Id id, Data data, [Map<String, dynamic> params]) {
throw new AngelHttpException.methodNotAllowed(); throw AngelHttpException.methodNotAllowed();
} }
/// Removes the given resource. /// Removes the given resource.
Future<Data> remove(Id id, [Map<String, dynamic> params]) { Future<Data> remove(Id id, [Map<String, dynamic> params]) {
throw new AngelHttpException.methodNotAllowed(); throw AngelHttpException.methodNotAllowed();
} }
/// Creates an [AnonymousService] that wraps over this one, and maps input and output /// Creates an [AnonymousService] that wraps over this one, and maps input and output
@ -167,7 +167,7 @@ class Service<Id, Data> extends Routable {
return encoder(inner); return encoder(inner);
}; };
return new AnonymousService<Id, U>( return AnonymousService<Id, U>(
readData: readData, readData: readData,
index: ([params]) { index: ([params]) {
return index(params).then((it) => it.map(encoder).toList()); return index(params).then((it) => it.map(encoder).toList());
@ -219,7 +219,7 @@ class Service<Id, Data> extends Routable {
void _addRoutesInner(Service service, Iterable<RequestHandler> handlerss) { void _addRoutesInner(Service service, Iterable<RequestHandler> handlerss) {
var restProvider = {'provider': Providers.rest}; var restProvider = {'provider': Providers.rest};
var handlers = new List<RequestHandler>.from(handlerss); var handlers = List<RequestHandler>.from(handlerss);
// Add global middleware if declared on the instance itself // Add global middleware if declared on the instance itself
Middleware before = Middleware before =
@ -363,8 +363,8 @@ class Service<Id, Data> extends Routable {
(removeMiddleware == null) ? [] : removeMiddleware.handlers)); (removeMiddleware == null) ? [] : removeMiddleware.handlers));
// REST compliance // REST compliance
put('/', (req, res) => throw new AngelHttpException.notFound()); put('/', (req, res) => throw AngelHttpException.notFound());
patch('/', (req, res) => throw new AngelHttpException.notFound()); patch('/', (req, res) => throw AngelHttpException.notFound());
} }
/// Invoked when this service is wrapped within a [HookedService]. /// Invoked when this service is wrapped within a [HookedService].

View file

@ -13,33 +13,33 @@ import '../core/core.dart';
import 'http_request_context.dart'; import 'http_request_context.dart';
import 'http_response_context.dart'; import 'http_response_context.dart';
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)'); final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
/// Adapts `dart:io`'s [HttpServer] to serve Angel. /// Adapts `dart:io`'s [HttpServer] to serve Angel.
class AngelHttp extends Driver<HttpRequest, HttpResponse, HttpServer, class AngelHttp extends Driver<HttpRequest, HttpResponse, HttpServer,
HttpRequestContext, HttpResponseContext> { HttpRequestContext, HttpResponseContext> {
@override @override
Uri get uri => Uri get uri =>
new Uri(scheme: 'http', host: server.address.address, port: server.port); Uri(scheme: 'http', host: server.address.address, port: server.port);
AngelHttp._(Angel app, AngelHttp._(Angel app,
Future<HttpServer> Function(dynamic, int) serverGenerator, bool useZone) Future<HttpServer> Function(dynamic, int) serverGenerator, bool useZone)
: super(app, serverGenerator, useZone: useZone); : super(app, serverGenerator, useZone: useZone);
factory AngelHttp(Angel app, {bool useZone = true}) { factory AngelHttp(Angel app, {bool useZone = true}) {
return new AngelHttp._(app, HttpServer.bind, useZone); return AngelHttp._(app, HttpServer.bind, useZone);
} }
/// An instance mounted on a server started by the [serverGenerator]. /// An instance mounted on a server started by the [serverGenerator].
factory AngelHttp.custom( factory AngelHttp.custom(
Angel app, Future<HttpServer> Function(dynamic, int) serverGenerator, Angel app, Future<HttpServer> Function(dynamic, int) serverGenerator,
{bool useZone = true}) { {bool useZone = true}) {
return new AngelHttp._(app, serverGenerator, useZone); return AngelHttp._(app, serverGenerator, useZone);
} }
factory AngelHttp.fromSecurityContext(Angel app, SecurityContext context, factory AngelHttp.fromSecurityContext(Angel app, SecurityContext context,
{bool useZone = true}) { {bool useZone = true}) {
return new AngelHttp._(app, (address, int port) { return AngelHttp._(app, (address, int port) {
return HttpServer.bindSecure(address, port, context); return HttpServer.bindSecure(address, port, context);
}, useZone); }, useZone);
} }
@ -55,11 +55,10 @@ class AngelHttp extends Driver<HttpRequest, HttpResponse, HttpServer,
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 = SecurityContext();
serverContext.useCertificateChain(certificateChain, password: password); serverContext.useCertificateChain(certificateChain, password: password);
serverContext.usePrivateKey(serverKey, password: password); serverContext.usePrivateKey(serverKey, password: password);
return new AngelHttp.fromSecurityContext(app, serverContext, return AngelHttp.fromSecurityContext(app, serverContext, useZone: useZone);
useZone: useZone);
} }
/// Use [server] instead. /// Use [server] instead.
@ -94,8 +93,8 @@ class AngelHttp extends Driver<HttpRequest, HttpResponse, HttpServer,
Future<HttpResponseContext> createResponseContext( Future<HttpResponseContext> createResponseContext(
HttpRequest request, HttpResponse response, HttpRequest request, HttpResponse response,
[HttpRequestContext correspondingRequest]) { [HttpRequestContext correspondingRequest]) {
return new Future<HttpResponseContext>.value( return Future<HttpResponseContext>.value(
new HttpResponseContext(response, app, correspondingRequest) HttpResponseContext(response, app, correspondingRequest)
..serializer = (app.serializer ?? json.encode) ..serializer = (app.serializer ?? json.encode)
..encoders.addAll(app.encoders ?? {})); ..encoders.addAll(app.encoders ?? {}));
} }
@ -103,7 +102,7 @@ class AngelHttp extends Driver<HttpRequest, HttpResponse, HttpServer,
@override @override
Stream<HttpResponse> createResponseStreamFromRawRequest( Stream<HttpResponse> createResponseStreamFromRawRequest(
HttpRequest request) => HttpRequest request) =>
new Stream.fromIterable([request.response]); Stream.fromIterable([request.response]);
@override @override
void setChunkedEncoding(HttpResponse response, bool value) => void setChunkedEncoding(HttpResponse response, bool value) =>

View file

@ -75,7 +75,7 @@ class HttpRequestContext extends RequestContext<HttpRequest> {
/// Magically transforms an [HttpRequest] into a [RequestContext]. /// Magically transforms an [HttpRequest] into a [RequestContext].
static Future<HttpRequestContext> from( static Future<HttpRequestContext> from(
HttpRequest request, Angel app, String path) { HttpRequest request, Angel app, String path) {
HttpRequestContext ctx = new HttpRequestContext() HttpRequestContext ctx = HttpRequestContext()
.._container = app.container.createChild(); .._container = app.container.createChild();
String override = request.method; String override = request.method;
@ -114,15 +114,15 @@ class HttpRequestContext extends RequestContext<HttpRequest> {
} }
if (lastSlash > -1) if (lastSlash > -1)
ctx._path = new String.fromCharCodes(_path.take(lastSlash)); ctx._path = String.fromCharCodes(_path.take(lastSlash));
else else
ctx._path = new String.fromCharCodes(_path); ctx._path = String.fromCharCodes(_path);
*/ */
ctx._path = path; ctx._path = path;
ctx._io = request; ctx._io = request;
return new Future.value(ctx); return Future.value(ctx);
} }
@override @override

View file

@ -51,7 +51,7 @@ class HttpResponseContext extends ResponseContext<HttpResponse> {
@override @override
void useBuffer() { void useBuffer() {
_buffer = new LockableBytesBuilder(); _buffer = LockableBytesBuilder();
} }
Iterable<String> __allowedEncodings; Iterable<String> __allowedEncodings;
@ -92,7 +92,7 @@ class HttpResponseContext extends ResponseContext<HttpResponse> {
rawResponse.contentLength; rawResponse.contentLength;
} }
rawResponse.headers.contentType = new ContentType( rawResponse.headers.contentType = ContentType(
contentType.type, contentType.subtype, contentType.type, contentType.subtype,
charset: contentType.parameters['charset'], charset: contentType.parameters['charset'],
parameters: contentType.parameters); parameters: contentType.parameters);
@ -209,6 +209,6 @@ class HttpResponseContext extends ResponseContext<HttpResponse> {
super.close(); super.close();
} }
return new Future.value(); return Future.value();
} }
} }

View file

@ -19,9 +19,9 @@ Future<SecureServerSocket> startSharedHttp2(
class AngelHttp2 extends Driver<Socket, ServerTransportStream, class AngelHttp2 extends Driver<Socket, ServerTransportStream,
SecureServerSocket, Http2RequestContext, Http2ResponseContext> { SecureServerSocket, Http2RequestContext, Http2ResponseContext> {
final ServerSettings settings; final ServerSettings settings;
final StreamController<HttpRequest> _onHttp1 = new StreamController(); final StreamController<HttpRequest> _onHttp1 = StreamController();
final Map<String, MockHttpSession> _sessions = {}; final Map<String, MockHttpSession> _sessions = {};
final Uuid _uuid = new Uuid(); final Uuid _uuid = Uuid();
_AngelHttp2ServerSocket _artificial; _AngelHttp2ServerSocket _artificial;
SecureServerSocket get socket => _artificial; SecureServerSocket get socket => _artificial;
@ -39,7 +39,7 @@ class AngelHttp2 extends Driver<Socket, ServerTransportStream,
factory AngelHttp2(Angel app, SecurityContext securityContext, factory AngelHttp2(Angel app, SecurityContext securityContext,
{bool useZone = true, ServerSettings settings}) { {bool useZone = true, ServerSettings settings}) {
return new AngelHttp2.custom(app, securityContext, SecureServerSocket.bind, return AngelHttp2.custom(app, securityContext, SecureServerSocket.bind,
settings: settings); settings: settings);
} }
@ -50,10 +50,10 @@ class AngelHttp2 extends Driver<Socket, ServerTransportStream,
address, int port, SecurityContext ctx), address, int port, SecurityContext ctx),
{bool useZone = true, {bool useZone = true,
ServerSettings settings}) { ServerSettings settings}) {
return new AngelHttp2._(app, (address, port) { return AngelHttp2._(app, (address, port) {
var addr = address is InternetAddress var addr = address is InternetAddress
? address ? address
: new InternetAddress(address.toString()); : InternetAddress(address.toString());
return Future.sync(() => serverGenerator(addr, port, ctx)); return Future.sync(() => serverGenerator(addr, port, ctx));
}, useZone, settings); }, useZone, settings);
} }
@ -64,7 +64,7 @@ class AngelHttp2 extends Driver<Socket, ServerTransportStream,
@override @override
Future<SecureServerSocket> generateServer([address, int port]) async { Future<SecureServerSocket> generateServer([address, int port]) async {
var s = await serverGenerator(address ?? '127.0.0.1', port ?? 0); var s = await serverGenerator(address ?? '127.0.0.1', port ?? 0);
return _artificial = new _AngelHttp2ServerSocket(s, this); return _artificial = _AngelHttp2ServerSocket(s, this);
} }
@override @override
@ -75,15 +75,15 @@ class AngelHttp2 extends Driver<Socket, ServerTransportStream,
@override @override
void addCookies(ServerTransportStream response, Iterable<Cookie> cookies) { void addCookies(ServerTransportStream response, Iterable<Cookie> cookies) {
var headers = cookies var headers =
.map((cookie) => new Header.ascii('set-cookie', cookie.toString())); cookies.map((cookie) => Header.ascii('set-cookie', cookie.toString()));
response.sendHeaders(headers.toList()); response.sendHeaders(headers.toList());
} }
@override @override
Future closeResponse(ServerTransportStream response) { Future closeResponse(ServerTransportStream response) {
response.terminate(); response.terminate();
return new Future.value(); return Future.value();
} }
@override @override
@ -96,7 +96,7 @@ class AngelHttp2 extends Driver<Socket, ServerTransportStream,
Future<Http2ResponseContext> createResponseContext( Future<Http2ResponseContext> createResponseContext(
Socket request, ServerTransportStream response, Socket request, ServerTransportStream response,
[Http2RequestContext correspondingRequest]) async { [Http2RequestContext correspondingRequest]) async {
return new Http2ResponseContext(app, response, correspondingRequest) return Http2ResponseContext(app, response, correspondingRequest)
..encoders.addAll(app.encoders); ..encoders.addAll(app.encoders);
} }
@ -104,7 +104,7 @@ class AngelHttp2 extends Driver<Socket, ServerTransportStream,
Stream<ServerTransportStream> createResponseStreamFromRawRequest( Stream<ServerTransportStream> createResponseStreamFromRawRequest(
Socket request) { Socket request) {
var connection = var connection =
new ServerTransportConnection.viaSocket(request, settings: settings); ServerTransportConnection.viaSocket(request, settings: settings);
return connection.incomingStreams; return connection.incomingStreams;
} }
@ -120,12 +120,12 @@ class AngelHttp2 extends Driver<Socket, ServerTransportStream,
@override @override
void setHeader(ServerTransportStream response, String key, String value) { void setHeader(ServerTransportStream response, String key, String value) {
response.sendHeaders([new Header.ascii(key, value)]); response.sendHeaders([Header.ascii(key, value)]);
} }
@override @override
void setStatusCode(ServerTransportStream response, int value) { void setStatusCode(ServerTransportStream response, int value) {
response.sendHeaders([new Header.ascii(':status', value.toString())]); response.sendHeaders([Header.ascii(':status', value.toString())]);
} }
@override @override
@ -147,7 +147,7 @@ class AngelHttp2 extends Driver<Socket, ServerTransportStream,
class _FakeServerSocket extends Stream<Socket> implements ServerSocket { class _FakeServerSocket extends Stream<Socket> implements ServerSocket {
final _AngelHttp2ServerSocket angel; final _AngelHttp2ServerSocket angel;
final _ctrl = new StreamController<Socket>(); final _ctrl = StreamController<Socket>();
_FakeServerSocket(this.angel); _FakeServerSocket(this.angel);
@ -175,13 +175,13 @@ class _AngelHttp2ServerSocket extends Stream<SecureSocket>
implements SecureServerSocket { implements SecureServerSocket {
final SecureServerSocket socket; final SecureServerSocket socket;
final AngelHttp2 driver; final AngelHttp2 driver;
final _ctrl = new StreamController<SecureSocket>(); final _ctrl = StreamController<SecureSocket>();
_FakeServerSocket _fake; _FakeServerSocket _fake;
StreamSubscription _sub; StreamSubscription _sub;
_AngelHttp2ServerSocket(this.socket, this.driver) { _AngelHttp2ServerSocket(this.socket, this.driver) {
_fake = new _FakeServerSocket(this); _fake = _FakeServerSocket(this);
new HttpServer.listenOn(_fake).pipe(driver._onHttp1); HttpServer.listenOn(_fake).pipe(driver._onHttp1);
_sub = socket.listen( _sub = socket.listen(
(socket) { (socket) {
if (socket.selectedProtocol == null || if (socket.selectedProtocol == null ||
@ -193,7 +193,7 @@ class _AngelHttp2ServerSocket extends Stream<SecureSocket>
_ctrl.add(socket); _ctrl.add(socket);
} else { } else {
socket.destroy(); socket.destroy();
throw new Exception( throw Exception(
'AngelHttp2 does not support ${socket.selectedProtocol} as an ALPN protocol.'); 'AngelHttp2 does not support ${socket.selectedProtocol} as an ALPN protocol.');
} }
}, },

View file

@ -7,11 +7,11 @@ import 'package:http2/transport.dart';
import 'package:mock_request/mock_request.dart'; import 'package:mock_request/mock_request.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
final RegExp _comma = new RegExp(r',\s*'); final RegExp _comma = RegExp(r',\s*');
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)'); final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
class Http2RequestContext extends RequestContext<ServerTransportStream> { class Http2RequestContext extends RequestContext<ServerTransportStream> {
final StreamController<List<int>> _body = new StreamController(); final StreamController<List<int>> _body = StreamController();
final Container container; final Container container;
List<Cookie> _cookies; List<Cookie> _cookies;
HttpHeaders _headers; HttpHeaders _headers;
@ -32,13 +32,13 @@ class Http2RequestContext extends RequestContext<ServerTransportStream> {
Angel app, Angel app,
Map<String, MockHttpSession> sessions, Map<String, MockHttpSession> sessions,
Uuid uuid) { Uuid uuid) {
var c = new Completer<Http2RequestContext>(); var c = Completer<Http2RequestContext>();
var req = new Http2RequestContext._(app.container.createChild()) var req = Http2RequestContext._(app.container.createChild())
..app = app ..app = app
.._socket = socket .._socket = socket
.._stream = stream; .._stream = stream;
var headers = req._headers = new MockHttpHeaders(); var headers = req._headers = MockHttpHeaders();
// String scheme = 'https', host = socket.address.address, path = ''; // String scheme = 'https', host = socket.address.address, path = '';
var uri = var uri =
Uri(scheme: 'https', host: socket.address.address, port: socket.port); Uri(scheme: 'https', host: socket.address.address, port: socket.port);
@ -46,7 +46,7 @@ class Http2RequestContext extends RequestContext<ServerTransportStream> {
void finalize() { void finalize() {
req req
.._cookies = new List.unmodifiable(cookies) .._cookies = List.unmodifiable(cookies)
.._uri = uri; .._uri = uri;
if (!c.isCompleted) c.complete(req); if (!c.isCompleted) c.complete(req);
} }
@ -97,7 +97,7 @@ class Http2RequestContext extends RequestContext<ServerTransportStream> {
for (var cookieString in cookieStrings) { for (var cookieString in cookieStrings) {
try { try {
cookies.add(new Cookie.fromSetCookieValue(cookieString)); cookies.add(Cookie.fromSetCookieValue(cookieString));
} catch (_) { } catch (_) {
// Ignore malformed cookies, and just don't add them to the container. // Ignore malformed cookies, and just don't add them to the container.
} }
@ -127,12 +127,12 @@ class Http2RequestContext extends RequestContext<ServerTransportStream> {
cookies.firstWhere((c) => c.name == 'DARTSESSID', orElse: () => null); cookies.firstWhere((c) => c.name == 'DARTSESSID', orElse: () => null);
if (dartSessId == null) { if (dartSessId == null) {
dartSessId = new Cookie('DARTSESSID', uuid.v4()); dartSessId = Cookie('DARTSESSID', uuid.v4());
} }
req._session = sessions.putIfAbsent( req._session = sessions.putIfAbsent(
dartSessId.value, dartSessId.value,
() => new MockHttpSession(id: dartSessId.value), () => MockHttpSession(id: dartSessId.value),
); );
return c.future; return c.future;

View file

@ -34,7 +34,7 @@ class Http2ResponseContext extends ResponseContext<ServerTransportStream> {
bool get canPush => stream.canPush; bool get canPush => stream.canPush;
/// Returns a [List] of all resources that have [push]ed to the client. /// Returns a [List] of all resources that have [push]ed to the client.
List<Http2ResponseContext> get pushes => new List.unmodifiable(_pushes); List<Http2ResponseContext> get pushes => List.unmodifiable(_pushes);
@override @override
ServerTransportStream detach() { ServerTransportStream detach() {
@ -65,7 +65,7 @@ class Http2ResponseContext extends ResponseContext<ServerTransportStream> {
@override @override
void useBuffer() { void useBuffer() {
_buffer = new LockableBytesBuilder(); _buffer = LockableBytesBuilder();
} }
/// Write headers, status, etc. to the underlying [stream]. /// Write headers, status, etc. to the underlying [stream].
@ -73,7 +73,7 @@ class Http2ResponseContext extends ResponseContext<ServerTransportStream> {
if (_isPush || _streamInitialized) return false; if (_isPush || _streamInitialized) return false;
var headers = <Header>[ var headers = <Header>[
new Header.ascii(':status', statusCode.toString()), Header.ascii(':status', statusCode.toString()),
]; ];
if (encoders.isNotEmpty && correspondingRequest != null) { if (encoders.isNotEmpty && correspondingRequest != null) {
@ -98,15 +98,15 @@ class Http2ResponseContext extends ResponseContext<ServerTransportStream> {
// Add all normal headers // Add all normal headers
for (var key in this.headers.keys) { for (var key in this.headers.keys) {
headers.add(new Header.ascii(key.toLowerCase(), this.headers[key])); headers.add(Header.ascii(key.toLowerCase(), this.headers[key]));
} }
// Persist session ID // Persist session ID
cookies.add(new Cookie('DARTSESSID', _req.session.id)); cookies.add(Cookie('DARTSESSID', _req.session.id));
// Send all cookies // Send all cookies
for (var cookie in cookies) { for (var cookie in cookies) {
headers.add(new Header.ascii('set-cookie', cookie.toString())); headers.add(Header.ascii('set-cookie', cookie.toString()));
} }
stream.sendHeaders(headers); stream.sendHeaders(headers);
@ -210,18 +210,18 @@ class Http2ResponseContext extends ResponseContext<ServerTransportStream> {
var targetUri = _req.uri.replace(path: path); var targetUri = _req.uri.replace(path: path);
var h = <Header>[ var h = <Header>[
new Header.ascii(':authority', targetUri.authority), Header.ascii(':authority', targetUri.authority),
new Header.ascii(':method', method), Header.ascii(':method', method),
new Header.ascii(':path', targetUri.path), Header.ascii(':path', targetUri.path),
new Header.ascii(':scheme', targetUri.scheme), Header.ascii(':scheme', targetUri.scheme),
]; ];
for (var key in headers.keys) { for (var key in headers.keys) {
h.add(new Header.ascii(key, headers[key])); h.add(Header.ascii(key, headers[key]));
} }
var s = stream.push(h); var s = stream.push(h);
var r = new Http2ResponseContext(app, s, _req) var r = Http2ResponseContext(app, s, _req)
.._isPush = true .._isPush = true
.._targetUri = targetUri; .._targetUri = targetUri;
_pushes.add(r); _pushes.add(r);

View file

@ -4,9 +4,9 @@ typedef void _InitCallback();
/// A [StreamController] boilerplate that prevents memory leaks. /// A [StreamController] boilerplate that prevents memory leaks.
abstract class SafeCtrl<T> { abstract class SafeCtrl<T> {
factory SafeCtrl() => new _SingleSafeCtrl(); factory SafeCtrl() => _SingleSafeCtrl();
factory SafeCtrl.broadcast() => new _BroadcastSafeCtrl(); factory SafeCtrl.broadcast() => _BroadcastSafeCtrl();
Stream<T> get stream; Stream<T> get stream;
@ -25,7 +25,7 @@ class _SingleSafeCtrl<T> implements SafeCtrl<T> {
_InitCallback _initializer; _InitCallback _initializer;
_SingleSafeCtrl() { _SingleSafeCtrl() {
_stream = new StreamController<T>(onListen: () { _stream = StreamController<T>(onListen: () {
_hasListener = true; _hasListener = true;
if (!_initialized && _initializer != null) { if (!_initialized && _initializer != null) {
@ -79,7 +79,7 @@ class _BroadcastSafeCtrl<T> implements SafeCtrl<T> {
_InitCallback _initializer; _InitCallback _initializer;
_BroadcastSafeCtrl() { _BroadcastSafeCtrl() {
_stream = new StreamController<T>.broadcast(onListen: () { _stream = StreamController<T>.broadcast(onListen: () {
_listeners++; _listeners++;
if (!_initialized && _initializer != null) { if (!_initialized && _initializer != null) {

View file

@ -1,6 +1,6 @@
import 'package:angel_container/angel_container.dart'; import 'package:angel_container/angel_container.dart';
final RegExp straySlashes = new RegExp(r'(^/+)|(/+$)'); final RegExp straySlashes = RegExp(r'(^/+)|(/+$)');
T matchingAnnotation<T>(List<ReflectedInstance> metadata) { T matchingAnnotation<T>(List<ReflectedInstance> metadata) {
for (ReflectedInstance metaDatum in metadata) { for (ReflectedInstance metaDatum in metadata) {

View file

@ -5,8 +5,8 @@ import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart'; import 'package:angel_framework/http.dart';
main() async { main() async {
var app = new Angel(); var app = Angel();
var http = new AngelHttp.custom(app, startShared, useZone: false); var http = AngelHttp.custom(app, startShared, useZone: false);
app.get('/', (req, res) => res.write('Hello, world!')); app.get('/', (req, res) => res.write('Hello, world!'));
app.optimizeForProduction(force: true); app.optimizeForProduction(force: true);

View file

@ -59,10 +59,10 @@ main() {
Future<RequestContext> acceptContentTypes( Future<RequestContext> acceptContentTypes(
[Iterable<String> contentTypes = const []]) { [Iterable<String> contentTypes = const []]) {
var headerString = contentTypes.isEmpty ? null : contentTypes.join(','); var headerString = contentTypes.isEmpty ? null : contentTypes.join(',');
var rq = new MockHttpRequest('GET', ENDPOINT); var rq = MockHttpRequest('GET', ENDPOINT);
rq.headers.set('accept', headerString); rq.headers.set('accept', headerString);
rq.close(); rq.close();
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
var http = new AngelHttp(app); var http = AngelHttp(app);
return http.createRequestContext(rq, rq.response); return http.createRequestContext(rq, rq.response);
} }

View file

@ -3,7 +3,7 @@ import 'package:test/test.dart';
main() { main() {
test('custom methods', () async { test('custom methods', () async {
var svc = new AnonymousService<String, String>( var svc = AnonymousService<String, String>(
index: ([p]) async => ['index'], index: ([p]) async => ['index'],
read: (id, [p]) async => 'read', read: (id, [p]) async => 'read',
create: (data, [p]) async => 'create', create: (data, [p]) async => 'create',
@ -20,21 +20,21 @@ main() {
test('defaults to throwing', () async { test('defaults to throwing', () async {
try { try {
var svc = new AnonymousService(); var svc = AnonymousService();
await svc.read(1); await svc.read(1);
throw 'Should have thrown 405!'; throw 'Should have thrown 405!';
} on AngelHttpException { } on AngelHttpException {
// print('Ok!'); // print('Ok!');
} }
try { try {
var svc = new AnonymousService(); var svc = AnonymousService();
await svc.modify(2, null); await svc.modify(2, null);
throw 'Should have thrown 405!'; throw 'Should have thrown 405!';
} on AngelHttpException { } on AngelHttpException {
// print('Ok!'); // print('Ok!');
} }
try { try {
var svc = new AnonymousService(); var svc = AnonymousService();
await svc.update(3, null); await svc.update(3, null);
throw 'Should have thrown 405!'; throw 'Should have thrown 405!';
} on AngelHttpException { } on AngelHttpException {

View file

@ -32,12 +32,12 @@ incrementTodoTimes(e) {
IncrementService.TIMES++; IncrementService.TIMES++;
} }
@Hooks(before: const [incrementTodoTimes]) @Hooks(before: [incrementTodoTimes])
class IncrementService extends Service { class IncrementService extends Service {
static int TIMES = 0; static int TIMES = 0;
@override @override
@Hooks(after: const [incrementTodoTimes]) @Hooks(after: [incrementTodoTimes])
index([params]) async => []; index([params]) async => [];
} }

View file

@ -13,7 +13,7 @@ import 'common.dart';
@Expose("/todos", middleware: [foo]) @Expose("/todos", middleware: [foo])
class TodoController extends Controller { class TodoController extends Controller {
List<Todo> todos = [new Todo(text: "Hello", over: "world")]; List<Todo> todos = [Todo(text: "Hello", over: "world")];
@Expose("/:id", middleware: [bar]) @Expose("/:id", middleware: [bar])
Future<Todo> fetchTodo( Future<Todo> fetchTodo(
@ -34,7 +34,7 @@ class NoExposeController extends Controller {}
@Expose('/named', as: 'foo') @Expose('/named', as: 'foo')
class NamedController extends Controller { class NamedController extends Controller {
@Expose('/optional/:arg?', allowNull: const ['arg']) @Expose('/optional/:arg?', allowNull: ['arg'])
optional() => 2; optional() => 2;
} }
@ -52,11 +52,11 @@ main() {
Angel app; Angel app;
TodoController ctrl; TodoController ctrl;
HttpServer server; HttpServer server;
http.Client client = new http.Client(); http.Client client = http.Client();
String url; String url;
setUp(() async { setUp(() async {
app = new Angel(reflector: MirrorsReflector()); app = Angel(reflector: MirrorsReflector());
app.get( app.get(
"/redirect", "/redirect",
(req, res) async => (req, res) async =>
@ -64,7 +64,7 @@ main() {
// Register as a singleton, just for the purpose of this test // Register as a singleton, just for the purpose of this test
if (!app.container.has<TodoController>()) if (!app.container.has<TodoController>())
app.container.registerSingleton(ctrl = new TodoController()); app.container.registerSingleton(ctrl = TodoController());
// Using mountController<T>(); // Using mountController<T>();
await app.mountController<TodoController>(); await app.mountController<TodoController>();
@ -72,7 +72,7 @@ main() {
print(app.controllers); print(app.controllers);
app.dumpTree(); app.dumpTree();
server = await new AngelHttp(app).startServer(); server = await AngelHttp(app).startServer();
url = 'http://${server.address.address}:${server.port}'; url = 'http://${server.address.address}:${server.port}';
}); });
@ -88,8 +88,8 @@ main() {
test('require expose', () async { test('require expose', () async {
try { try {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
await app.configure(new NoExposeController().configureServer); await app.configure(NoExposeController().configureServer);
throw 'Should require @Expose'; throw 'Should require @Expose';
} on Exception { } on Exception {
// :) // :)
@ -97,26 +97,26 @@ main() {
}); });
test('create dynamic handler', () async { test('create dynamic handler', () async {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
app.get( app.get(
'/foo', '/foo',
ioc(({String bar}) { ioc(({String bar}) {
return 2; return 2;
}, optional: ['bar'])); }, optional: ['bar']));
var rq = new MockHttpRequest('GET', new Uri(path: 'foo')); var rq = MockHttpRequest('GET', Uri(path: 'foo'));
await new AngelHttp(app).handleRequest(rq); await AngelHttp(app).handleRequest(rq);
var body = await rq.response.transform(utf8.decoder).join(); var body = await rq.response.transform(utf8.decoder).join();
expect(json.decode(body), 2); expect(json.decode(body), 2);
}); });
test('optional name', () async { test('optional name', () async {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
await app.configure(new NamedController().configureServer); await app.configure(NamedController().configureServer);
expect(app.controllers['foo'], const IsInstanceOf<NamedController>()); expect(app.controllers['foo'], const IsInstanceOf<NamedController>());
}); });
test("middleware", () async { test("middleware", () async {
var rgx = new RegExp("^Hello, world!"); var rgx = RegExp("^Hello, world!");
var response = await client.get("$url/todos/0"); var response = await client.get("$url/todos/0");
print('Response: ${response.body}'); print('Response: ${response.body}');

View file

@ -8,8 +8,8 @@ void main() {
AngelHttp http; AngelHttp http;
setUp(() async { setUp(() async {
var app = new Angel(); var app = Angel();
http = new AngelHttp(app); http = AngelHttp(app);
app.get('/detach', (req, res) async { app.get('/detach', (req, res) async {
if (res is HttpResponseContext) { if (res is HttpResponseContext) {
@ -17,7 +17,7 @@ void main() {
io..write('Hey!'); io..write('Hey!');
await io.close(); await io.close();
} else { } else {
throw new StateError('This endpoint only supports HTTP/1.1.'); throw StateError('This endpoint only supports HTTP/1.1.');
} }
}); });
}); });
@ -25,7 +25,7 @@ void main() {
tearDown(() => http.close()); tearDown(() => http.close());
test('detach response', () async { test('detach response', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/detach')); var rq = MockHttpRequest('GET', Uri.parse('/detach'));
await rq.close(); await rq.close();
var rs = rq.response; var rs = rq.response;
await http.handleRequest(rq); await http.handleRequest(rq);

View file

@ -21,11 +21,11 @@ main() {
String url; String url;
setUp(() async { setUp(() async {
app = new Angel(reflector: MirrorsReflector()); app = Angel(reflector: MirrorsReflector());
client = new http.Client(); client = http.Client();
// Inject some todos // Inject some todos
app.container.registerSingleton(new Todo(text: TEXT, over: OVER)); app.container.registerSingleton(Todo(text: TEXT, over: OVER));
app.container.registerFactory<Future<Foo>>((container) async { app.container.registerFactory<Future<Foo>>((container) async {
var req = container.make<RequestContext>(); var req = container.make<RequestContext>();
var text = await req.body.transform(utf8.decoder).join(); var text = await req.body.transform(utf8.decoder).join();
@ -38,10 +38,10 @@ main() {
ioc(({Errand singleton, Todo foo, RequestContext req}) => ioc(({Errand singleton, Todo foo, RequestContext req}) =>
singleton.text)); singleton.text));
app.post('/async', ioc((Foo foo) => {'baz': foo.bar})); app.post('/async', ioc((Foo foo) => {'baz': foo.bar}));
await app.configure(new SingletonController().configureServer); await app.configure(SingletonController().configureServer);
await app.configure(new ErrandController().configureServer); await app.configure(ErrandController().configureServer);
server = await new AngelHttp(app).startServer(); server = await AngelHttp(app).startServer();
url = "http://${server.address.host}:${server.port}"; url = "http://${server.address.host}:${server.port}";
}); });
@ -54,18 +54,18 @@ main() {
}); });
test('runContained with custom container', () async { test('runContained with custom container', () async {
var app = new Angel(); var app = Angel();
var c = new Container(const MirrorsReflector()); var c = Container(const MirrorsReflector());
c.registerSingleton(new Todo(text: 'Hey!')); c.registerSingleton(Todo(text: 'Hey!'));
app.get('/', (req, res) async { app.get('/', (req, res) async {
return app.runContained((Todo t) => t.text, req, res, c); return app.runContained((Todo t) => t.text, req, res, c);
}); });
var rq = new MockHttpRequest('GET', new Uri(path: '/')); var rq = MockHttpRequest('GET', Uri(path: '/'));
await rq.close(); await rq.close();
var rs = rq.response; var rs = rq.response;
await new AngelHttp(app).handleRequest(rq); await AngelHttp(app).handleRequest(rq);
var text = await rs.transform(utf8.decoder).join(); var text = await rs.transform(utf8.decoder).join();
expect(text, json.encode('Hey!')); expect(text, json.encode('Hey!'));
}); });

View file

@ -11,7 +11,7 @@ import 'package:test/test.dart';
Future<List<int>> getBody(MockHttpResponse rs) async { Future<List<int>> getBody(MockHttpResponse rs) async {
var list = await rs.toList(); var list = await rs.toList();
var bb = new BytesBuilder(); var bb = BytesBuilder();
list.forEach(bb.add); list.forEach(bb.add);
return bb.takeBytes(); return bb.takeBytes();
} }
@ -20,7 +20,7 @@ main() {
Angel app; Angel app;
setUp(() { setUp(() {
app = new Angel(reflector: MirrorsReflector()); app = Angel(reflector: MirrorsReflector());
app.encoders.addAll( app.encoders.addAll(
{ {
'deflate': zlib.encoder, 'deflate': zlib.encoder,
@ -47,11 +47,11 @@ void encodingTests(Angel getApp()) {
setUp(() { setUp(() {
app = getApp(); app = getApp();
http = new AngelHttp(app); http = AngelHttp(app);
}); });
test('sends plaintext if no accept-encoding', () async { test('sends plaintext if no accept-encoding', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/hello')); var rq = MockHttpRequest('GET', Uri.parse('/hello'));
await rq.close(); await rq.close();
var rs = rq.response; var rs = rq.response;
await http.handleRequest(rq); await http.handleRequest(rq);
@ -61,7 +61,7 @@ void encodingTests(Angel getApp()) {
}); });
test('encodes if wildcard', () async { test('encodes if wildcard', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/hello')) var rq = MockHttpRequest('GET', Uri.parse('/hello'))
..headers.set('accept-encoding', '*'); ..headers.set('accept-encoding', '*');
await rq.close(); await rq.close();
var rs = rq.response; var rs = rq.response;
@ -74,7 +74,7 @@ void encodingTests(Angel getApp()) {
}); });
test('encodes if wildcard + multiple', () async { test('encodes if wildcard + multiple', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/hello')) var rq = MockHttpRequest('GET', Uri.parse('/hello'))
..headers.set('accept-encoding', ['foo', 'bar', '*']); ..headers.set('accept-encoding', ['foo', 'bar', '*']);
await rq.close(); await rq.close();
var rs = rq.response; var rs = rq.response;
@ -86,7 +86,7 @@ void encodingTests(Angel getApp()) {
}); });
test('encodes if explicit', () async { test('encodes if explicit', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/hello')) var rq = MockHttpRequest('GET', Uri.parse('/hello'))
..headers.set('accept-encoding', 'gzip'); ..headers.set('accept-encoding', 'gzip');
await rq.close(); await rq.close();
var rs = rq.response; var rs = rq.response;
@ -98,7 +98,7 @@ void encodingTests(Angel getApp()) {
}); });
test('only uses one encoder', () async { test('only uses one encoder', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/hello')) var rq = MockHttpRequest('GET', Uri.parse('/hello'))
..headers.set('accept-encoding', ['gzip', 'deflate']); ..headers.set('accept-encoding', ['gzip', 'deflate']);
await rq.close(); await rq.close();
var rs = rq.response; var rs = rq.response;

View file

@ -5,54 +5,51 @@ import 'package:test/test.dart';
main() { main() {
test('named constructors', () { test('named constructors', () {
expect(new AngelHttpException.badRequest(), expect(
isException(400, '400 Bad Request')); AngelHttpException.badRequest(), isException(400, '400 Bad Request'));
expect(new AngelHttpException.notAuthenticated(), expect(AngelHttpException.notAuthenticated(),
isException(401, '401 Not Authenticated')); isException(401, '401 Not Authenticated'));
expect(new AngelHttpException.paymentRequired(), expect(AngelHttpException.paymentRequired(),
isException(402, '402 Payment Required')); isException(402, '402 Payment Required'));
expect( expect(AngelHttpException.forbidden(), isException(403, '403 Forbidden'));
new AngelHttpException.forbidden(), isException(403, '403 Forbidden')); expect(AngelHttpException.notFound(), isException(404, '404 Not Found'));
expect( expect(AngelHttpException.methodNotAllowed(),
new AngelHttpException.notFound(), isException(404, '404 Not Found'));
expect(new AngelHttpException.methodNotAllowed(),
isException(405, '405 Method Not Allowed')); isException(405, '405 Method Not Allowed'));
expect(new AngelHttpException.notAcceptable(), expect(AngelHttpException.notAcceptable(),
isException(406, '406 Not Acceptable')); isException(406, '406 Not Acceptable'));
expect(new AngelHttpException.methodTimeout(), expect(AngelHttpException.methodTimeout(), isException(408, '408 Timeout'));
isException(408, '408 Timeout')); expect(AngelHttpException.conflict(), isException(409, '409 Conflict'));
expect(new AngelHttpException.conflict(), isException(409, '409 Conflict')); expect(AngelHttpException.notProcessable(),
expect(new AngelHttpException.notProcessable(),
isException(422, '422 Not Processable')); isException(422, '422 Not Processable'));
expect(new AngelHttpException.notImplemented(), expect(AngelHttpException.notImplemented(),
isException(501, '501 Not Implemented')); isException(501, '501 Not Implemented'));
expect(new AngelHttpException.unavailable(), expect(
isException(503, '503 Unavailable')); AngelHttpException.unavailable(), isException(503, '503 Unavailable'));
}); });
test('fromMap', () { test('fromMap', () {
expect(new AngelHttpException.fromMap({'status_code': -1, 'message': 'ok'}), expect(AngelHttpException.fromMap({'status_code': -1, 'message': 'ok'}),
isException(-1, 'ok')); isException(-1, 'ok'));
}); });
test('toMap = toJson', () { test('toMap = toJson', () {
var exc = new AngelHttpException.badRequest(); var exc = AngelHttpException.badRequest();
expect(exc.toMap(), exc.toJson()); expect(exc.toMap(), exc.toJson());
var json_ = json.encode(exc.toJson()); var json_ = json.encode(exc.toJson());
var exc2 = new AngelHttpException.fromJson(json_); var exc2 = AngelHttpException.fromJson(json_);
expect(exc2.toJson(), exc.toJson()); expect(exc2.toJson(), exc.toJson());
}); });
test('toString', () { test('toString', () {
expect( expect(
new AngelHttpException(null, statusCode: 420, message: 'Blaze It') AngelHttpException(null, statusCode: 420, message: 'Blaze It')
.toString(), .toString(),
'420: Blaze It'); '420: Blaze It');
}); });
} }
Matcher isException(int statusCode, String message) => Matcher isException(int statusCode, String message) =>
new _IsException(statusCode, message); _IsException(statusCode, message);
class _IsException extends Matcher { class _IsException extends Matcher {
final int statusCode; final int statusCode;

View file

@ -25,8 +25,8 @@ main() {
} }
Future<RequestContext> makeRequest(String path) { Future<RequestContext> makeRequest(String path) {
var rq = new MockHttpRequest('GET', ENDPOINT.replace(path: path))..close(); var rq = MockHttpRequest('GET', ENDPOINT.replace(path: path))..close();
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
var http = new AngelHttp(app); var http = AngelHttp(app);
return http.createRequestContext(rq, rq.response); return http.createRequestContext(rq, rq.response);
} }

View file

@ -7,17 +7,17 @@ void main() {
throwsA(const IsInstanceOf<AngelHttpException>()); throwsA(const IsInstanceOf<AngelHttpException>());
test('throw 404 on null', () { test('throw 404 on null', () {
var service = new AnonymousService(index: ([p]) => null); var service = AnonymousService(index: ([p]) => null);
expect(() => service.findOne(), throwsAnAngelHttpException); expect(() => service.findOne(), throwsAnAngelHttpException);
}); });
test('throw 404 on empty iterable', () { test('throw 404 on empty iterable', () {
var service = new AnonymousService(index: ([p]) => []); var service = AnonymousService(index: ([p]) => []);
expect(() => service.findOne(), throwsAnAngelHttpException); expect(() => service.findOne(), throwsAnAngelHttpException);
}); });
test('return first element of iterable', () async { test('return first element of iterable', () async {
var service = new AnonymousService(index: ([p]) => [2]); var service = AnonymousService(index: ([p]) => [2]);
expect(await service.findOne(), 2); expect(await service.findOne(), 2);
}); });
} }

View file

@ -13,12 +13,12 @@ main() {
String url; String url;
setUp(() async { setUp(() async {
app = new Angel(reflector: MirrorsReflector()) app = Angel(reflector: MirrorsReflector())
..post('/foo', (req, res) => res.serialize({'hello': 'world'})) ..post('/foo', (req, res) => res.serialize({'hello': 'world'}))
..all('*', (req, res) => throw new AngelHttpException.notFound()); ..all('*', (req, res) => throw AngelHttpException.notFound());
client = new http.Client(); client = http.Client();
server = await new AngelHttp(app).startServer(); server = await AngelHttp(app).startServer();
url = "http://${server.address.host}:${server.port}"; url = "http://${server.address.host}:${server.port}";
}); });

View file

@ -4,7 +4,7 @@ import 'all.dart' as hm;
main() async { main() async {
var zone = Zone.current.fork( var zone = Zone.current.fork(
specification: new ZoneSpecification(print: (self, parent, zone, line) { specification: ZoneSpecification(print: (self, parent, zone, line) {
if (line == 'null') { if (line == 'null') {
parent.print(zone, cyan.wrap(StackTrace.current.toString())); parent.print(zone, cyan.wrap(StackTrace.current.toString()));
} }

View file

@ -20,10 +20,10 @@ main() {
HookedService todoService; HookedService todoService;
setUp(() async { setUp(() async {
app = new Angel(reflector: MirrorsReflector()); app = Angel(reflector: MirrorsReflector());
client = new http.Client(); client = http.Client();
app.use('/todos', new MapService()); app.use('/todos', MapService());
app.use('/books', new BookService()); app.use('/books', BookService());
todoService = app.findHookedService<MapService>('todos'); todoService = app.findHookedService<MapService>('todos');
@ -35,7 +35,7 @@ main() {
throw e.error; throw e.error;
}; };
server = await new AngelHttp(app).startServer(); server = await AngelHttp(app).startServer();
url = "http://${server.address.host}:${server.port}"; url = "http://${server.address.host}:${server.port}";
}); });
@ -106,7 +106,7 @@ main() {
}); });
test('metadata', () async { test('metadata', () async {
final service = new HookedService(new IncrementService())..addHooks(app); final service = HookedService(IncrementService())..addHooks(app);
expect(service.inner, isNot(const IsInstanceOf<MapService>())); expect(service.inner, isNot(const IsInstanceOf<MapService>()));
IncrementService.TIMES = 0; IncrementService.TIMES = 0;
await service.index(); await service.index();
@ -131,7 +131,7 @@ main() {
}); });
test('contains provider in before and after', () async { test('contains provider in before and after', () async {
var svc = new HookedService(new AnonymousService(index: ([p]) async => [])); var svc = HookedService(AnonymousService(index: ([p]) async => []));
ensureProviderIsPresent(HookedServiceEvent e) { ensureProviderIsPresent(HookedServiceEvent e) {
var type = e.isBefore ? 'before' : 'after'; var type = e.isBefore ? 'before' : 'after';

View file

@ -17,18 +17,17 @@ const String jfk =
'Ask not what your country can do for you, but what you can do for your country.'; 'Ask not what your country can do for you, but what you can do for your country.';
Stream<List<int>> jfkStream() { Stream<List<int>> jfkStream() {
return new Stream.fromIterable([utf8.encode(jfk)]); return Stream.fromIterable([utf8.encode(jfk)]);
} }
void main() { void main() {
var client = new Http2Client(); var client = Http2Client();
Angel app; Angel app;
AngelHttp2 http2; AngelHttp2 http2;
Uri serverRoot; Uri serverRoot;
setUp(() async { setUp(() async {
app = new Angel(reflector: MirrorsReflector()) app = Angel(reflector: MirrorsReflector())..encoders['gzip'] = gzip.encoder;
..encoders['gzip'] = gzip.encoder;
hierarchicalLoggingEnabled = true; hierarchicalLoggingEnabled = true;
app.logger = Logger.detached('angel.http2') app.logger = Logger.detached('angel.http2')
..onRecord.listen((rec) { ..onRecord.listen((rec) {
@ -93,12 +92,12 @@ void main() {
return req.queryParameters; return req.queryParameters;
}); });
var ctx = new SecurityContext() var ctx = SecurityContext()
..useCertificateChain('dev.pem') ..useCertificateChain('dev.pem')
..usePrivateKey('dev.key', password: 'dartdart') ..usePrivateKey('dev.key', password: 'dartdart')
..setAlpnProtocols(['h2'], true); ..setAlpnProtocols(['h2'], true);
http2 = new AngelHttp2(app, ctx); http2 = AngelHttp2(app, ctx);
var server = await http2.startServer(); var server = await http2.startServer();
serverRoot = Uri.parse('https://127.0.0.1:${server.port}'); serverRoot = Uri.parse('https://127.0.0.1:${server.port}');
@ -181,16 +180,16 @@ void main() {
supportedProtocols: ['h2'], supportedProtocols: ['h2'],
); );
var connection = new ClientTransportConnection.viaSocket( var connection = ClientTransportConnection.viaSocket(
socket, socket,
settings: new ClientSettings(allowServerPushes: true), settings: ClientSettings(allowServerPushes: true),
); );
var headers = <Header>[ var headers = <Header>[
new Header.ascii(':authority', serverRoot.authority), Header.ascii(':authority', serverRoot.authority),
new Header.ascii(':method', 'GET'), Header.ascii(':method', 'GET'),
new Header.ascii(':path', serverRoot.replace(path: '/push').path), Header.ascii(':path', serverRoot.replace(path: '/push').path),
new Header.ascii(':scheme', serverRoot.scheme), Header.ascii(':scheme', serverRoot.scheme),
]; ];
var stream = await connection.makeRequest(headers, endStream: true); var stream = await connection.makeRequest(headers, endStream: true);
@ -198,8 +197,7 @@ void main() {
var bb = await stream.incomingMessages var bb = await stream.incomingMessages
.where((s) => s is DataStreamMessage) .where((s) => s is DataStreamMessage)
.cast<DataStreamMessage>() .cast<DataStreamMessage>()
.fold<BytesBuilder>( .fold<BytesBuilder>(BytesBuilder(), (out, msg) => out..add(msg.bytes));
new BytesBuilder(), (out, msg) => out..add(msg.bytes));
// Check that main body was sent // Check that main body was sent
expect(utf8.decode(bb.takeBytes()), 'ok'); expect(utf8.decode(bb.takeBytes()), 'ok');
@ -231,7 +229,7 @@ void main() {
.where((s) => s is DataStreamMessage) .where((s) => s is DataStreamMessage)
.cast<DataStreamMessage>() .cast<DataStreamMessage>()
.fold<BytesBuilder>( .fold<BytesBuilder>(
new BytesBuilder(), (out, msg) => out..add(msg.bytes)); BytesBuilder(), (out, msg) => out..add(msg.bytes));
return UTF8.decode(bb.takeBytes()); return UTF8.decode(bb.takeBytes());
} }
*/ */
@ -268,14 +266,14 @@ void main() {
}); });
test('multipart body parsed', () async { test('multipart body parsed', () async {
var rq = new http.MultipartRequest( var rq =
'POST', serverRoot.replace(path: '/upload')); http.MultipartRequest('POST', serverRoot.replace(path: '/upload'));
rq.headers.addAll({'accept': 'application/json'}); rq.headers.addAll({'accept': 'application/json'});
rq.fields['foo'] = 'bar'; rq.fields['foo'] = 'bar';
rq.files.add(new http.MultipartFile( rq.files.add(http.MultipartFile(
'file', new Stream.fromIterable([utf8.encode('hello world')]), 11, 'file', Stream.fromIterable([utf8.encode('hello world')]), 11,
contentType: new MediaType('angel', 'framework'))); contentType: MediaType('angel', 'framework')));
var response = await client.send(rq); var response = await client.send(rq);
var responseBody = await response.stream.transform(utf8.decoder).join(); var responseBody = await response.stream.transform(utf8.decoder).join();

View file

@ -17,29 +17,29 @@ class Http2Client extends BaseClient {
supportedProtocols: ['h2'], supportedProtocols: ['h2'],
); );
var connection = new ClientTransportConnection.viaSocket(socket); var connection = ClientTransportConnection.viaSocket(socket);
var headers = <Header>[ var headers = <Header>[
new Header.ascii(':authority', request.url.authority), Header.ascii(':authority', request.url.authority),
new Header.ascii(':method', request.method), Header.ascii(':method', request.method),
new Header.ascii( Header.ascii(
':path', ':path',
request.url.path + request.url.path +
(request.url.hasQuery ? ('?' + request.url.query) : '')), (request.url.hasQuery ? ('?' + request.url.query) : '')),
new Header.ascii(':scheme', request.url.scheme), Header.ascii(':scheme', request.url.scheme),
]; ];
var bb = await request var bb = await request
.finalize() .finalize()
.fold<BytesBuilder>(new BytesBuilder(), (out, list) => out..add(list)); .fold<BytesBuilder>(BytesBuilder(), (out, list) => out..add(list));
var body = bb.takeBytes(); var body = bb.takeBytes();
if (body.isNotEmpty) { if (body.isNotEmpty) {
headers.add(new Header.ascii('content-length', body.length.toString())); headers.add(Header.ascii('content-length', body.length.toString()));
} }
request.headers.forEach((k, v) { request.headers.forEach((k, v) {
headers.add(new Header.ascii(k, v)); headers.add(Header.ascii(k, v));
}); });
var stream = await connection.makeRequest(headers, endStream: body.isEmpty); var stream = await connection.makeRequest(headers, endStream: body.isEmpty);
@ -56,7 +56,7 @@ class Http2Client extends BaseClient {
/// Returns `true` if the response stream was closed. /// Returns `true` if the response stream was closed.
static Future<bool> readResponse(ClientTransportStream stream, static Future<bool> readResponse(ClientTransportStream stream,
Map<String, String> headers, BytesBuilder body) { Map<String, String> headers, BytesBuilder body) {
var c = new Completer<bool>(); var c = Completer<bool>();
var closed = false; var closed = false;
stream.incomingMessages.listen( stream.incomingMessages.listen(
@ -86,10 +86,10 @@ class Http2Client extends BaseClient {
Future<StreamedResponse> send(BaseRequest request) async { Future<StreamedResponse> send(BaseRequest request) async {
var stream = await convertRequestToStream(request); var stream = await convertRequestToStream(request);
var headers = <String, String>{}; var headers = <String, String>{};
var body = new BytesBuilder(); var body = BytesBuilder();
var closed = await readResponse(stream, headers, body); var closed = await readResponse(stream, headers, body);
return new StreamedResponse( return StreamedResponse(
new Stream.fromIterable([body.takeBytes()]), Stream.fromIterable([body.takeBytes()]),
int.parse(headers[':status']), int.parse(headers[':status']),
headers: headers, headers: headers,
isRedirect: headers.containsKey('location'), isRedirect: headers.containsKey('location'),

View file

@ -27,8 +27,8 @@ parameterMetaTests() {
AngelHttp http; AngelHttp http;
setUp(() { setUp(() {
app = new Angel(reflector: MirrorsReflector()); app = Angel(reflector: MirrorsReflector());
http = new AngelHttp(app); http = AngelHttp(app);
app.get('/cookie', ioc((@CookieValue('token') String jwt) { app.get('/cookie', ioc((@CookieValue('token') String jwt) {
return jwt; return jwt;
@ -58,7 +58,7 @@ parameterMetaTests() {
return 'DEFAULT $mode'; return 'DEFAULT $mode';
})); }));
/*app.logger = new Logger('parameter_meta_test') /*app.logger = Logger('parameter_meta_test')
..onRecord.listen((rec) { ..onRecord.listen((rec) {
print(rec); print(rec);
if (rec.error != null) print(rec.error); if (rec.error != null) print(rec.error);
@ -69,7 +69,7 @@ parameterMetaTests() {
test('injects header or throws', () async { test('injects header or throws', () async {
// Invalid request // Invalid request
var rq = new MockHttpRequest('GET', Uri.parse('/header')); var rq = MockHttpRequest('GET', Uri.parse('/header'));
unawaited(rq.close()); unawaited(rq.close());
var rs = rq.response; var rs = rq.response;
unawaited(http.handleRequest(rq)); unawaited(http.handleRequest(rq));
@ -78,7 +78,7 @@ parameterMetaTests() {
expect(rs.statusCode, 400); expect(rs.statusCode, 400);
// Valid request // Valid request
rq = new MockHttpRequest('GET', Uri.parse('/header')) rq = MockHttpRequest('GET', Uri.parse('/header'))
..headers.add('x-foo', 'bar'); ..headers.add('x-foo', 'bar');
unawaited(rq.close()); unawaited(rq.close());
rs = rq.response; rs = rq.response;
@ -92,7 +92,7 @@ parameterMetaTests() {
test('injects session or throws', () async { test('injects session or throws', () async {
// Invalid request // Invalid request
var rq = new MockHttpRequest('GET', Uri.parse('/session')); var rq = MockHttpRequest('GET', Uri.parse('/session'));
unawaited(rq.close()); unawaited(rq.close());
var rs = rq.response; var rs = rq.response;
unawaited(http unawaited(http
@ -103,7 +103,7 @@ parameterMetaTests() {
await printResponse(rs); await printResponse(rs);
expect(rs.statusCode, 500); expect(rs.statusCode, 500);
rq = new MockHttpRequest('GET', Uri.parse('/session')); rq = MockHttpRequest('GET', Uri.parse('/session'));
rq.session['foo'] = 'bar'; rq.session['foo'] = 'bar';
unawaited(rq.close()); unawaited(rq.close());
rs = rq.response; rs = rq.response;
@ -118,7 +118,7 @@ parameterMetaTests() {
// they will all function the same way. // they will all function the same way.
test('pattern matching', () async { test('pattern matching', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/match?mode=pos')); var rq = MockHttpRequest('GET', Uri.parse('/match?mode=pos'));
unawaited(rq.close()); unawaited(rq.close());
var rs = rq.response; var rs = rq.response;
unawaited(http.handleRequest(rq)); unawaited(http.handleRequest(rq));
@ -127,7 +127,7 @@ parameterMetaTests() {
expect(rs.statusCode, 200); expect(rs.statusCode, 200);
expect(body, json.encode('YES pos')); expect(body, json.encode('YES pos'));
rq = new MockHttpRequest('GET', Uri.parse('/match?mode=neg')); rq = MockHttpRequest('GET', Uri.parse('/match?mode=neg'));
unawaited(rq.close()); unawaited(rq.close());
rs = rq.response; rs = rq.response;
unawaited(http.handleRequest(rq)); unawaited(http.handleRequest(rq));
@ -137,7 +137,7 @@ parameterMetaTests() {
expect(body, json.encode('NO neg')); expect(body, json.encode('NO neg'));
// Fallback // Fallback
rq = new MockHttpRequest('GET', Uri.parse('/match?mode=ambi')); rq = MockHttpRequest('GET', Uri.parse('/match?mode=ambi'));
unawaited(rq.close()); unawaited(rq.close());
rs = rq.response; rs = rq.response;
unawaited(http.handleRequest(rq)); unawaited(http.handleRequest(rq));

View file

@ -9,16 +9,16 @@ import 'package:test/test.dart';
main() { main() {
test('preinjects functions', () async { test('preinjects functions', () async {
var app = new Angel(reflector: MirrorsReflector()) var app = Angel(reflector: MirrorsReflector())
..configuration['foo'] = 'bar' ..configuration['foo'] = 'bar'
..get('/foo', ioc(echoAppFoo)); ..get('/foo', ioc(echoAppFoo));
app.optimizeForProduction(force: true); app.optimizeForProduction(force: true);
print(app.preContained); print(app.preContained);
expect(app.preContained.keys, contains(echoAppFoo)); expect(app.preContained.keys, contains(echoAppFoo));
var rq = new MockHttpRequest('GET', new Uri(path: '/foo')); var rq = MockHttpRequest('GET', Uri(path: '/foo'));
unawaited(rq.close()); unawaited(rq.close());
await new AngelHttp(app).handleRequest(rq); await AngelHttp(app).handleRequest(rq);
var rs = rq.response; var rs = rq.response;
var body = await rs.transform(utf8.decoder).join(); var body = await rs.transform(utf8.decoder).join();
expect(body, json.encode('bar')); expect(body, json.encode('bar'));

View file

@ -13,9 +13,9 @@ main() {
AngelHttp http; AngelHttp http;
setUp(() { setUp(() {
app = new Angel(reflector: MirrorsReflector()) app = Angel(reflector: MirrorsReflector())
..configuration['global'] = 305; // Pitbull! ..configuration['global'] = 305; // Pitbull!
http = new AngelHttp(app); http = AngelHttp(app);
app.get('/string/:string', ioc((String string) => string)); app.get('/string/:string', ioc((String string) => string));
@ -39,7 +39,7 @@ main() {
tearDown(() => app.close()); tearDown(() => app.close());
test('String type annotation', () async { test('String type annotation', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/string/hello')); var rq = MockHttpRequest('GET', Uri.parse('/string/hello'));
unawaited(rq.close()); unawaited(rq.close());
await http.handleRequest(rq); await http.handleRequest(rq);
var rs = await rq.response.transform(utf8.decoder).join(); var rs = await rq.response.transform(utf8.decoder).join();
@ -47,7 +47,7 @@ main() {
}); });
test('Primitive after parsed param injection', () async { test('Primitive after parsed param injection', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/num/parsed/24')); var rq = MockHttpRequest('GET', Uri.parse('/num/parsed/24'));
unawaited(rq.close()); unawaited(rq.close());
await http.handleRequest(rq); await http.handleRequest(rq);
var rs = await rq.response.transform(utf8.decoder).join(); var rs = await rq.response.transform(utf8.decoder).join();
@ -55,7 +55,7 @@ main() {
}); });
test('globally-injected primitive', () async { test('globally-injected primitive', () async {
var rq = new MockHttpRequest('GET', Uri.parse('/num/global')); var rq = MockHttpRequest('GET', Uri.parse('/num/global'));
unawaited(rq.close()); unawaited(rq.close());
await http.handleRequest(rq); await http.handleRequest(rq);
var rs = await rq.response.transform(utf8.decoder).join(); var rs = await rq.response.transform(utf8.decoder).join();
@ -64,12 +64,12 @@ main() {
test('unparsed primitive throws error', () async { test('unparsed primitive throws error', () async {
try { try {
var rq = new MockHttpRequest('GET', Uri.parse('/num/unparsed/32')); var rq = MockHttpRequest('GET', Uri.parse('/num/unparsed/32'));
unawaited(rq.close()); unawaited(rq.close());
var req = await http.createRequestContext(rq, rq.response); var req = await http.createRequestContext(rq, rq.response);
var res = await http.createResponseContext(rq, rq.response, req); var res = await http.createResponseContext(rq, rq.response, req);
await app.runContained((num unparsed) => unparsed, req, res); await app.runContained((num unparsed) => unparsed, req, res);
throw new StateError( throw StateError(
'ArgumentError should be thrown if a parameter cannot be resolved.'); 'ArgumentError should be thrown if a parameter cannot be resolved.');
} on ArgumentError { } on ArgumentError {
// Success // Success

View file

@ -9,14 +9,14 @@ import 'package:test/test.dart';
main() { main() {
MockHttpRequest mk(int id) { MockHttpRequest mk(int id) {
return new MockHttpRequest('GET', Uri.parse('/test/$id'))..close(); return MockHttpRequest('GET', Uri.parse('/test/$id'))..close();
} }
test('can request the same url twice', () async { test('can request the same url twice', () async {
var app = new Angel(reflector: MirrorsReflector()) var app = Angel(reflector: MirrorsReflector())
..get('/test/:id', ioc((id) => 'Hello $id')); ..get('/test/:id', ioc((id) => 'Hello $id'));
var rq1 = mk(1), rq2 = mk(2), rq3 = mk(1); var rq1 = mk(1), rq2 = mk(2), rq3 = mk(1);
await Future.wait([rq1, rq2, rq3].map(new AngelHttp(app).handleRequest)); await Future.wait([rq1, rq2, rq3].map(AngelHttp(app).handleRequest));
var body1 = await rq1.response.transform(utf8.decoder).join(), var body1 = await rq1.response.transform(utf8.decoder).join(),
body2 = await rq2.response.transform(utf8.decoder).join(), body2 = await rq2.response.transform(utf8.decoder).join(),
body3 = await rq3.response.transform(utf8.decoder).join(); body3 = await rq3.response.transform(utf8.decoder).join();

View file

@ -42,12 +42,12 @@ main() {
http.Client client; http.Client client;
setUp(() async { setUp(() async {
app = new Angel(reflector: MirrorsReflector()); app = Angel(reflector: MirrorsReflector());
nested = new Angel(reflector: MirrorsReflector()); nested = Angel(reflector: MirrorsReflector());
todos = new Angel(reflector: MirrorsReflector()); todos = Angel(reflector: MirrorsReflector());
[app, nested, todos].forEach((Angel app) { [app, nested, todos].forEach((Angel app) {
app.logger = new Logger('routing_test') app.logger = Logger('routing_test')
..onRecord.listen((rec) { ..onRecord.listen((rec) {
if (rec.error != null) { if (rec.error != null) {
stdout stdout
@ -95,7 +95,7 @@ main() {
app.get('/method', (req, res) => 'Only GET'); app.get('/method', (req, res) => 'Only GET');
app.post('/method', (req, res) => 'Only POST'); app.post('/method', (req, res) => 'Only POST');
app.use('/query', new QueryService()); app.use('/query', QueryService());
RequestHandler write(String message) { RequestHandler write(String message) {
return (req, res) { return (req, res) {
@ -111,8 +111,8 @@ main() {
//app.dumpTree(header: "DUMPING ROUTES:", showMatchers: true); //app.dumpTree(header: "DUMPING ROUTES:", showMatchers: true);
client = new http.Client(); client = http.Client();
var server = await new AngelHttp(app).startServer('127.0.0.1', 0); var server = await AngelHttp(app).startServer('127.0.0.1', 0);
url = "http://${server.address.host}:${server.port}"; url = "http://${server.address.host}:${server.port}";
}); });

View file

@ -14,15 +14,15 @@ main() {
String url; String url;
setUp(() async { setUp(() async {
app = new Angel(reflector: MirrorsReflector()) app = Angel(reflector: MirrorsReflector())
..get('/foo', ioc(() => {'hello': 'world'})) ..get('/foo', ioc(() => {'hello': 'world'}))
..get('/bar', (req, res) async { ..get('/bar', (req, res) async {
await res.serialize({'hello': 'world'}, await res.serialize({'hello': 'world'},
contentType: new MediaType('text', 'html')); contentType: MediaType('text', 'html'));
}); });
client = new http.Client(); client = http.Client();
server = await new AngelHttp(app).startServer(); server = await AngelHttp(app).startServer();
url = "http://${server.address.host}:${server.port}"; url = "http://${server.address.host}:${server.port}";
}); });

View file

@ -15,9 +15,8 @@ final Uri $foo = Uri.parse('http://localhost:3000/foo');
/// Additional tests to improve coverage of server.dart /// Additional tests to improve coverage of server.dart
main() { main() {
group('scoping', () { group('scoping', () {
var parent = new Angel(reflector: MirrorsReflector()) var parent = Angel(reflector: MirrorsReflector())..configuration['two'] = 2;
..configuration['two'] = 2; var child = Angel(reflector: MirrorsReflector());
var child = new Angel(reflector: MirrorsReflector());
parent.mount('/child', child); parent.mount('/child', child);
test('sets children', () { test('sets children', () {
@ -34,20 +33,20 @@ main() {
}); });
test('custom server generator', () { test('custom server generator', () {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
var http = new AngelHttp.custom(app, HttpServer.bind); var http = AngelHttp.custom(app, HttpServer.bind);
expect(http.serverGenerator, HttpServer.bind); expect(http.serverGenerator, HttpServer.bind);
}); });
test('default error handler', () async { test('default error handler', () async {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
var http = new AngelHttp(app); var http = AngelHttp(app);
var rq = new MockHttpRequest('GET', $foo); var rq = MockHttpRequest('GET', $foo);
unawaited(rq.close()); unawaited(rq.close());
var rs = rq.response; var rs = rq.response;
var req = await http.createRequestContext(rq, rs); var req = await http.createRequestContext(rq, rs);
var res = await http.createResponseContext(rq, rs); var res = await http.createResponseContext(rq, rs);
var e = new AngelHttpException(null, var e = AngelHttpException(null,
statusCode: 321, message: 'Hello', errors: ['foo', 'bar']); statusCode: 321, message: 'Hello', errors: ['foo', 'bar']);
await app.errorHandler(e, req, res); await app.errorHandler(e, req, res);
await http.sendResponse(rq, rs, req, res); await http.sendResponse(rq, rs, req, res);
@ -63,10 +62,10 @@ main() {
}); });
test('plug-ins run on startup', () async { test('plug-ins run on startup', () async {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
app.startupHooks.add((app) => app.configuration['two'] = 2); app.startupHooks.add((app) => app.configuration['two'] = 2);
var http = new AngelHttp(app); var http = AngelHttp(app);
await http.startServer(); await http.startServer();
expect(app.configuration['two'], 2); expect(app.configuration['two'], 2);
await app.close(); await app.close();
@ -74,16 +73,16 @@ main() {
}); });
test('warning when adding routes to flattened router', () { test('warning when adding routes to flattened router', () {
var app = new Angel(reflector: MirrorsReflector()) var app = Angel(reflector: MirrorsReflector())
..optimizeForProduction(force: true); ..optimizeForProduction(force: true);
app.dumpTree(); app.dumpTree();
app.get('/', (req, res) => 2); app.get('/', (req, res) => 2);
app.mount('/foo', new Router()..get('/', (req, res) => 3)); app.mount('/foo', Router()..get('/', (req, res) => 3));
}); });
test('services close on close call', () async { test('services close on close call', () async {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
var svc = new CustomCloseService(); var svc = CustomCloseService();
expect(svc.value, 2); expect(svc.value, 2);
app.use('/', svc); app.use('/', svc);
await app.close(); await app.close();
@ -91,11 +90,10 @@ main() {
}); });
test('global injection added to injection map', () async { test('global injection added to injection map', () async {
var app = new Angel(reflector: MirrorsReflector()) var app = Angel(reflector: MirrorsReflector())..configuration['a'] = 'b';
..configuration['a'] = 'b'; var http = AngelHttp(app);
var http = new AngelHttp(app);
app.get('/', ioc((String a) => a)); app.get('/', ioc((String a) => a));
var rq = new MockHttpRequest('GET', Uri.parse('/')); var rq = MockHttpRequest('GET', Uri.parse('/'));
unawaited(rq.close()); unawaited(rq.close());
await http.handleRequest(rq); await http.handleRequest(rq);
var body = await rq.response.transform(utf8.decoder).join(); var body = await rq.response.transform(utf8.decoder).join();
@ -103,10 +101,10 @@ main() {
}); });
test('global injected serializer', () async { test('global injected serializer', () async {
var app = new Angel(reflector: MirrorsReflector())..serializer = (_) => 'x'; var app = Angel(reflector: MirrorsReflector())..serializer = (_) => 'x';
var http = new AngelHttp(app); var http = AngelHttp(app);
app.get($foo.path, (req, ResponseContext res) => res.serialize(null)); app.get($foo.path, (req, ResponseContext res) => res.serialize(null));
var rq = new MockHttpRequest('GET', $foo); var rq = MockHttpRequest('GET', $foo);
unawaited(rq.close()); unawaited(rq.close());
await http.handleRequest(rq); await http.handleRequest(rq);
var body = await rq.response.transform(utf8.decoder).join(); var body = await rq.response.transform(utf8.decoder).join();
@ -114,15 +112,15 @@ main() {
}); });
group('handler results', () { group('handler results', () {
var app = new Angel(reflector: MirrorsReflector()); var app = Angel(reflector: MirrorsReflector());
var http = new AngelHttp(app); var http = AngelHttp(app);
app.responseFinalizers app.responseFinalizers
.add((req, res) => throw new AngelHttpException.forbidden()); .add((req, res) => throw AngelHttpException.forbidden());
RequestContext req; RequestContext req;
ResponseContext res; ResponseContext res;
setUp(() async { setUp(() async {
var rq = new MockHttpRequest('GET', $foo); var rq = MockHttpRequest('GET', $foo);
unawaited(rq.close()); unawaited(rq.close());
req = await http.createRequestContext(rq, rq.response); req = await http.createRequestContext(rq, rq.response);
res = await http.createResponseContext(rq, rq.response); res = await http.createResponseContext(rq, rq.response);
@ -138,14 +136,14 @@ main() {
}); });
test('return future', () async { test('return future', () async {
var handler = new Future.value(2); var handler = Future.value(2);
expect(await app.getHandlerResult(handler, req, res), 2); expect(await app.getHandlerResult(handler, req, res), 2);
}); });
}); });
group('executeHandler', () { group('executeHandler', () {
test('return Stream', () async { test('return Stream', () async {
var handler = (req, res) => new Stream.fromIterable([2, 3]); var handler = (req, res) => Stream.fromIterable([2, 3]);
expect(await app.executeHandler(handler, req, res), isFalse); expect(await app.executeHandler(handler, req, res), isFalse);
}); });
@ -161,10 +159,10 @@ main() {
AngelHttp http; AngelHttp http;
setUp(() async { setUp(() async {
app = new Angel(reflector: MirrorsReflector()); app = Angel(reflector: MirrorsReflector());
app.get('/wtf', (req, res) => throw new AngelHttpException.forbidden()); app.get('/wtf', (req, res) => throw AngelHttpException.forbidden());
app.get('/wtf2', (req, res) => throw new AngelHttpException.forbidden()); app.get('/wtf2', (req, res) => throw AngelHttpException.forbidden());
http = new AngelHttp(app); http = AngelHttp(app);
await http.startServer('127.0.0.1', 0); await http.startServer('127.0.0.1', 0);
var oldHandler = app.errorHandler; var oldHandler = app.errorHandler;
@ -178,7 +176,7 @@ main() {
tearDown(() => app.close()); tearDown(() => app.close());
test('can send json', () async { test('can send json', () async {
var rq = new MockHttpRequest('GET', new Uri(path: 'wtf')) var rq = MockHttpRequest('GET', Uri(path: 'wtf'))
..headers.set('accept', 'application/json'); ..headers.set('accept', 'application/json');
unawaited(rq.close()); unawaited(rq.close());
unawaited(http.handleRequest(rq)); unawaited(http.handleRequest(rq));
@ -188,7 +186,7 @@ main() {
}); });
test('can throw in finalizer', () async { test('can throw in finalizer', () async {
var rq = new MockHttpRequest('GET', new Uri(path: 'wtf')) var rq = MockHttpRequest('GET', Uri(path: 'wtf'))
..headers.set('accept', 'application/json'); ..headers.set('accept', 'application/json');
unawaited(rq.close()); unawaited(rq.close());
unawaited(http.handleRequest(rq)); unawaited(http.handleRequest(rq));
@ -198,7 +196,7 @@ main() {
}); });
test('can send html', () async { test('can send html', () async {
var rq = new MockHttpRequest('GET', new Uri(path: 'wtf2')); var rq = MockHttpRequest('GET', Uri(path: 'wtf2'));
rq.headers.set('accept', 'text/html'); rq.headers.set('accept', 'text/html');
unawaited(rq.close()); unawaited(rq.close());
unawaited(http.handleRequest(rq)); unawaited(http.handleRequest(rq));

View file

@ -6,18 +6,18 @@ void main() {
Service<String, Todo> mapped; Service<String, Todo> mapped;
setUp(() { setUp(() {
inner = new MapService(); inner = MapService();
mapped = inner.map<Todo>(Todo.fromMap, Todo.toMap); mapped = inner.map<Todo>(Todo.fromMap, Todo.toMap);
}); });
test('create', () async { test('create', () async {
var result = await mapped.create( var result = await mapped.create(
new Todo(text: 'hello', complete: false), Todo(text: 'hello', complete: false),
); );
print(result); print(result);
expect( expect(
result, result,
new Todo(text: 'hello', complete: false), Todo(text: 'hello', complete: false),
); );
}); });
@ -26,7 +26,7 @@ void main() {
String id; String id;
setUp(() async { setUp(() async {
result = await mapped.create(new Todo(text: 'hello', complete: false)); result = await mapped.create(Todo(text: 'hello', complete: false));
id = result.id; id = result.id;
}); });
@ -35,12 +35,12 @@ void main() {
}); });
test('modify', () async { test('modify', () async {
var newTodo = new Todo(text: 'yes', complete: true); var newTodo = Todo(text: 'yes', complete: true);
expect(await mapped.update(id, newTodo), newTodo); expect(await mapped.update(id, newTodo), newTodo);
}); });
test('update', () async { test('update', () async {
var newTodo = new Todo(id: 'hmmm', text: 'yes', complete: true); var newTodo = Todo(id: 'hmmm', text: 'yes', complete: true);
expect(await mapped.update(id, newTodo), newTodo); expect(await mapped.update(id, newTodo), newTodo);
}); });
@ -61,7 +61,7 @@ class Todo {
Todo({this.id, this.text, this.complete}); Todo({this.id, this.text, this.complete});
static Todo fromMap(Map<String, dynamic> json) { static Todo fromMap(Map<String, dynamic> json) {
return new Todo( return Todo(
id: json['id'] as String, id: json['id'] as String,
text: json['text'] as String, text: json['text'] as String,
complete: json['complete'] as bool); complete: json['complete'] as bool);

View file

@ -22,15 +22,15 @@ main() {
http.Client client; http.Client client;
setUp(() async { setUp(() async {
app = new Angel(reflector: MirrorsReflector()) app = Angel(reflector: MirrorsReflector())
..use('/todos', service = new MapService()) ..use('/todos', service = MapService())
..errorHandler = (e, req, res) { ..errorHandler = (e, req, res) {
if (e.error != null) print('Whoops: ${e.error}'); if (e.error != null) print('Whoops: ${e.error}');
if (e.stackTrace != null) print(new Chain.forTrace(e.stackTrace).terse); if (e.stackTrace != null) print(Chain.forTrace(e.stackTrace).terse);
}; };
var server = await new AngelHttp(app).startServer(); var server = await AngelHttp(app).startServer();
client = new http.Client(); client = http.Client();
url = "http://${server.address.host}:${server.port}"; url = "http://${server.address.host}:${server.port}";
}); });

View file

@ -18,10 +18,10 @@ main() {
AngelHttp http; AngelHttp http;
setUp(() { setUp(() {
app = new Angel(reflector: MirrorsReflector()); app = Angel(reflector: MirrorsReflector());
http = new AngelHttp(app, useZone: true); http = AngelHttp(app, useZone: true);
app.logger = new Logger('streaming_test') app.logger = Logger('streaming_test')
..onRecord.listen((rec) { ..onRecord.listen((rec) {
print(rec); print(rec);
if (rec.stackTrace != null) print(rec.stackTrace); if (rec.stackTrace != null) print(rec.stackTrace);
@ -35,31 +35,30 @@ main() {
); );
app.get('/hello', (req, res) { app.get('/hello', (req, res) {
return new Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits]) return Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits])
.pipe(res); .pipe(res);
}); });
app.get('/write', (req, res) async { app.get('/write', (req, res) async {
await res.addStream( await res.addStream(
new Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits])); Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits]));
res.write('bye'); res.write('bye');
await res.close(); await res.close();
}); });
app.get('/multiple', (req, res) async { app.get('/multiple', (req, res) async {
await res.addStream( await res.addStream(
new Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits])); Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits]));
await res await res.addStream(Stream<List<int>>.fromIterable(['bye'.codeUnits]));
.addStream(new Stream<List<int>>.fromIterable(['bye'.codeUnits]));
await res.close(); await res.close();
}); });
app.get('/overwrite', (req, res) async { app.get('/overwrite', (req, res) async {
res.statusCode = 32; res.statusCode = 32;
await new Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits]) await Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits])
.pipe(res); .pipe(res);
var f = new Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits]) var f = Stream<List<int>>.fromIterable(['Hello, world!'.codeUnits])
.pipe(res) .pipe(res)
.then((_) => false) .then((_) => false)
.catchError((_) => true); .catchError((_) => true);
@ -67,7 +66,7 @@ main() {
expect(f, completion(true)); expect(f, completion(true));
}); });
app.get('/error', (req, res) => res.addError(new StateError('wtf'))); app.get('/error', (req, res) => res.addError(StateError('wtf')));
app.errorHandler = (e, req, res) async { app.errorHandler = (e, req, res) async {
stderr..writeln(e.error)..writeln(e.stackTrace); stderr..writeln(e.error)..writeln(e.stackTrace);
@ -77,7 +76,7 @@ main() {
tearDown(() => http.close()); tearDown(() => http.close());
_expectHelloBye(String path) async { _expectHelloBye(String path) async {
var rq = new MockHttpRequest('GET', Uri.parse(path)); var rq = MockHttpRequest('GET', Uri.parse(path));
unawaited(rq.close()); unawaited(rq.close());
await http.handleRequest(rq); await http.handleRequest(rq);
var body = await rq.response.transform(utf8.decoder).join(); var body = await rq.response.transform(utf8.decoder).join();
@ -90,7 +89,7 @@ main() {
test('cannot write after close', () async { test('cannot write after close', () async {
try { try {
var rq = new MockHttpRequest('GET', Uri.parse('/overwrite')); var rq = MockHttpRequest('GET', Uri.parse('/overwrite'));
unawaited(rq.close()); unawaited(rq.close());
await http.handleRequest(rq); await http.handleRequest(rq);
var body = await rq.response.transform(utf8.decoder).join(); var body = await rq.response.transform(utf8.decoder).join();
@ -104,7 +103,7 @@ main() {
test('res => addError', () async { test('res => addError', () async {
try { try {
var rq = new MockHttpRequest('GET', Uri.parse('/error')); var rq = MockHttpRequest('GET', Uri.parse('/error'));
unawaited(rq.close()); unawaited(rq.close());
await http.handleRequest(rq); await http.handleRequest(rq);
var body = await rq.response.transform(utf8.decoder).join(); var body = await rq.response.transform(utf8.decoder).join();

View file

@ -3,7 +3,7 @@ import 'package:test/test.dart';
main() { main() {
test('default view generator', () async { test('default view generator', () async {
var app = new Angel(); var app = Angel();
var view = await app.viewGenerator('foo', {'bar': 'baz'}); var view = await app.viewGenerator('foo', {'bar': 'baz'});
expect(view, contains('No view engine')); expect(view, contains('No view engine'));
}); });