diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml
new file mode 100644
index 00000000..7cf9e265
--- /dev/null
+++ b/.idea/libraries/Dart_Packages.xml
@@ -0,0 +1,347 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..94a25f7f
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/client.dart b/lib/client.dart
new file mode 100644
index 00000000..e4fe74c4
--- /dev/null
+++ b/lib/client.dart
@@ -0,0 +1,30 @@
+library angel_websocket.client;
+
+import 'dart:convert' show JSON;
+import 'dart:html';
+import 'shared.dart';
+
+class Angel {
+ String wsEndPoint;
+ WebSocket _socket;
+
+ Angel(String this.wsEndPoint) {
+ _socket = new WebSocket(wsEndPoint);
+ }
+
+ AngelService service(String path) {
+ return new AngelService._base(_socket, path.trim().replaceAll(new RegExp(r'(^\/+)|(\/+$)'), ''));
+ }
+}
+
+class AngelService {
+ WebSocket _socket;
+ String path;
+
+ AngelService._base(WebSocket this._socket, path) {}
+
+ index([Map params]) {
+ AngelMessage request = new AngelMessage(path, 'index', body: params);
+ _socket.send(JSON.encode(request.toMap()));
+ }
+}
\ No newline at end of file
diff --git a/lib/server.dart b/lib/server.dart
new file mode 100644
index 00000000..dece693e
--- /dev/null
+++ b/lib/server.dart
@@ -0,0 +1,86 @@
+///Exposes WebSocket functionality to Angel.
+library angel_websocket.server;
+
+import 'dart:io';
+import 'package:angel_framework/angel_framework.dart';
+import 'shared.dart';
+
+_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') {
+ return await service.update(
+ message.body['id'], message.body['data'] ?? {}, message.body['query']);
+ }
+
+ else if (message.method == 'remove') {
+ return await service.remove(message.body['id'], message.body['query']);
+ }
+
+ 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. :)
+ }
+ };
+}
+
+websocket({String endPoint: '/ws'}) {
+ 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);
+
+ socket.listen(_handleMsg(socket, app));
+ } else {
+ throw new AngelHttpException.BadRequest(
+ message: 'This endpoint is only available via WebSockets.');
+ }
+ });
+ };
+}
\ No newline at end of file
diff --git a/lib/shared.dart b/lib/shared.dart
new file mode 100644
index 00000000..7ce9b229
--- /dev/null
+++ b/lib/shared.dart
@@ -0,0 +1,53 @@
+library angel_websocket;
+import 'dart:math';
+
+String _randomString(int length) {
+ var rand = new Random();
+ var codeUnits = new List.generate(
+ length,
+ (index){
+ return rand.nextInt(33)+89;
+ }
+ );
+
+ return new String.fromCharCodes(codeUnits);
+}
+
+/// A WebSocket message sent from server to client, or vice-versa.
+class AngelMessage {
+ String id;
+ String service;
+ String method;
+ Map body;
+
+ AngelMessage(String this.service, String this.method,
+ {Map this.body: const {}}) {
+ id = _randomString(32);
+ }
+
+ /// Parses a Map into an AngelMessage.
+ AngelMessage.fromMap(Map msg) {
+ bool invalid = !(msg['service'] is String) ||
+ (msg['service'] is String && msg['service'].isEmpty);
+ invalid = invalid || !(msg['method'] is String) ||
+ (msg['method'] is String && msg['method'].isEmpty);
+
+ if (invalid) {
+ throw new Exception("Invalid message supplied.");
+ } else {
+ this.id = _randomString(32);
+ this.service = msg['service'];
+ this.method = msg['method'];
+ this.body = msg['body'] ?? {};
+ }
+ }
+
+ Map toMap() {
+ return {
+ 'id': id,
+ 'service': service,
+ 'method': method,
+ 'body': body
+ };
+ }
+}
\ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
new file mode 100644
index 00000000..35516d53
--- /dev/null
+++ b/pubspec.yaml
@@ -0,0 +1,10 @@
+name: angel_websocket
+description: WebSocket plugin for Angel
+version: 0.0.0-dev.0
+author: thosakwe
+homepage: https://github.com/angel-dart/angel_websocket
+dependencies:
+ angel_framework: ">=0.0.0-dev < 0.1.0"
+dev_dependencies:
+ http: ">= 0.11.3 < 0.12.0"
+ test: ">= 0.12.13 < 0.13.0"
\ No newline at end of file