This commit is contained in:
thosakwe 2017-04-04 04:35:36 -04:00
parent 94886bca13
commit edf1b04f9f
5 changed files with 145 additions and 15 deletions

View file

@ -1,6 +1,6 @@
# angel_framework # angel_framework
[![pub 1.0.0-dev.73](https://img.shields.io/badge/pub-1.0.0--dev.73-red.svg)](https://pub.dartlang.org/packages/angel_framework) [![pub 1.0.0-dev.74](https://img.shields.io/badge/pub-1.0.0--dev.74-red.svg)](https://pub.dartlang.org/packages/angel_framework)
[![build status](https://travis-ci.org/angel-dart/framework.svg)](https://travis-ci.org/angel-dart/framework) [![build status](https://travis-ci.org/angel-dart/framework.svg)](https://travis-ci.org/angel-dart/framework)
A high-powered HTTP server with support for dependency injection, sophisticated routing and more. A high-powered HTTP server with support for dependency injection, sophisticated routing and more.

View file

@ -11,30 +11,34 @@ import 'service.dart';
/// Wraps another service in a service that broadcasts events on actions. /// Wraps another service in a service that broadcasts events on actions.
class HookedService extends Service { class HookedService extends Service {
final List<StreamController<HookedServiceEvent>> _ctrl = [];
/// Tbe service that is proxied by this hooked one. /// Tbe service that is proxied by this hooked one.
final Service inner; final Service inner;
HookedServiceEventDispatcher beforeIndexed = final HookedServiceEventDispatcher beforeIndexed =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeRead = new HookedServiceEventDispatcher(); final HookedServiceEventDispatcher beforeRead =
HookedServiceEventDispatcher beforeCreated =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeModified = final HookedServiceEventDispatcher beforeCreated =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeUpdated = final HookedServiceEventDispatcher beforeModified =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeRemoved = final HookedServiceEventDispatcher beforeUpdated =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterIndexed = final HookedServiceEventDispatcher beforeRemoved =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterRead = new HookedServiceEventDispatcher(); final HookedServiceEventDispatcher afterIndexed =
HookedServiceEventDispatcher afterCreated =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterModified = final HookedServiceEventDispatcher afterRead =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterUpdated = final HookedServiceEventDispatcher afterCreated =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterRemoved = final HookedServiceEventDispatcher afterModified =
new HookedServiceEventDispatcher();
final HookedServiceEventDispatcher afterUpdated =
new HookedServiceEventDispatcher();
final HookedServiceEventDispatcher afterRemoved =
new HookedServiceEventDispatcher(); new HookedServiceEventDispatcher();
HookedService(Service this.inner) { HookedService(Service this.inner) {
@ -61,6 +65,25 @@ class HookedService extends Service {
.fold({}, (map, key) => map..[key] = params[key]); .fold({}, (map, key) => map..[key] = params[key]);
} }
/// Closes any open [StreamController]s on this instance. **Internal use only**.
Future close() async {
_ctrl.forEach((c) => c.close());
beforeIndexed._close();
beforeRead._close();
beforeCreated._close();
beforeModified._close();
beforeUpdated._close();
beforeRemoved._close();
afterIndexed._close();
afterRead._close();
afterCreated._close();
afterModified._close();
afterUpdated._close();
afterRemoved._close();
if (inner is HookedService) inner.close();
}
/// Adds hooks to this instance. /// Adds hooks to this instance.
void addHooks() { void addHooks() {
Hooks hooks = getAnnotation(inner, Hooks); Hooks hooks = getAnnotation(inner, Hooks);
@ -309,6 +332,54 @@ class HookedService extends Service {
afterRemoved.listen(listener); afterRemoved.listen(listener);
} }
/// Returns a [Stream] of all events fired before every service method.
///
/// *NOTE*: Only use this if you do not plan to modify events. There is no guarantee
/// that events coming out of this [Stream] will see changes you make within the [Stream]
/// callback.
Stream<HookedServiceEvent> beforeAllStream() {
var ctrl = new StreamController<HookedServiceEvent>();
_ctrl.add(ctrl);
before(HookedServiceEvent.ALL, ctrl.add);
return ctrl.stream;
}
/// Returns a [Stream] of all events fired after every service method.
///
/// *NOTE*: Only use this if you do not plan to modify events. There is no guarantee
/// that events coming out of this [Stream] will see changes you make within the [Stream]
/// callback.
Stream<HookedServiceEvent> afterAllStream() {
var ctrl = new StreamController<HookedServiceEvent>();
_ctrl.add(ctrl);
before(HookedServiceEvent.ALL, ctrl.add);
return ctrl.stream;
}
/// Returns a [Stream] of all events fired before every service method specified.
///
/// *NOTE*: Only use this if you do not plan to modify events. There is no guarantee
/// that events coming out of this [Stream] will see changes you make within the [Stream]
/// callback.
Stream<HookedServiceEvent> beforeStream(Iterable<String> eventNames) {
var ctrl = new StreamController<HookedServiceEvent>();
_ctrl.add(ctrl);
before(eventNames, ctrl.add);
return ctrl.stream;
}
/// Returns a [Stream] of all events fired AFTER every service method specified.
///
/// *NOTE*: Only use this if you do not plan to modify events. There is no guarantee
/// that events coming out of this [Stream] will see changes you make within the [Stream]
/// callback.
Stream<HookedServiceEvent> afterStream(Iterable<String> eventNames) {
var ctrl = new StreamController<HookedServiceEvent>();
_ctrl.add(ctrl);
after(eventNames, ctrl.add);
return ctrl.stream;
}
/// Runs the [listener] before [create], [modify] and [update]. /// Runs the [listener] before [create], [modify] and [update].
void beforeModify(HookedServiceEventListener listener) { void beforeModify(HookedServiceEventListener listener) {
beforeCreated.listen(listener); beforeCreated.listen(listener);
@ -549,6 +620,14 @@ class HookedServiceEvent {
static const String MODIFIED = "modified"; static const String MODIFIED = "modified";
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 [
INDEXED,
READ,
CREATED,
MODIFIED,
UPDATED,
REMOVED
];
/// Use this to end processing of an event. /// Use this to end processing of an event.
void cancel([result]) { void cancel([result]) {
@ -601,7 +680,12 @@ typedef HookedServiceEventListener(HookedServiceEvent event);
/// Can be listened to, but events may be canceled. /// Can be listened to, but events may be canceled.
class HookedServiceEventDispatcher { class HookedServiceEventDispatcher {
List<HookedServiceEventListener> listeners = []; final List<StreamController<HookedServiceEvent>> _ctrl = [];
final List<HookedServiceEventListener> listeners = [];
void _close() {
_ctrl.forEach((c) => c.close());
}
/// Fires an event, and returns it once it is either canceled, or all listeners have run. /// Fires an event, and returns it once it is either canceled, or all listeners have run.
Future<HookedServiceEvent> _emit(HookedServiceEvent event) async { Future<HookedServiceEvent> _emit(HookedServiceEvent event) async {
@ -616,6 +700,17 @@ class HookedServiceEventDispatcher {
return event; return event;
} }
/// Returns a [Stream] containing all events fired by this dispatcher.
///
/// *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.
Stream<HookedServiceEvent> asStream() {
var ctrl = new StreamController<HookedServiceEvent>();
_ctrl.add(ctrl);
listen(ctrl.add);
return ctrl.stream;
}
/// Registers the listener to be called whenever an event is triggered. /// Registers the listener to be called whenever an event is triggered.
void listen(HookedServiceEventListener listener) { void listen(HookedServiceEventListener listener) {
listeners.add(listener); listeners.add(listener);

View file

@ -11,6 +11,7 @@ import 'angel_base.dart';
import 'angel_http_exception.dart'; import 'angel_http_exception.dart';
import 'controller.dart'; import 'controller.dart';
import 'fatal_error.dart'; import 'fatal_error.dart';
import 'hooked_service.dart';
import 'request_context.dart'; import 'request_context.dart';
import 'response_context.dart'; import 'response_context.dart';
import 'routable.dart'; import 'routable.dart';
@ -93,6 +94,11 @@ class Angel extends AngelBase {
/// If the server is never started, they will never be called. /// If the server is never started, they will never be called.
final List<AngelConfigurer> justBeforeStart = []; final List<AngelConfigurer> justBeforeStart = [];
/// Plug-ins to be called right before server shutdown
///
/// If the server is never [close]d, they will never be called.
final List<AngelConfigurer> justBeforeStop = [];
/// Always run before responses are sent. /// Always run before responses are sent.
/// ///
/// These will only not run if an [AngelFatalError] occurs, /// These will only not run if an [AngelFatalError] occurs,
@ -180,6 +186,31 @@ class Angel extends AngelBase {
container.singleton(this); container.singleton(this);
} }
/// Shuts down the server, and closes any open [StreamController]s.
Future<HttpServer> close() async {
HttpServer server;
if (httpServer != null) {
server = httpServer;
await httpServer.close(force: true);
}
_afterProcessed.close();
_beforeProcessed.close();
_fatalErrorStream.close();
_onController.close();
await Future.forEach(services.keys, (Service service) async {
if (service is HookedService) {
await service.close();
}
});
for (var plugin in justBeforeStop) await plugin(this);
return server;
}
@override @override
void dumpTree( void dumpTree(
{callback(String tree), {callback(String tree),

View file

@ -1,5 +1,5 @@
name: angel_framework name: angel_framework
version: 1.0.0-dev.73 version: 1.0.0-dev.74
description: A high-powered HTTP server with DI, routing and more. description: A high-powered HTTP server with DI, routing and more.
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_framework homepage: https://github.com/angel-dart/angel_framework

View file

@ -24,6 +24,10 @@ main() {
app.use('/books', new BookService()); app.use('/books', new BookService());
Todos = app.service("todos"); Todos = app.service("todos");
Todos.beforeAllStream().listen((e) {
print('Fired ${e.eventName}! Data: ${e.data}; Params: ${e.params}');
});
app.fatalErrorStream.listen((e) => throw e.error); app.fatalErrorStream.listen((e) => throw e.error);
server = await app.startServer(); server = await app.startServer();