74
This commit is contained in:
parent
94886bca13
commit
edf1b04f9f
5 changed files with 145 additions and 15 deletions
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue