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
[![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)
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.
class HookedService extends Service {
final List<StreamController<HookedServiceEvent>> _ctrl = [];
/// Tbe service that is proxied by this hooked one.
final Service inner;
HookedServiceEventDispatcher beforeIndexed =
final HookedServiceEventDispatcher beforeIndexed =
new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeRead = new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeCreated =
final HookedServiceEventDispatcher beforeRead =
new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeModified =
final HookedServiceEventDispatcher beforeCreated =
new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeUpdated =
final HookedServiceEventDispatcher beforeModified =
new HookedServiceEventDispatcher();
HookedServiceEventDispatcher beforeRemoved =
final HookedServiceEventDispatcher beforeUpdated =
new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterIndexed =
final HookedServiceEventDispatcher beforeRemoved =
new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterRead = new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterCreated =
final HookedServiceEventDispatcher afterIndexed =
new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterModified =
final HookedServiceEventDispatcher afterRead =
new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterUpdated =
final HookedServiceEventDispatcher afterCreated =
new HookedServiceEventDispatcher();
HookedServiceEventDispatcher afterRemoved =
final HookedServiceEventDispatcher afterModified =
new HookedServiceEventDispatcher();
final HookedServiceEventDispatcher afterUpdated =
new HookedServiceEventDispatcher();
final HookedServiceEventDispatcher afterRemoved =
new HookedServiceEventDispatcher();
HookedService(Service this.inner) {
@ -61,6 +65,25 @@ class HookedService extends Service {
.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.
void addHooks() {
Hooks hooks = getAnnotation(inner, Hooks);
@ -309,6 +332,54 @@ class HookedService extends Service {
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].
void beforeModify(HookedServiceEventListener listener) {
beforeCreated.listen(listener);
@ -549,6 +620,14 @@ class HookedServiceEvent {
static const String MODIFIED = "modified";
static const String UPDATED = "updated";
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.
void cancel([result]) {
@ -601,7 +680,12 @@ typedef HookedServiceEventListener(HookedServiceEvent event);
/// Can be listened to, but events may be canceled.
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.
Future<HookedServiceEvent> _emit(HookedServiceEvent event) async {
@ -616,6 +700,17 @@ class HookedServiceEventDispatcher {
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.
void listen(HookedServiceEventListener listener) {
listeners.add(listener);

View file

@ -11,6 +11,7 @@ import 'angel_base.dart';
import 'angel_http_exception.dart';
import 'controller.dart';
import 'fatal_error.dart';
import 'hooked_service.dart';
import 'request_context.dart';
import 'response_context.dart';
import 'routable.dart';
@ -93,6 +94,11 @@ class Angel extends AngelBase {
/// If the server is never started, they will never be called.
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.
///
/// These will only not run if an [AngelFatalError] occurs,
@ -180,6 +186,31 @@ class Angel extends AngelBase {
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
void dumpTree(
{callback(String tree),

View file

@ -1,5 +1,5 @@
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.
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_framework

View file

@ -24,6 +24,10 @@ main() {
app.use('/books', new BookService());
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);
server = await app.startServer();