2016-04-29 01:19:09 +00:00
|
|
|
///Exposes WebSocket functionality to Angel.
|
|
|
|
library angel_websocket.server;
|
|
|
|
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:angel_framework/angel_framework.dart';
|
|
|
|
import 'shared.dart';
|
|
|
|
|
2016-05-03 23:42:06 +00:00
|
|
|
List<WebSocket> sockets = [];
|
|
|
|
|
2016-04-29 01:19:09 +00:00
|
|
|
_respond(AngelMessage message, Service service, Angel app) async {
|
|
|
|
if (message.method == 'index') {
|
|
|
|
return await service.index(message.body['query']);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (message.method == 'read') {
|
|
|
|
return await service.read(message.body['id'], message.body['query']);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (message.method == 'modify') {
|
|
|
|
return await service.modify(
|
|
|
|
message.body['id'], message.body['data'] ?? {}, message.body['query']);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (message.method == 'update') {
|
2016-05-03 23:42:06 +00:00
|
|
|
await service.update(
|
2016-04-29 01:19:09 +00:00
|
|
|
message.body['id'], message.body['data'] ?? {}, message.body['query']);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (message.method == 'remove') {
|
2016-05-03 23:42:06 +00:00
|
|
|
await service.remove(message.body['id'], message.body['query']);
|
2016-04-29 01:19:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
else throw new AngelHttpException.NotImplemented(
|
|
|
|
message: "This service does not support a \"${message
|
|
|
|
.method}\" method.");
|
|
|
|
}
|
|
|
|
|
|
|
|
_handleMsg(WebSocket socket, Angel app) {
|
|
|
|
return (msg) async {
|
|
|
|
String text = msg.toString();
|
|
|
|
try {
|
|
|
|
AngelMessage incoming = new AngelMessage.fromMap(
|
|
|
|
app.god.serializeToMap(text));
|
|
|
|
try {
|
|
|
|
Service service = app.service(incoming.service);
|
|
|
|
if (service == null) {
|
|
|
|
throw new AngelHttpException.NotFound(
|
|
|
|
message: 'The requested service does not exist.');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, let's respond. :)
|
|
|
|
var result = await _respond(incoming, service, app);
|
|
|
|
AngelMessage response = new AngelMessage(
|
|
|
|
incoming.service, incoming.method, body: {'result': result});
|
|
|
|
socket.add(app.god.serialize(response));
|
|
|
|
} catch (e) {
|
|
|
|
AngelHttpException err = (e is AngelHttpException)
|
|
|
|
? e
|
|
|
|
: new AngelHttpException(e);
|
|
|
|
AngelMessage response = new AngelMessage(
|
|
|
|
incoming.service, incoming.method, body: err.toMap());
|
|
|
|
socket.add(app.god.serialize(response));
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
// If we are sent invalid data, we're not even going to
|
|
|
|
// bother responding. :)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-05-03 23:42:06 +00:00
|
|
|
_wireHooks(bool hookAll) {
|
|
|
|
return (Angel app) async {
|
|
|
|
for (Pattern path in app.services.keys) {
|
|
|
|
Service _service = app.services[path];
|
|
|
|
|
|
|
|
// Hook any unhooked services
|
|
|
|
if (!(_service is HookedService) && hookAll) {
|
|
|
|
app.services[path] = new HookedService(_service);
|
|
|
|
}
|
|
|
|
|
|
|
|
Service service = app.services[path];
|
|
|
|
if (service is HookedService) {
|
|
|
|
service.onIndexed.listen((List items) {
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
websocket({String endPoint: '/ws', bool hookAll: true}) {
|
2016-04-29 01:19:09 +00:00
|
|
|
return (Angel app) async {
|
|
|
|
app.get(endPoint, (RequestContext req, ResponseContext res) async {
|
|
|
|
if (WebSocketTransformer.isUpgradeRequest(req.underlyingRequest)) {
|
|
|
|
res
|
|
|
|
..end()
|
|
|
|
..willCloseItself = true;
|
|
|
|
WebSocket socket = await WebSocketTransformer.upgrade(
|
|
|
|
req.underlyingRequest);
|
|
|
|
|
2016-05-03 23:42:06 +00:00
|
|
|
sockets.add(socket);
|
|
|
|
socket.listen(_handleMsg(socket, app), onDone: () {
|
|
|
|
// Remove from cache on disconnect
|
|
|
|
sockets.remove(socket);
|
|
|
|
});
|
2016-04-29 01:19:09 +00:00
|
|
|
} else {
|
|
|
|
throw new AngelHttpException.BadRequest(
|
|
|
|
message: 'This endpoint is only available via WebSockets.');
|
|
|
|
}
|
|
|
|
});
|
2016-05-03 23:42:06 +00:00
|
|
|
|
|
|
|
await app.configure(_wireHooks(hookAll));
|
2016-04-29 01:19:09 +00:00
|
|
|
};
|
|
|
|
}
|