diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml index 69c608f9..1f841d46 100644 --- a/.idea/libraries/Dart_Packages.xml +++ b/.idea/libraries/Dart_Packages.xml @@ -5,7 +5,7 @@ - + @@ -33,7 +33,7 @@ - + @@ -51,13 +51,6 @@ - - - - - - - @@ -79,13 +72,6 @@ - - - - - - - @@ -96,14 +82,14 @@ - + - + @@ -124,7 +110,7 @@ - + @@ -152,21 +138,21 @@ - + - + - + @@ -180,7 +166,7 @@ - + @@ -212,13 +198,6 @@ - - - - - - - @@ -243,14 +222,21 @@ - + + + + + + + + - + @@ -264,7 +250,7 @@ - + @@ -306,7 +292,7 @@ - + @@ -320,14 +306,14 @@ - + - + @@ -341,7 +327,7 @@ - + @@ -369,7 +355,7 @@ - + @@ -383,14 +369,14 @@ - + - + @@ -425,7 +411,7 @@ - + @@ -453,7 +439,7 @@ - + @@ -478,101 +464,107 @@ + + + + + + + - + - + - + - + - + - - - - + + - + - - - + + + - + - - - + + + - + - + - - + + - + - + - - + + - + - + - - - + + + + diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 99d3b52f..36f5c394 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -1,9 +1,43 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -26,20 +60,11 @@ - - + + - - - - - - - - - - - + + @@ -47,8 +72,8 @@ - - + + @@ -56,64 +81,78 @@ - - + + - - + + - - + + - - - - - - - + + - - + + - - + + - - + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + @@ -126,19 +165,6 @@ - var body = await rs.fold<List<int>>([], (out, list) => []..addAll(list)); - async = - async { - await - e read( - for (var ha - geth - pip - close - sendFile - getHan - gethandle - BANG execute lazyBod lazyBody() @@ -156,13 +182,21 @@ handleAnge errorHandl handl + HttpHeaders.ACCEPT + HttpHeaders.CONTENT_TYPE + HttpHeaders.CONTE + HttpHeaders + HttpStatus.FORBIDDEN + HttpStatus. + JSON + ContentType.JSON.toString() + (req, res) + headers: headers, + _ + ContentType.HTML.mimeType + ContentType.JSON.mimeType - modify - update - remove - data - event after fatalErrorStream onController @@ -174,7 +208,6 @@ req.path req.path` autoSnakeCaseNames == false ? $0 : '$1ated_at' - 'content-type' appa isClosed useStream @@ -186,6 +219,14 @@ = { + 'accept' + 'content-type' + 403 + (RequestContext req, res) + headers: headers.cast<String, String>(), + this. + 'text/html' + 'application/json' C:\Users\thosa\Source\Angel\framework\lib @@ -195,6 +236,7 @@ $PROJECT_DIR$/test $PROJECT_DIR$/lib/src/core $PROJECT_DIR$/lib + $PROJECT_DIR$ @@ -208,57 +250,57 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + @@ -272,10 +314,10 @@ - - - - + + + + @@ -285,9 +327,6 @@ - - - @@ -309,14 +348,15 @@ - - - + + + + @@ -358,7 +398,7 @@ - + @@ -635,14 +675,10 @@ - - - - 1507654580167 - - - - 1507654580167 + + + + 1511026951368 @@ -980,13 +1016,17 @@ 1528672631392 - + + 1529523884120 + + + + 1529523884121 + + - - - @@ -1014,9 +1054,12 @@ + + + - + @@ -1028,7 +1071,7 @@ - + @@ -1036,7 +1079,7 @@ - + @@ -1047,13 +1090,15 @@ + + - - - + + + @@ -1064,8 +1109,6 @@ - - @@ -1079,7 +1122,6 @@ - @@ -1104,7 +1146,8 @@ - + + @@ -1112,156 +1155,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1269,20 +1162,6 @@ - - - - - - - - - - - - - - @@ -1290,27 +1169,6 @@ - - - - - - - - - - - - - - - - - - - - - @@ -1367,73 +1225,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - @@ -1441,31 +1245,271 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CHANGELOG.md b/CHANGELOG.md index a40f76bf..557ac482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 1.1.4+5 +* Intermediary release while patching up Dart 2 bugs. +* Stricter Dart 2 use. +* Remove `AngelMetrics` for good. + # 1.1.4+4 * Fix a bug that caused a race condition in hooked services. diff --git a/analysis_options.yaml b/analysis_options.yaml index 1167d894..a0ee1ea1 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,5 +1,6 @@ analyzer: - strong-mode: true + strong-mode: + implicit-casts: false linter: rules: - avoid_slow_async_io \ No newline at end of file diff --git a/lib/hooks.dart b/lib/hooks.dart index bcce6141..0b50dccd 100644 --- a/lib/hooks.dart +++ b/lib/hooks.dart @@ -141,12 +141,12 @@ HookedServiceEventListener remove(key, [remover(key, obj)]) { else if (obj is List) return obj..remove(key); else if (obj is Iterable) - return obj.where((k) => !key); + return obj.where((k) => key != true); else if (obj is Map) return obj..remove(key); else { try { - reflect(obj).setField(new Symbol(key), null); + reflect(obj).setField(new Symbol(key.toString()), null); return obj; } catch (e) { throw new ArgumentError("Cannot remove key '$key' from $obj."); diff --git a/lib/metrics.dart b/lib/metrics.dart deleted file mode 100644 index b4ecfdf1..00000000 --- a/lib/metrics.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'src/stats/metric_server.dart'; -export 'src/stats/stats.dart'; diff --git a/lib/src/core/anonymous_service.dart b/lib/src/core/anonymous_service.dart index d263dca6..0faf3b12 100644 --- a/lib/src/core/anonymous_service.dart +++ b/lib/src/core/anonymous_service.dart @@ -5,15 +5,17 @@ import 'service.dart'; /// /// Well-suited for testing. class AnonymousService extends Service { - Function _index, _read, _create, _modify, _update, _remove; + Future Function([Map]) _index; + Future Function(Object, [Map]) _read, _create, _remove; + Future Function(Object, Object, [Map]) _modify, _update; AnonymousService( - {FutureOr index([Map params]), - FutureOr read(id, [Map params]), - FutureOr create(data, [Map params]), - FutureOr modify(id, data, [Map params]), - FutureOr update(id, data, [Map params]), - FutureOr remove(id, [Map params])}) + {Future index([Map params]), + Future read(id, [Map params]), + Future create(data, [Map params]), + Future modify(id, data, [Map params]), + Future update(id, data, [Map params]), + Future remove(id, [Map params])}) : super() { _index = index; _read = read; diff --git a/lib/src/core/hooked_service.dart b/lib/src/core/hooked_service.dart index 3fae479c..17dc5b31 100644 --- a/lib/src/core/hooked_service.dart +++ b/lib/src/core/hooked_service.dart @@ -1,8 +1,6 @@ library angel_framework.http; import 'dart:async'; -import 'package:angel_http_exception/angel_http_exception.dart'; -import 'package:merge_map/merge_map.dart'; import '../util.dart'; import 'request_context.dart'; import 'response_context.dart'; @@ -48,12 +46,12 @@ class HookedService extends Service { RequestContext _getRequest(Map params) { if (params == null) return null; - return params['__requestctx']; + return params['__requestctx'] as RequestContext; } ResponseContext _getResponse(Map params) { if (params == null) return null; - return params['__responsectx']; + return params['__responsectx'] as ResponseContext; } Map _stripReq(Map params) { @@ -88,8 +86,7 @@ class HookedService extends Service { /// Adds hooks to this instance. void addHooks() { Hooks hooks = getAnnotation(inner, Hooks); - final before = []; - final after = []; + List before = [], after = []; if (hooks != null) { before.addAll(hooks.before); @@ -99,7 +96,8 @@ class HookedService extends Service { void applyListeners(Function fn, HookedServiceEventDispatcher dispatcher, [bool isAfter]) { Hooks hooks = getAnnotation(fn, Hooks); - final listeners = []..addAll(isAfter == true ? after : before); + final listeners = [] + ..addAll(isAfter == true ? after : before); if (hooks != null) listeners.addAll(isAfter == true ? hooks.after : hooks.before); diff --git a/lib/src/core/injection.dart b/lib/src/core/injection.dart index b9594642..5952fded 100644 --- a/lib/src/core/injection.dart +++ b/lib/src/core/injection.dart @@ -5,7 +5,7 @@ const List _primitiveTypes = const [String, int, num, double, Null]; /// Shortcut for calling [preInject], and then [handleContained]. /// /// Use this to instantly create a request handler for a DI-enabled method. -RequestHandler createDynamicHandler(handler, +RequestHandler createDynamicHandler(Function handler, {Iterable optional: const []}) { var injection = preInject(handler); injection.optional.addAll(optional ?? []); @@ -77,7 +77,7 @@ bool suitableForInjection( } /// Handles a request with a DI-enabled handler. -RequestHandler handleContained(handler, InjectionRequest injection) { +RequestHandler handleContained(Function handler, InjectionRequest injection) { return (RequestContext req, ResponseContext res) { if (injection.parameters.isNotEmpty && injection.parameters.values.any((p) => p.match != null) && diff --git a/lib/src/core/map_service.dart b/lib/src/core/map_service.dart index 3f2d9e90..a405834a 100644 --- a/lib/src/core/map_service.dart +++ b/lib/src/core/map_service.dart @@ -77,7 +77,7 @@ class MapService extends Service { message: 'MapService does not support `create` with ${data.runtimeType}.'); var now = new DateTime.now().toIso8601String(); - var result = data; + var result = data as Map; if (autoIdAndDateFields == true) { result @@ -85,7 +85,7 @@ class MapService extends Service { ..[autoSnakeCaseNames == false ? 'createdAt' : 'created_at'] = now ..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = now; } - items.add(result); + items.add(result.cast()); return new Future.value(result); } @@ -98,7 +98,7 @@ class MapService extends Service { if (!items.any(_matchesId(id))) return create(data, params); return read(id).then((item) { - var result = item..addAll(data); + var result = item..addAll(data as Map); if (autoIdAndDateFields == true) result @@ -121,7 +121,7 @@ class MapService extends Service { throw new AngelHttpException.notFound( message: 'No record found for ID $id'); - var result = data; + var result = data as Map; if (autoIdAndDateFields == true) { result ..['id'] = id?.toString() @@ -130,7 +130,7 @@ class MapService extends Service { ..[autoSnakeCaseNames == false ? 'updatedAt' : 'updated_at'] = new DateTime.now().toIso8601String(); } - items.add(result); + items.add(result.cast()); return new Future.value(result); }); } diff --git a/lib/src/core/request_context.dart b/lib/src/core/request_context.dart index c926c792..36ad5210 100644 --- a/lib/src/core/request_context.dart +++ b/lib/src/core/request_context.dart @@ -144,18 +144,18 @@ abstract class RequestContext { /// within a service hook. T grab(key) { if (params.containsKey(key)) - return params[key]; + return params[key] as T; else if (_injections.containsKey(key)) - return _injections[key]; + return _injections[key] as T; else if (properties.containsKey(key)) - return properties[key]; + return properties[key] as T; else { var prop = app?.findProperty(key); if (prop != null) - return prop; + return prop as T; else if (key is Type) { try { - return app.container.make(key); + return app.container.make(key) as T; } catch (e) { return null; } @@ -195,7 +195,7 @@ abstract class RequestContext { throw new ArgumentError( 'RequestContext.accepts expects the `contentType` parameter to NOT be null.'); - _acceptHeaderCache ??= headers.value(HttpHeaders.ACCEPT); + _acceptHeaderCache ??= headers.value('accept'); if (_acceptHeaderCache == null) return false; diff --git a/lib/src/core/response_context.dart b/lib/src/core/response_context.dart index 25f0445a..6330fad6 100644 --- a/lib/src/core/response_context.dart +++ b/lib/src/core/response_context.dart @@ -179,7 +179,7 @@ abstract class ResponseContext implements StreamSink>, StringSink { } /// Serializes JSON to the response. - void json(value) => serialize(value, contentType: ContentType.JSON); + void json(value) => serialize(value, contentType: 'application/json'); /// Returns a JSONP response. void jsonp(value, {String callbackName: "callback", contentType}) { @@ -202,7 +202,7 @@ abstract class ResponseContext implements StreamSink>, StringSink { if (!isOpen) throw closed(); return app.viewGenerator(view, data).then((content) { write(content); - headers['content-type'] = ContentType.HTML.toString(); + headers['content-type'] = 'text/html'; end(); }); } @@ -217,9 +217,9 @@ abstract class ResponseContext implements StreamSink>, StringSink { void redirect(url, {bool absolute: true, int code: 302}) { if (!isOpen) throw closed(); headers - ..['content-type'] = ContentType.HTML.toString() + ..['content-type'] = 'text/html' ..['location'] = - url is String ? url : app.navigate(url, absolute: absolute); + url is String ? url : app.navigate(url as Iterable, absolute: absolute); statusCode = code ?? 302; write(''' @@ -259,7 +259,7 @@ abstract class ResponseContext implements StreamSink>, StringSink { Route matched = _findRoute(app); if (matched != null) { - redirect(matched.makeUri(params), code: code); + redirect(matched.makeUri(params.cast()), code: code); return; } @@ -290,7 +290,7 @@ abstract class ResponseContext implements StreamSink>, StringSink { final head = controller.findExpose().path.toString().replaceAll(_straySlashes, ''); - final tail = matched.makeUri(params).replaceAll(_straySlashes, ''); + final tail = matched.makeUri(params.cast()).replaceAll(_straySlashes, ''); redirect('$head/$tail'.replaceAll(_straySlashes, ''), code: code); } diff --git a/lib/src/core/routable.dart b/lib/src/core/routable.dart index 8dafb635..f39ae109 100644 --- a/lib/src/core/routable.dart +++ b/lib/src/core/routable.dart @@ -8,6 +8,7 @@ import 'hooked_service.dart'; import 'metadata.dart'; import 'request_context.dart'; import 'response_context.dart'; +import 'server.dart'; import 'service.dart'; final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)'); @@ -16,7 +17,7 @@ final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)'); typedef Future RequestMiddleware(RequestContext req, ResponseContext res); /// A function that receives an incoming [RequestContext] and responds to it. -typedef Future RequestHandler(RequestContext req, ResponseContext res); +typedef FutureOr RequestHandler(RequestContext req, ResponseContext res); /// Sequentially runs a list of [handlers] of middleware, and returns early if any does not /// return `true`. Works well with [Router].chain. @@ -31,8 +32,9 @@ RequestMiddleware waterfall(List handlers) { runPipeline = () => req.app.executeHandler(handler, req, res); else { var current = runPipeline; - runPipeline = () => current().then((result) => - !result ? result : req.app.executeHandler(handler, req, res)); + runPipeline = () => current().then((result) => !result + ? new Future.value(result) + : req.app.executeHandler(handler, req, res)); } } @@ -97,7 +99,8 @@ class Routable extends Router { handlerSequence.addAll(middleware ?? []); handlerSequence.addAll(handlers); - return super.addRoute(method, path, handler, middleware: handlerSequence); + return super.addRoute(method, path.toString(), handler, + middleware: handlerSequence); } /// Mounts the given [router] on this instance. @@ -128,8 +131,8 @@ class Routable extends Router { if (_router is AngelBase) { handlers.add((RequestContext req, ResponseContext res) { - req.app = _router; - res.app = _router; + req.app = _router as Angel; + res.app = _router as Angel; return true; }); } @@ -140,7 +143,7 @@ class Routable extends Router { Map copiedMiddleware = new Map.from(router.requestMiddleware); for (String middlewareName in copiedMiddleware.keys) { requestMiddleware.putIfAbsent("$middlewarePrefix$middlewareName", - () => copiedMiddleware[middlewareName]); + () => copiedMiddleware[middlewareName] as RequestHandler); } // Also copy properties... @@ -154,7 +157,7 @@ class Routable extends Router { // _router.dumpTree(header: 'Mounting on "$path":'); // root.child(path, debug: debug, handlers: handlers).addChild(router.root); - var mounted = mount(path, _router); + var mounted = mount(path.toString(), _router); if (_router is Routable) { // Copy services, too. :) diff --git a/lib/src/core/server.dart b/lib/src/core/server.dart index f9d07318..7029bb4f 100644 --- a/lib/src/core/server.dart +++ b/lib/src/core/server.dart @@ -31,7 +31,7 @@ typedef FutureOr AngelConfigurer(Angel app); /// A powerful real-time/REST/MVC server class. class Angel extends AngelBase { final List _children = []; - final Map>>> + final Map>>> handlerCache = new HashMap(); Router _flattened; @@ -186,7 +186,7 @@ class Angel extends AngelBase { 'This route will be ignored, and no requests will ever reach it.'); } return super - .mount(path, router, hooked: hooked != false, namespace: namespace); + .mount(path.toString(), router, hooked: hooked != false, namespace: namespace); } /// Loads some base dependencies into the service container. diff --git a/lib/src/core/service.dart b/lib/src/core/service.dart index 3cd6e6fd..ca59dbb0 100644 --- a/lib/src/core/service.dart +++ b/lib/src/core/service.dart @@ -117,7 +117,7 @@ class Service extends Routable { if (before != null) handlers.addAll(before.handlers); Middleware indexMiddleware = getAnnotation(service.index, Middleware); - get('/', (req, res) { + get('/', (RequestContext req, res) { return this.index(mergeMap([ {'query': req.query}, restProvider, @@ -154,7 +154,7 @@ class Service extends Routable { get( '/:id', - (req, res) => this.read( + (RequestContext req, res) => this.read( toId(req.params['id']), mergeMap([ {'query': req.query}, @@ -214,7 +214,7 @@ class Service extends Routable { Middleware removeMiddleware = getAnnotation(service.remove, Middleware); delete( '/', - (req, res) => this.remove( + (RequestContext req, res) => this.remove( null, mergeMap([ {'query': req.query}, @@ -227,7 +227,7 @@ class Service extends Routable { (removeMiddleware == null) ? [] : removeMiddleware.handlers)); delete( '/:id', - (req, res) => this.remove( + (RequestContext req, res) => this.remove( toId(req.params['id']), mergeMap([ {'query': req.query}, diff --git a/lib/src/core/typed_service.dart b/lib/src/core/typed_service.dart index 9ee37834..aa9821c9 100644 --- a/lib/src/core/typed_service.dart +++ b/lib/src/core/typed_service.dart @@ -37,15 +37,15 @@ class TypedService extends Service { Model result = god.deserializeDatum(data, outputType: T); if (data['createdAt'] is DateTime) { - result.createdAt = data['createdAt']; + result.createdAt = data['createdAt'] as DateTime; } else if (data['created_at'] is DateTime) { - result.createdAt = data['created_at']; + result.createdAt = data['created_at'] as DateTime; } if (data['updatedAt'] is DateTime) { - result.updatedAt = data['updatedAt']; + result.updatedAt = data['updatedAt'] as DateTime; } else if (data['updated_at'] is DateTime) { - result.updatedAt = data['updated_at']; + result.updatedAt = data['updated_at'] as DateTime; } // print('x: $x\nresult: $result'); diff --git a/lib/src/http/angel_http.dart b/lib/src/http/angel_http.dart index 0c5ec736..7f9919be 100644 --- a/lib/src/http/angel_http.dart +++ b/lib/src/http/angel_http.dart @@ -112,7 +112,7 @@ class AngelHttp { var path = req.path; if (path == '/') path = ''; - Tuple3>> resolveTuple() { + Tuple3>> resolveTuple() { Router r = app.optimizedRouter; var resolved = r.resolveAbsolute(path, method: req.method, strip: false); @@ -147,7 +147,7 @@ class AngelHttp { else { var current = runPipeline; runPipeline = () => current().then((result) => - !result ? result : app.executeHandler(handler, req, res)); + !result ? new Future.value(result) : app.executeHandler(handler, req, res)); } } @@ -157,7 +157,7 @@ class AngelHttp { } if (useZone == false) { - return handle().catchError((e, st) { + return handle().catchError((e, StackTrace st) { if (e is FormatException) throw new AngelHttpException.badRequest(message: e.message) ..stackTrace = st; @@ -196,7 +196,7 @@ class AngelHttp { } return handleAngelHttpException(e, trace, req, res, request); - }).catchError((e, st) { + }).catchError((e, StackTrace st) { var trace = new Trace.from(st ?? StackTrace.current).terse; request.response.close(); // Ideally, we won't be in a position where an absolutely fatal error occurs, @@ -353,7 +353,7 @@ class AngelHttp { Future createResponseContext(HttpResponse response, [RequestContext correspondingRequest]) => new Future.value( - new HttpResponseContextImpl(response, app, correspondingRequest) + new HttpResponseContextImpl(response, app, correspondingRequest as HttpRequestContextImpl) ..serializer = (app.serializer ?? god.serialize) ..encoders.addAll(app.encoders ?? {})); diff --git a/lib/src/http/controller.dart b/lib/src/http/controller.dart index 40493bb2..f4e8005b 100644 --- a/lib/src/http/controller.dart +++ b/lib/src/http/controller.dart @@ -27,7 +27,7 @@ class Controller { Controller({this.debug: false, this.injectSingleton: true}); @mustCallSuper - Future configureServer(Angel app) { + Future configureServer(Angel app) { _app = app; if (injectSingleton != false) _app.container.singleton(this); @@ -59,7 +59,7 @@ class Controller { return new Future.value(); } - Function _routeBuilder( + void Function(Symbol, MethodMirror) _routeBuilder( InstanceMirror instanceMirror, Routable routable, List handlers) { return (Symbol methodName, MethodMirror method) { if (method.isRegularMethod && @@ -74,7 +74,8 @@ class Controller { if (exposeDecl == null) return; - var reflectedMethod = instanceMirror.getField(methodName).reflectee; + var reflectedMethod = + instanceMirror.getField(methodName).reflectee as Function; var middleware = []..addAll(handlers)..addAll(exposeDecl.middleware); String name = exposeDecl.as?.isNotEmpty == true ? exposeDecl.as @@ -86,9 +87,10 @@ class Controller { method.parameters[1].type.reflectedType == ResponseContext) { // Create a regular route routeMappings[name] = routable - .addRoute(exposeDecl.method, exposeDecl.path, (req, res) { - var result = reflectedMethod(req, res); - return result is RequestHandler ? result(req, res) : result; + .addRoute(exposeDecl.method, exposeDecl.path, + (RequestContext req, ResponseContext res) { + var result = reflectedMethod(req, res); + return result is RequestHandler ? result(req, res) : result; }, middleware: middleware); return; } @@ -112,5 +114,5 @@ class Controller { Expose findExpose() => reflectClass(runtimeType) .metadata .map((m) => m.reflectee) - .firstWhere((r) => r is Expose, orElse: () => null); + .firstWhere((r) => r is Expose, orElse: () => null) as Expose; } diff --git a/lib/src/http/http_request_context.dart b/lib/src/http/http_request_context.dart index c483de8a..5de674e2 100644 --- a/lib/src/http/http_request_context.dart +++ b/lib/src/http/http_request_context.dart @@ -27,7 +27,7 @@ class HttpRequestContextImpl extends RequestContext { @override String get hostname { - return io.headers.value(HttpHeaders.HOST); + return io.headers.value('host'); } /// The underlying [HttpRequest] instance underneath this context. diff --git a/lib/src/http/http_response_context.dart b/lib/src/http/http_response_context.dart index 56f3b324..a6f200ba 100644 --- a/lib/src/http/http_response_context.dart +++ b/lib/src/http/http_response_context.dart @@ -68,7 +68,7 @@ class HttpResponseContextImpl extends ResponseContext { if (encoders.isNotEmpty && correspondingRequest != null) { var allowedEncodings = correspondingRequest.headers - .value(HttpHeaders.ACCEPT_ENCODING) + .value('accept-encoding') ?.split(',') ?.map((s) => s.trim()) ?.where((s) => s.isNotEmpty) @@ -92,7 +92,7 @@ class HttpResponseContextImpl extends ResponseContext { if (encoder != null) { if (firstStream) { - io.headers.set(HttpHeaders.CONTENT_ENCODING, key); + io.headers.set('content-encoding', key); } output = encoders[key].bind(output); diff --git a/lib/src/stats/metric_server.dart b/lib/src/stats/metric_server.dart deleted file mode 100644 index 5aa7463a..00000000 --- a/lib/src/stats/metric_server.dart +++ /dev/null @@ -1,118 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import '../core/core.dart'; -import '../http/http.dart'; -import 'stats.dart'; - -@deprecated -class AngelMetrics extends Angel { - Angel _inner; - StreamSubscription _sub; - - AngelMetrics() : super() { - get('/metrics', (req, res) { - res.contentType = ContentType.HTML; - - var rows = stats.all.map((stat) { - return ''' - - ${stat.name} - ${stat.iterations} - ${stat.sum}ms - ${stat.average.toStringAsFixed(2)}ms - '''; - }).join(); - - res.write(''' - - - - - Metrics - - - Metrics - Updated every 5 seconds - - - - Stat - # Iterations - Total (ms) - Average (ms) - - - $rows - - - - - '''); - }); - } - - final AngelMetricsStats stats = new AngelMetricsStats._(); - - @override - Future close() { - _sub?.cancel(); - _inner.close(); - return super.close(); - } - - @override - Iterable resolveAll(String absolute, String relative, - {String method: 'GET', bool strip: true}) { - return stats.resolveAll.run(() => - _inner.resolveAll(absolute, relative, method: method, strip: strip)); - } - - @override - Future executeHandler( - handler, RequestContext req, ResponseContext res) { - return stats.executeHandler - .run(() => super.executeHandler(handler, req, res)); - } - - @override - Future getHandlerResult(handler, RequestContext req, ResponseContext res) { - return stats.getHandlerResult - .run(() => super.getHandlerResult(handler, req, res)); - } - - @override - Future runContained( - Function handler, RequestContext req, ResponseContext res) { - return stats.runContained.run(() => super.runContained(handler, req, res)); - } -} - -class AngelMetricsStats { - AngelMetricsStats._() { - all = [ - resolveAll, - executeHandler, - getHandlerResult, - runContained, - ]; - } - - final Stats resolveAll = new Stats('resolveAll'); - final Stats executeHandler = new Stats('executeHandler'); - final Stats getHandlerResult = new Stats('getHandlerResult'); - final Stats runContained = new Stats('runContained'); - - List all; - - void add(Stats stats) { - all.add(stats); - } - - void log() { - all.forEach((s) => s.log()); - } -} diff --git a/lib/src/stats/stats.dart b/lib/src/stats/stats.dart deleted file mode 100644 index 2c42a5dc..00000000 --- a/lib/src/stats/stats.dart +++ /dev/null @@ -1,53 +0,0 @@ -/// Computes averages progressively. - -import 'dart:async'; - -class Stats { - final String name; - - int _total = 0, _count = 0; - double _average = 0.0; - - Stats(this.name); - - double get average => _average ?? (_total / _count); - - int get iterations => _count; - - int get sum => _total; - - void log() { - print('$name: $average avg.'); - } - - void add(int value) { - _average = null; - _total += value; - _count++; - } - - FutureOr run(FutureOr f()) { - var sw = new Stopwatch(); - //print('--- $name START'); - sw.start(); - - void whenDone() { - sw.stop(); - var ms = sw.elapsedMilliseconds; - add(ms); - //print('--- $name DONE after ${ms}ms'); - } - - var r = f(); - - if (r is Future) { - return (r as Future).then((x) { - whenDone(); - return x; - }); - } - - whenDone(); - return r; - } -} diff --git a/lib/src/util.dart b/lib/src/util.dart index 9586611c..435ad4e9 100644 --- a/lib/src/util.dart +++ b/lib/src/util.dart @@ -20,7 +20,7 @@ getAnnotation(obj, Type T) { MethodMirror methodMirror = (reflect(obj) as ClosureMirror).function; return matchingAnnotation(methodMirror.metadata, T); } else { - ClassMirror classMirror = reflectClass(obj.runtimeType); + ClassMirror classMirror = reflectClass(obj.runtimeType as Type); return matchingAnnotation(classMirror.metadata, T); } } diff --git a/pubspec.yaml b/pubspec.yaml index 37e15872..4ee94a3e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_framework -version: 1.1.4+4 +version: 1.1.4+5 description: A high-powered HTTP server with DI, routing and more. author: Tobe O homepage: https://github.com/angel-dart/angel_framework diff --git a/test/accepts_test.dart b/test/accepts_test.dart index 0c93b6a9..2fe4e6bc 100644 --- a/test/accepts_test.dart +++ b/test/accepts_test.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; import 'package:mock_request/mock_request.dart'; import 'package:test/test.dart'; @@ -10,34 +9,36 @@ main() { test('no content type', () async { var req = await acceptContentTypes(); expect(req.acceptsAll, isFalse); - expect(req.accepts(ContentType.JSON), isFalse); + //expect(req.accepts(ContentType.JSON), isFalse); expect(req.accepts('application/json'), isFalse); - expect(req.accepts(ContentType.HTML), isFalse); + //expect(req.accepts(ContentType.HTML), isFalse); expect(req.accepts('text/html'), isFalse); }); test('wildcard', () async { var req = await acceptContentTypes(['*/*']); expect(req.acceptsAll, isTrue); - expect(req.accepts(ContentType.JSON), isTrue); + //expect(req.accepts(ContentType.JSON), isTrue); expect(req.accepts('application/json'), isTrue); - expect(req.accepts(ContentType.HTML), isTrue); + //expect(req.accepts(ContentType.HTML), isTrue); expect(req.accepts('text/html'), isTrue); }); test('specific type', () async { var req = await acceptContentTypes(['text/html']); expect(req.acceptsAll, isFalse); - expect(req.accepts(ContentType.JSON), isFalse); + //expect(req.accepts(ContentType.JSON), isFalse); expect(req.accepts('application/json'), isFalse); - expect(req.accepts(ContentType.HTML), isTrue); + //expect(req.accepts(ContentType.HTML), isTrue); expect(req.accepts('text/html'), isTrue); }); test('strict', () async { var req = await acceptContentTypes(['text/html', "*/*"]); - expect(req.accepts(ContentType.HTML), isTrue); - expect(req.accepts(ContentType.JSON, strict: true), isFalse); + expect(req.accepts('text/html'), isTrue); + //expect(req.accepts(ContentType.HTML), isTrue); + //expect(req.accepts(ContentType.JSON, strict: true), isFalse); + expect(req.accepts('application/json', strict: true), isFalse); }); group('disallow null', () { @@ -57,7 +58,7 @@ Future acceptContentTypes( [Iterable contentTypes = const []]) { var headerString = contentTypes.isEmpty ? null : contentTypes.join(','); var rq = new MockHttpRequest('GET', ENDPOINT); - rq.headers.set(HttpHeaders.ACCEPT, headerString); + rq.headers.set('accept', headerString); rq.close(); var app = new Angel(); var http = new AngelHttp(app); diff --git a/test/controller_test.dart b/test/controller_test.dart index a4307b2e..47289020 100644 --- a/test/controller_test.dart +++ b/test/controller_test.dart @@ -100,7 +100,7 @@ main() { test('optional name', () async { var app = new Angel(); await app.configure(new NamedController().configureServer); - expect(app.controllers['foo'], new isInstanceOf()); + expect(app.controllers['foo'], const TypeMatcher()); }); test("middleware", () async { diff --git a/test/di_test.dart b/test/di_test.dart index 56b2a966..db9db0c9 100644 --- a/test/di_test.dart +++ b/test/di_test.dart @@ -61,7 +61,7 @@ main() { } void validateTodoSingleton(response) { - Map todo = json.decode(response.body); + Map todo = json.decode(response.body.toString()); expect(todo["id"], equals(null)); expect(todo["text"], equals(TEXT)); expect(todo["over"], equals(OVER)); diff --git a/test/exception_test.dart b/test/exception_test.dart index 0a852a9a..28937a1e 100644 --- a/test/exception_test.dart +++ b/test/exception_test.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; import 'package:dart2_constant/convert.dart'; import 'package:matcher/matcher.dart'; @@ -7,29 +6,29 @@ import 'package:test/test.dart'; main() { test('named constructors', () { expect(new AngelHttpException.badRequest(), - isException(HttpStatus.BAD_REQUEST, '400 Bad Request')); + isException(400, '400 Bad Request')); expect(new AngelHttpException.notAuthenticated(), - isException(HttpStatus.UNAUTHORIZED, '401 Not Authenticated')); + isException(401, '401 Not Authenticated')); expect(new AngelHttpException.paymentRequired(), - isException(HttpStatus.PAYMENT_REQUIRED, '402 Payment Required')); + isException(402, '402 Payment Required')); expect(new AngelHttpException.forbidden(), - isException(HttpStatus.FORBIDDEN, '403 Forbidden')); + isException(403, '403 Forbidden')); expect(new AngelHttpException.notFound(), - isException(HttpStatus.NOT_FOUND, '404 Not Found')); + isException(404, '404 Not Found')); expect(new AngelHttpException.methodNotAllowed(), - isException(HttpStatus.METHOD_NOT_ALLOWED, '405 Method Not Allowed')); + isException(405, '405 Method Not Allowed')); expect(new AngelHttpException.notAcceptable(), - isException(HttpStatus.NOT_ACCEPTABLE, '406 Not Acceptable')); + isException(406, '406 Not Acceptable')); expect(new AngelHttpException.methodTimeout(), - isException(HttpStatus.REQUEST_TIMEOUT, '408 Timeout')); + isException(408, '408 Timeout')); expect(new AngelHttpException.conflict(), - isException(HttpStatus.CONFLICT, '409 Conflict')); + isException(409, '409 Conflict')); expect(new AngelHttpException.notProcessable(), isException(422, '422 Not Processable')); expect(new AngelHttpException.notImplemented(), - isException(HttpStatus.NOT_IMPLEMENTED, '501 Not Implemented')); + isException(501, '501 Not Implemented')); expect(new AngelHttpException.unavailable(), - isException(HttpStatus.SERVICE_UNAVAILABLE, '503 Unavailable')); + isException(503, '503 Unavailable')); }); test('fromMap', () { diff --git a/test/hooked_test.dart b/test/hooked_test.dart index afe51caa..0b6b0dc8 100644 --- a/test/hooked_test.dart +++ b/test/hooked_test.dart @@ -22,7 +22,7 @@ main() { client = new http.Client(); app.use('/todos', new TypedService(new MapService())); app.use('/books', new BookService()); - Todos = app.service("todos"); + Todos = app.service("todos") as HookedService; Todos.beforeAllStream().listen((e) { print('Fired ${e.eventName}! Data: ${e.data}; Params: ${e.params}'); @@ -71,7 +71,7 @@ main() { }); var response = await client.post("$url/todos", - body: god.serialize({"arbitrary": "data"}), headers: headers); + body: god.serialize({"arbitrary": "data"}), headers: headers.cast()); print(response.body); Map result = god.deserialize(response.body); expect(result["hello"], equals("hooked world")); @@ -97,7 +97,7 @@ main() { test('metadata', () async { final service = new HookedService(new IncrementService())..addHooks(); - expect(service.inner, isNot(new isInstanceOf())); + expect(service.inner, isNot(const TypeMatcher())); IncrementService.TIMES = 0; await service.index(); expect(IncrementService.TIMES, equals(2)); @@ -128,7 +128,7 @@ main() { print('Params to $type ${e.eventName}: ${e.params}'); expect(e.params, isMap); expect(e.params.keys, contains('provider')); - expect(e.params['provider'], const isInstanceOf()); + expect(e.params['provider'], const TypeMatcher()); } svc diff --git a/test/parameter_meta_test.dart b/test/parameter_meta_test.dart index 20af59cb..99060a62 100644 --- a/test/parameter_meta_test.dart +++ b/test/parameter_meta_test.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:dart2_constant/convert.dart'; import 'package:angel_framework/angel_framework.dart'; -import 'package:logging/logging.dart'; import 'package:mock_request/mock_request.dart'; import 'package:test/test.dart'; diff --git a/test/primitives_test.dart b/test/primitives_test.dart index ec0fada9..289eb533 100644 --- a/test/primitives_test.dart +++ b/test/primitives_test.dart @@ -18,7 +18,7 @@ main() { '/num/parsed/:num', waterfall([ (RequestContext req) { - req.params['n'] = num.parse(req.params['num']); + req.params['n'] = num.parse(req.params['num'].toString()); return true; }, (num n) => n, diff --git a/test/routing_test.dart b/test/routing_test.dart index 4e95e7d0..3dcc0c8a 100644 --- a/test/routing_test.dart +++ b/test/routing_test.dart @@ -118,7 +118,7 @@ main() { var response = await client.get('$url/name/HELLO/last/WORLD'); print('Response: ${response.body}'); var json_ = json.decode(response.body); - expect(json_, new isInstanceOf>()); + expect(json_, const TypeMatcher()); expect(json_['first'], equals('HELLO')); expect(json_['last'], equals('WORLD')); }); @@ -157,7 +157,7 @@ main() { Map headers = {'Content-Type': 'application/json'}; String postData = json.encode({'it': 'works'}); var response = - await client.post("$url/lambda", headers: headers, body: postData); + await client.post("$url/lambda", headers: headers.cast(), body: postData); print('Response: ${response.body}'); expect(json.decode(response.body)['it'], equals('works')); }); diff --git a/test/serialize_test.dart b/test/serialize_test.dart index ad31a54b..24929afb 100644 --- a/test/serialize_test.dart +++ b/test/serialize_test.dart @@ -15,7 +15,7 @@ main() { ..get( '/bar', (req, ResponseContext res) => - res.serialize({'hello': 'world'}, contentType: ContentType.HTML)); + res.serialize({'hello': 'world'}, contentType: 'text/html')); client = new http.Client(); server = await new AngelHttp(app).startServer(); @@ -33,12 +33,10 @@ main() { test("correct content-type", () async { var response = await client.get('$url/foo'); print('Response: ${response.body}'); - expect(response.headers[HttpHeaders.CONTENT_TYPE], - contains(ContentType.JSON.mimeType)); + expect(response.headers['content-type'], contains('application/json')); response = await client.get('$url/bar'); print('Response: ${response.body}'); - expect(response.headers[HttpHeaders.CONTENT_TYPE], - contains(ContentType.HTML.mimeType)); + expect(response.headers['content-type'], contains('text/html')); }); } diff --git a/test/server_test.dart b/test/server_test.dart index 558ffbaa..15b42bdf 100644 --- a/test/server_test.dart +++ b/test/server_test.dart @@ -47,8 +47,8 @@ main() { await app.errorHandler(e, req, res); await http.sendResponse(rq, req, res); expect( - ContentType.parse(rs.headers.value(HttpHeaders.CONTENT_TYPE)).mimeType, - ContentType.HTML.mimeType, + ContentType.parse(rs.headers.value('content-type')).mimeType, + 'text/html', ); expect(rs.statusCode, e.statusCode); var body = await rs.transform(utf8.decoder).join(); @@ -169,35 +169,35 @@ main() { test('can send json', () async { var rq = new MockHttpRequest('GET', new Uri(path: 'wtf')) - ..headers.set(HttpHeaders.ACCEPT, ContentType.JSON.toString()); + ..headers.set('accept', 'application/json'); rq.close(); http.handleRequest(rq); await rq.response.toList(); - expect(rq.response.statusCode, HttpStatus.FORBIDDEN); + expect(rq.response.statusCode, 403); expect( - rq.response.headers.contentType.mimeType, ContentType.JSON.mimeType); + rq.response.headers.contentType.mimeType, 'application/json'); }); test('can throw in finalizer', () async { var rq = new MockHttpRequest('GET', new Uri(path: 'wtf')) - ..headers.set(HttpHeaders.ACCEPT, ContentType.JSON.toString()); + ..headers.set('accept', 'application/json'); rq.close(); http.handleRequest(rq); await rq.response.toList(); - expect(rq.response.statusCode, HttpStatus.FORBIDDEN); + expect(rq.response.statusCode, 403); expect( - rq.response.headers.contentType.mimeType, ContentType.JSON.mimeType); + rq.response.headers.contentType.mimeType, 'application/json'); }); test('can send html', () async { var rq = new MockHttpRequest('GET', new Uri(path: 'wtf2')); - rq.headers.set(HttpHeaders.ACCEPT, ContentType.HTML.toString()); + rq.headers.set('accept', 'text/html'); rq.close(); http.handleRequest(rq); await rq.response.toList(); - expect(rq.response.statusCode, HttpStatus.FORBIDDEN); + expect(rq.response.statusCode, 403); expect( - rq.response.headers.contentType?.mimeType, ContentType.HTML.mimeType); + rq.response.headers.contentType?.mimeType, 'text/html'); }); }); } diff --git a/test/services_test.dart b/test/services_test.dart index 7ea687fe..06ae7e5e 100644 --- a/test/services_test.dart +++ b/test/services_test.dart @@ -52,7 +52,7 @@ main() { test('can create data', () async { String postData = god.serialize({'text': 'Hello, world!'}); var response = - await client.post("$url/todos", headers: headers, body: postData); + await client.post("$url/todos", headers: headers.cast(), body: postData); expect(response.statusCode, 201); var json = god.deserialize(response.body); print(json); @@ -61,7 +61,7 @@ main() { test('can fetch data', () async { String postData = god.serialize({'text': 'Hello, world!'}); - await client.post("$url/todos", headers: headers, body: postData); + await client.post("$url/todos", headers: headers.cast(), body: postData); var response = await client.get("$url/todos/0"); expect(response.statusCode, 200); var json = god.deserialize(response.body); @@ -71,10 +71,10 @@ main() { test('can modify data', () async { String postData = god.serialize({'text': 'Hello, world!'}); - await client.post("$url/todos", headers: headers, body: postData); + await client.post("$url/todos", headers: headers.cast(), body: postData); postData = god.serialize({'text': 'modified'}); var response = - await client.patch("$url/todos/0", headers: headers, body: postData); + await client.patch("$url/todos/0", headers: headers.cast(), body: postData); expect(response.statusCode, 200); var json = god.deserialize(response.body); print(json); @@ -83,10 +83,10 @@ main() { test('can overwrite data', () async { String postData = god.serialize({'text': 'Hello, world!'}); - await client.post("$url/todos", headers: headers, body: postData); + await client.post("$url/todos", headers: headers.cast(), body: postData); postData = god.serialize({'over': 'write'}); var response = - await client.post("$url/todos/0", headers: headers, body: postData); + await client.post("$url/todos/0", headers: headers.cast(), body: postData); expect(response.statusCode, 200); var json = god.deserialize(response.body); print(json); @@ -97,7 +97,7 @@ main() { test('can delete data', () async { String postData = god.serialize({'text': 'Hello, world!'}); var created = await client - .post("$url/todos", headers: headers, body: postData) + .post("$url/todos", headers: headers.cast(), body: postData) .then((r) => json.decode(r.body)); var response = await client.delete("$url/todos/${created['id']}"); expect(response.statusCode, 200); diff --git a/test/streaming_test.dart b/test/streaming_test.dart index 798442ab..f6b86091 100644 --- a/test/streaming_test.dart +++ b/test/streaming_test.dart @@ -29,7 +29,7 @@ main() { }, ); - app.get('/hello', (res) { + app.get('/hello', (ResponseContext res) { new Stream>.fromIterable(['Hello, world!'.codeUnits]).pipe(res); }); @@ -48,7 +48,7 @@ main() { await res.close(); }); - app.get('/overwrite', (res) async { + app.get('/overwrite', (ResponseContext res) async { res.statusCode = 32; await new Stream>.fromIterable(['Hello, world!'.codeUnits]) .pipe(res); diff --git a/test/typed_service_test.dart b/test/typed_service_test.dart index f084de04..4b4b1b28 100644 --- a/test/typed_service_test.dart +++ b/test/typed_service_test.dart @@ -24,7 +24,7 @@ main() { new Todo(text: 'a', completed: false, createdAt: now, updatedAt: now); var m = svc.serialize(t); print(m); - expect(m, { + expect(m..remove('_identityHashCode'), { 'id': null, 'createdAt': now.toIso8601String(), 'updatedAt': now.toIso8601String(), @@ -39,7 +39,7 @@ main() { 'createdAt': now.toIso8601String(), 'updatedAt': now.toIso8601String() }); - expect(m, new isInstanceOf()); + expect(m, const TypeMatcher()); var t = m as Todo; expect(t.createdAt.millisecondsSinceEpoch, now.millisecondsSinceEpoch); }); @@ -50,7 +50,7 @@ main() { 'created_at': now.toIso8601String(), 'updated_at': now.toIso8601String() }); - expect(m, new isInstanceOf()); + expect(m, const TypeMatcher()); var t = m as Todo; expect(t.createdAt.millisecondsSinceEpoch, now.millisecondsSinceEpoch); });