2016-09-15 19:53:01 +00:00
|
|
|
library angel_framework.http;
|
|
|
|
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:merge_map/merge_map.dart';
|
|
|
|
import '../util.dart';
|
2017-01-20 22:11:20 +00:00
|
|
|
import 'request_context.dart';
|
|
|
|
import 'response_context.dart';
|
2016-09-15 19:53:01 +00:00
|
|
|
import 'metadata.dart';
|
|
|
|
import 'service.dart';
|
2016-05-02 22:28:14 +00:00
|
|
|
|
2016-06-19 05:02:41 +00:00
|
|
|
/// Wraps another service in a service that broadcasts events on actions.
|
2016-05-02 22:28:14 +00:00
|
|
|
class HookedService extends Service {
|
2016-06-21 22:56:04 +00:00
|
|
|
/// Tbe service that is proxied by this hooked one.
|
2016-05-02 22:28:14 +00:00
|
|
|
final Service inner;
|
|
|
|
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher beforeIndexed =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher beforeRead = new HookedServiceEventDispatcher();
|
|
|
|
HookedServiceEventDispatcher beforeCreated =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher beforeModified =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher beforeUpdated =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher beforeRemoved =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher afterIndexed =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher afterRead = new HookedServiceEventDispatcher();
|
|
|
|
HookedServiceEventDispatcher afterCreated =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher afterModified =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher afterUpdated =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEventDispatcher afterRemoved =
|
2016-10-22 20:41:36 +00:00
|
|
|
new HookedServiceEventDispatcher();
|
2016-06-21 04:19:43 +00:00
|
|
|
|
2016-06-23 19:05:55 +00:00
|
|
|
HookedService(Service this.inner) {
|
2016-06-24 19:19:02 +00:00
|
|
|
// Clone app instance
|
2016-10-22 20:41:36 +00:00
|
|
|
if (inner.app != null) this.app = inner.app;
|
2016-11-23 09:10:47 +00:00
|
|
|
}
|
2016-06-24 19:19:02 +00:00
|
|
|
|
2017-01-20 22:40:48 +00:00
|
|
|
RequestContext _getRequest(Map params) {
|
|
|
|
if (params == null) return null;
|
|
|
|
return params['__requestctx'];
|
|
|
|
}
|
|
|
|
|
|
|
|
ResponseContext _getResponse(Map params) {
|
|
|
|
if (params == null) return null;
|
|
|
|
return params['__responsectx'];
|
|
|
|
}
|
|
|
|
|
2017-01-20 22:11:20 +00:00
|
|
|
Map _stripReq(Map params) {
|
|
|
|
if (params == null)
|
|
|
|
return params;
|
|
|
|
else
|
|
|
|
return params..remove('__requestctx')..remove('__responsectx');
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adds hooks to this instance.
|
2016-12-10 14:05:40 +00:00
|
|
|
void addHooks() {
|
|
|
|
Hooks hooks = getAnnotation(inner, Hooks);
|
|
|
|
final before = [];
|
|
|
|
final after = [];
|
|
|
|
|
|
|
|
if (hooks != null) {
|
|
|
|
before.addAll(hooks.before);
|
|
|
|
after.addAll(hooks.after);
|
|
|
|
}
|
|
|
|
|
|
|
|
void applyListeners(Function fn, HookedServiceEventDispatcher dispatcher,
|
|
|
|
[bool isAfter]) {
|
|
|
|
Hooks hooks = getAnnotation(fn, Hooks);
|
|
|
|
final listeners = []..addAll(isAfter == true ? after : before);
|
|
|
|
|
|
|
|
if (hooks != null)
|
|
|
|
listeners.addAll(isAfter == true ? hooks.after : hooks.before);
|
|
|
|
|
|
|
|
listeners.forEach(dispatcher.listen);
|
|
|
|
}
|
|
|
|
|
|
|
|
applyListeners(inner.index, beforeIndexed);
|
|
|
|
applyListeners(inner.read, beforeRead);
|
|
|
|
applyListeners(inner.created, beforeCreated);
|
|
|
|
applyListeners(inner.modify, beforeModified);
|
|
|
|
applyListeners(inner.updated, beforeUpdated);
|
|
|
|
applyListeners(inner.removed, beforeRemoved);
|
|
|
|
applyListeners(inner.index, afterIndexed, true);
|
|
|
|
applyListeners(inner.read, afterRead, true);
|
|
|
|
applyListeners(inner.created, afterCreated, true);
|
|
|
|
applyListeners(inner.modify, afterModified, true);
|
|
|
|
applyListeners(inner.updated, afterUpdated, true);
|
|
|
|
applyListeners(inner.removed, afterRemoved, true);
|
|
|
|
}
|
|
|
|
|
2017-01-20 22:11:20 +00:00
|
|
|
/// Adds routes to this instance.
|
2016-11-23 09:10:47 +00:00
|
|
|
@override
|
|
|
|
void addRoutes() {
|
2016-06-24 19:19:02 +00:00
|
|
|
// Set up our routes. We still need to copy middleware from inner service
|
|
|
|
Map restProvider = {'provider': Providers.REST};
|
|
|
|
|
|
|
|
// Add global middleware if declared on the instance itself
|
2016-09-15 19:53:01 +00:00
|
|
|
Middleware before = getAnnotation(inner, Middleware);
|
2016-10-22 20:41:36 +00:00
|
|
|
final handlers = [];
|
|
|
|
|
2016-11-23 09:10:47 +00:00
|
|
|
if (before != null) handlers.addAll(before.handlers);
|
2016-06-24 19:19:02 +00:00
|
|
|
|
2016-09-15 19:53:01 +00:00
|
|
|
Middleware indexMiddleware = getAnnotation(inner.index, Middleware);
|
2016-06-24 19:19:02 +00:00
|
|
|
get('/', (req, res) async {
|
2017-01-20 22:11:20 +00:00
|
|
|
return await this.index(mergeMap([
|
|
|
|
req.query,
|
|
|
|
restProvider,
|
|
|
|
{'__requestctx': req, '__responsectx': res}
|
|
|
|
]));
|
2016-10-22 20:41:36 +00:00
|
|
|
},
|
|
|
|
middleware: []
|
|
|
|
..addAll(handlers)
|
|
|
|
..addAll((indexMiddleware == null) ? [] : indexMiddleware.handlers));
|
2016-06-24 19:19:02 +00:00
|
|
|
|
2016-09-15 19:53:01 +00:00
|
|
|
Middleware createMiddleware = getAnnotation(inner.create, Middleware);
|
2016-12-10 14:05:40 +00:00
|
|
|
post(
|
|
|
|
'/',
|
2017-01-20 22:11:20 +00:00
|
|
|
(req, res) async => await this.create(
|
|
|
|
req.body,
|
|
|
|
mergeMap([
|
|
|
|
req.query,
|
|
|
|
restProvider,
|
|
|
|
{'__requestctx': req, '__responsectx': res}
|
|
|
|
])),
|
2016-10-22 20:41:36 +00:00
|
|
|
middleware: []
|
|
|
|
..addAll(handlers)
|
|
|
|
..addAll(
|
|
|
|
(createMiddleware == null) ? [] : createMiddleware.handlers));
|
2016-06-24 19:19:02 +00:00
|
|
|
|
2016-09-15 19:53:01 +00:00
|
|
|
Middleware readMiddleware = getAnnotation(inner.read, Middleware);
|
2016-06-24 19:19:02 +00:00
|
|
|
|
|
|
|
get(
|
|
|
|
'/:id',
|
2017-01-20 22:11:20 +00:00
|
|
|
(req, res) async => await this.read(
|
|
|
|
req.params['id'],
|
|
|
|
mergeMap([
|
|
|
|
req.query,
|
|
|
|
restProvider,
|
|
|
|
{'__requestctx': req, '__responsectx': res}
|
|
|
|
])),
|
2016-10-22 20:41:36 +00:00
|
|
|
middleware: []
|
|
|
|
..addAll(handlers)
|
|
|
|
..addAll((readMiddleware == null) ? [] : readMiddleware.handlers));
|
2016-06-24 19:19:02 +00:00
|
|
|
|
2016-09-15 19:53:01 +00:00
|
|
|
Middleware modifyMiddleware = getAnnotation(inner.modify, Middleware);
|
2016-06-24 19:19:02 +00:00
|
|
|
patch(
|
|
|
|
'/:id',
|
2016-12-10 14:05:40 +00:00
|
|
|
(req, res) async => await this.modify(
|
2017-01-20 22:11:20 +00:00
|
|
|
req.params['id'],
|
|
|
|
req.body,
|
|
|
|
mergeMap([
|
|
|
|
req.query,
|
|
|
|
restProvider,
|
|
|
|
{'__requestctx': req, '__responsectx': res}
|
|
|
|
])),
|
2016-10-22 20:41:36 +00:00
|
|
|
middleware: []
|
|
|
|
..addAll(handlers)
|
|
|
|
..addAll(
|
|
|
|
(modifyMiddleware == null) ? [] : modifyMiddleware.handlers));
|
2016-06-24 19:19:02 +00:00
|
|
|
|
2016-09-15 19:53:01 +00:00
|
|
|
Middleware updateMiddleware = getAnnotation(inner.update, Middleware);
|
2016-06-24 19:19:02 +00:00
|
|
|
post(
|
|
|
|
'/:id',
|
2016-12-10 14:05:40 +00:00
|
|
|
(req, res) async => await this.update(
|
2017-01-20 22:11:20 +00:00
|
|
|
req.params['id'],
|
|
|
|
req.body,
|
|
|
|
mergeMap([
|
|
|
|
req.query,
|
|
|
|
restProvider,
|
|
|
|
{'__requestctx': req, '__responsectx': res}
|
|
|
|
])),
|
2016-10-22 20:41:36 +00:00
|
|
|
middleware: []
|
|
|
|
..addAll(handlers)
|
|
|
|
..addAll(
|
|
|
|
(updateMiddleware == null) ? [] : updateMiddleware.handlers));
|
2016-06-24 19:19:02 +00:00
|
|
|
|
2016-09-15 19:53:01 +00:00
|
|
|
Middleware removeMiddleware = getAnnotation(inner.remove, Middleware);
|
2016-06-24 19:19:02 +00:00
|
|
|
delete(
|
|
|
|
'/:id',
|
2017-01-20 22:11:20 +00:00
|
|
|
(req, res) async => await this.remove(
|
|
|
|
req.params['id'],
|
|
|
|
mergeMap([
|
|
|
|
req.query,
|
|
|
|
restProvider,
|
|
|
|
{'__requestctx': req, '__responsectx': res}
|
|
|
|
])),
|
2016-10-22 20:41:36 +00:00
|
|
|
middleware: []
|
|
|
|
..addAll(handlers)
|
|
|
|
..addAll(
|
|
|
|
(removeMiddleware == null) ? [] : removeMiddleware.handlers));
|
2016-12-10 14:05:40 +00:00
|
|
|
|
|
|
|
addHooks();
|
2016-06-23 19:05:55 +00:00
|
|
|
}
|
2016-05-02 22:28:14 +00:00
|
|
|
|
|
|
|
@override
|
2017-01-20 22:11:20 +00:00
|
|
|
Future<List> index([Map _params]) async {
|
|
|
|
var params = _stripReq(_params);
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEvent before = await beforeIndexed._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.INDEXED,
|
2016-06-21 04:19:43 +00:00
|
|
|
params: params));
|
2016-06-19 05:02:41 +00:00
|
|
|
if (before._canceled) {
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEvent after = await beforeIndexed._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.INDEXED,
|
2016-06-21 04:19:43 +00:00
|
|
|
params: params, result: before.result));
|
|
|
|
return after.result;
|
2016-06-19 05:02:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
List result = await inner.index(params);
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEvent after = await afterIndexed._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.INDEXED,
|
2016-06-21 04:19:43 +00:00
|
|
|
params: params, result: result));
|
|
|
|
return after.result;
|
2016-05-02 22:28:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
2017-01-20 22:11:20 +00:00
|
|
|
Future read(id, [Map _params]) async {
|
|
|
|
var params = _stripReq(_params);
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEvent before = await beforeRead._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.READ,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, params: params));
|
2016-05-02 22:28:14 +00:00
|
|
|
|
2016-06-21 04:19:43 +00:00
|
|
|
if (before._canceled) {
|
|
|
|
HookedServiceEvent after = await afterRead._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.READ,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, params: params, result: before.result));
|
|
|
|
return after.result;
|
|
|
|
}
|
|
|
|
|
|
|
|
var result = await inner.read(id, params);
|
|
|
|
HookedServiceEvent after = await afterRead._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.READ,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, params: params, result: result));
|
|
|
|
return after.result;
|
|
|
|
}
|
2016-05-02 22:28:14 +00:00
|
|
|
|
|
|
|
@override
|
2017-01-20 22:11:20 +00:00
|
|
|
Future create(data, [Map _params]) async {
|
|
|
|
var params = _stripReq(_params);
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEvent before = await beforeCreated._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.CREATED,
|
2016-06-21 04:19:43 +00:00
|
|
|
data: data, params: params));
|
|
|
|
|
|
|
|
if (before._canceled) {
|
|
|
|
HookedServiceEvent after = await afterCreated._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.CREATED,
|
2016-06-21 04:19:43 +00:00
|
|
|
data: data, params: params, result: before.result));
|
|
|
|
return after.result;
|
|
|
|
}
|
|
|
|
|
|
|
|
var result = await inner.create(data, params);
|
|
|
|
HookedServiceEvent after = await afterCreated._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.CREATED,
|
2016-06-21 04:19:43 +00:00
|
|
|
data: data, params: params, result: result));
|
|
|
|
return after.result;
|
2016-05-02 22:28:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
2017-01-20 22:11:20 +00:00
|
|
|
Future modify(id, data, [Map _params]) async {
|
|
|
|
var params = _stripReq(_params);
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEvent before = await beforeModified._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.MODIFIED,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, data: data, params: params));
|
2016-05-02 22:28:14 +00:00
|
|
|
|
2016-06-21 04:19:43 +00:00
|
|
|
if (before._canceled) {
|
|
|
|
HookedServiceEvent after = await afterModified._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.MODIFIED,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, data: data, params: params, result: before.result));
|
|
|
|
return after.result;
|
|
|
|
}
|
|
|
|
|
|
|
|
var result = await inner.modify(id, data, params);
|
|
|
|
HookedServiceEvent after = await afterModified._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.MODIFIED,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, data: data, params: params, result: result));
|
|
|
|
return after.result;
|
|
|
|
}
|
2016-05-02 22:28:14 +00:00
|
|
|
|
|
|
|
@override
|
2017-01-20 22:11:20 +00:00
|
|
|
Future update(id, data, [Map _params]) async {
|
|
|
|
var params = _stripReq(_params);
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEvent before = await beforeUpdated._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.UPDATED,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, data: data, params: params));
|
|
|
|
|
|
|
|
if (before._canceled) {
|
|
|
|
HookedServiceEvent after = await afterUpdated._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.UPDATED,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, data: data, params: params, result: before.result));
|
|
|
|
return after.result;
|
|
|
|
}
|
|
|
|
|
|
|
|
var result = await inner.update(id, data, params);
|
|
|
|
HookedServiceEvent after = await afterUpdated._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.UPDATED,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, data: data, params: params, result: result));
|
|
|
|
return after.result;
|
2016-05-02 22:28:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
2017-01-20 22:11:20 +00:00
|
|
|
Future remove(id, [Map _params]) async {
|
|
|
|
var params = _stripReq(_params);
|
2016-06-21 04:19:43 +00:00
|
|
|
HookedServiceEvent before = await beforeRemoved._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.REMOVED,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, params: params));
|
|
|
|
|
|
|
|
if (before._canceled) {
|
|
|
|
HookedServiceEvent after = await afterRemoved._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.REMOVED,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, params: params, result: before.result));
|
|
|
|
return after.result;
|
|
|
|
}
|
|
|
|
|
|
|
|
var result = await inner.remove(id, params);
|
|
|
|
HookedServiceEvent after = await afterRemoved._emit(
|
2017-01-20 22:40:48 +00:00
|
|
|
new HookedServiceEvent._base(_getRequest(_params),
|
|
|
|
_getResponse(_params), inner, HookedServiceEvent.REMOVED,
|
2016-06-21 04:19:43 +00:00
|
|
|
id: id, params: params, result: result));
|
|
|
|
return after.result;
|
2016-05-02 22:28:14 +00:00
|
|
|
}
|
2017-01-20 22:11:20 +00:00
|
|
|
|
|
|
|
/// Fires an `after` event. This will not be propagated to clients,
|
|
|
|
/// but will be broadcasted to WebSockets, etc.
|
2017-01-20 22:40:48 +00:00
|
|
|
Future<HookedServiceEvent> fire(String eventName, result,
|
|
|
|
[HookedServiceEventListener callback]) async {
|
2017-01-20 22:11:20 +00:00
|
|
|
HookedServiceEventDispatcher dispatcher;
|
|
|
|
|
|
|
|
switch (eventName) {
|
|
|
|
case HookedServiceEvent.INDEXED:
|
|
|
|
dispatcher = afterIndexed;
|
|
|
|
break;
|
|
|
|
case HookedServiceEvent.READ:
|
|
|
|
dispatcher = afterRead;
|
|
|
|
break;
|
|
|
|
case HookedServiceEvent.CREATED:
|
|
|
|
dispatcher = afterCreated;
|
|
|
|
break;
|
|
|
|
case HookedServiceEvent.MODIFIED:
|
|
|
|
dispatcher = afterModified;
|
|
|
|
break;
|
|
|
|
case HookedServiceEvent.UPDATED:
|
|
|
|
dispatcher = afterUpdated;
|
|
|
|
break;
|
|
|
|
case HookedServiceEvent.REMOVED:
|
|
|
|
dispatcher = afterRemoved;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new ArgumentError("Invalid service event name: '$eventName'");
|
|
|
|
}
|
|
|
|
|
|
|
|
var ev = new HookedServiceEvent._base(null, null, this, eventName);
|
|
|
|
if (callback != null) await callback(ev);
|
|
|
|
return await dispatcher._emit(ev);
|
|
|
|
}
|
2016-06-19 05:02:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Fired when a hooked service is invoked.
|
|
|
|
class HookedServiceEvent {
|
2016-06-21 04:19:43 +00:00
|
|
|
static const String INDEXED = "indexed";
|
|
|
|
static const String READ = "read";
|
|
|
|
static const String CREATED = "created";
|
|
|
|
static const String MODIFIED = "modified";
|
|
|
|
static const String UPDATED = "updated";
|
|
|
|
static const String REMOVED = "removed";
|
|
|
|
|
2016-06-19 05:02:41 +00:00
|
|
|
/// Use this to end processing of an event.
|
|
|
|
void cancel(result) {
|
|
|
|
_canceled = true;
|
|
|
|
_result = result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool _canceled = false;
|
2016-06-21 04:19:43 +00:00
|
|
|
String _eventName;
|
|
|
|
var _id;
|
2016-06-19 05:02:41 +00:00
|
|
|
var data;
|
2016-06-21 04:19:43 +00:00
|
|
|
Map _params;
|
2016-06-19 05:02:41 +00:00
|
|
|
var _result;
|
2017-01-20 22:11:20 +00:00
|
|
|
RequestContext _request;
|
|
|
|
ResponseContext _response;
|
2016-06-21 04:19:43 +00:00
|
|
|
|
|
|
|
String get eventName => _eventName;
|
|
|
|
|
|
|
|
get id => _id;
|
|
|
|
|
|
|
|
Map get params => _params;
|
|
|
|
|
2017-01-20 22:11:20 +00:00
|
|
|
RequestContext get request => _request;
|
|
|
|
|
|
|
|
ResponseContext get response => _response;
|
|
|
|
|
2016-06-19 05:02:41 +00:00
|
|
|
get result => _result;
|
2016-06-21 04:19:43 +00:00
|
|
|
|
2016-06-19 05:02:41 +00:00
|
|
|
/// The inner service whose method was hooked.
|
|
|
|
Service service;
|
|
|
|
|
2017-01-20 22:11:20 +00:00
|
|
|
HookedServiceEvent._base(this._result, this._response, Service this.service,
|
|
|
|
String this._eventName,
|
2016-06-21 04:19:43 +00:00
|
|
|
{id, this.data, Map params, result}) {
|
|
|
|
_id = id;
|
|
|
|
_params = params ?? {};
|
2016-06-19 05:02:41 +00:00
|
|
|
_result = result;
|
|
|
|
}
|
2016-06-21 04:19:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Triggered on a hooked service event.
|
2017-01-20 22:11:20 +00:00
|
|
|
typedef HookedServiceEventListener(HookedServiceEvent event);
|
2016-06-21 04:19:43 +00:00
|
|
|
|
|
|
|
/// Can be listened to, but events may be canceled.
|
|
|
|
class HookedServiceEventDispatcher {
|
|
|
|
List<HookedServiceEventListener> listeners = [];
|
|
|
|
|
|
|
|
/// Fires an event, and returns it once it is either canceled, or all listeners have run.
|
|
|
|
Future<HookedServiceEvent> _emit(HookedServiceEvent event) async {
|
|
|
|
for (var listener in listeners) {
|
|
|
|
await listener(event);
|
|
|
|
|
|
|
|
if (event._canceled) return event;
|
|
|
|
}
|
|
|
|
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Registers the listener to be called whenever an event is triggered.
|
|
|
|
void listen(HookedServiceEventListener listener) {
|
|
|
|
listeners.add(listener);
|
|
|
|
}
|
|
|
|
}
|