Readme
This commit is contained in:
parent
bdb9ad4fcd
commit
29a682cce8
9 changed files with 73 additions and 125 deletions
65
README.md
65
README.md
|
@ -1,2 +1,67 @@
|
||||||
# angel_websocket
|
# angel_websocket
|
||||||
WebSocket plugin for Angel. Features JWT support.
|
WebSocket plugin for Angel. Features JWT support.
|
||||||
|
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
**Server-side**
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import "package:angel_framework/angel_framework.dart";
|
||||||
|
import "package:angel_websocket/server.dart";
|
||||||
|
|
||||||
|
main() async {
|
||||||
|
var app = new Angel();
|
||||||
|
await app.configure(new AngelWebSocket("/ws"));
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
**In the Browser**
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import "package:angel_websocket/browser.dart";
|
||||||
|
|
||||||
|
main() async {
|
||||||
|
Angel app = new WebSocketClient("/ws");
|
||||||
|
var Cars = app.service("api/cars");
|
||||||
|
|
||||||
|
Cars.onCreated.listen((e) => print("New car: ${e.data}"));
|
||||||
|
|
||||||
|
// Happens asynchronously
|
||||||
|
Cars.create({"brand": "Toyota"});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**CLI Client**
|
||||||
|
|
||||||
|
```dart
|
||||||
|
import "package:angel_framework/angel_framework" as srv;
|
||||||
|
import "package:angel_websocket/browser.dart";
|
||||||
|
|
||||||
|
// You can include these in a shared file and access on both client and server
|
||||||
|
class Car extends srv.Model {
|
||||||
|
int year;
|
||||||
|
String brand, make;
|
||||||
|
|
||||||
|
Car({this.year, this.brand, this.make});
|
||||||
|
|
||||||
|
@override String toString() => "$year $brand $make";
|
||||||
|
}
|
||||||
|
|
||||||
|
main() async {
|
||||||
|
Angel app = new WebSocketClient("/ws");
|
||||||
|
var Cars = app.service("api/cars", type: Car);
|
||||||
|
|
||||||
|
Cars.onCreated.listen((e) {
|
||||||
|
// Automatically deserialized into a car :)
|
||||||
|
Car car = e.data;
|
||||||
|
|
||||||
|
// I just bought a new 2016 Toyota Camry!
|
||||||
|
print("I just bought a new $car!");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Happens asynchronously
|
||||||
|
Cars.create({"year": 2016, "brand": "Toyota", "make": "Camry"});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -14,4 +14,4 @@ class WebSocketAction {
|
||||||
var params;
|
var params;
|
||||||
|
|
||||||
WebSocketAction({String this.id, String this.eventName, this.data, this.params});
|
WebSocketAction({String this.id, String this.eventName, this.data, this.params});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:convert';
|
||||||
import 'dart:html';
|
import 'dart:html';
|
||||||
import 'package:angel_client/angel_client.dart';
|
import 'package:angel_client/angel_client.dart';
|
||||||
import 'package:angel_websocket/angel_websocket.dart';
|
import 'package:angel_websocket/angel_websocket.dart';
|
||||||
|
export 'package:angel_client/angel_client.dart';
|
||||||
export 'package:angel_websocket/angel_websocket.dart';
|
export 'package:angel_websocket/angel_websocket.dart';
|
||||||
|
|
||||||
class WebSocketClient extends Angel {
|
class WebSocketClient extends Angel {
|
||||||
|
|
|
@ -5,6 +5,8 @@ import 'package:angel_client/angel_client.dart';
|
||||||
import 'package:angel_framework/angel_framework.dart' as srv;
|
import 'package:angel_framework/angel_framework.dart' as srv;
|
||||||
import 'package:angel_websocket/angel_websocket.dart';
|
import 'package:angel_websocket/angel_websocket.dart';
|
||||||
import 'package:json_god/json_god.dart' as god;
|
import 'package:json_god/json_god.dart' as god;
|
||||||
|
export 'package:angel_client/angel_client.dart';
|
||||||
|
export 'package:angel_websocket/angel_websocket.dart';
|
||||||
|
|
||||||
class WebSocketClient extends Angel {
|
class WebSocketClient extends Angel {
|
||||||
WebSocket _socket;
|
WebSocket _socket;
|
|
@ -7,6 +7,7 @@ import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:json_god/json_god.dart' as god;
|
import 'package:json_god/json_god.dart' as god;
|
||||||
import 'package:merge_map/merge_map.dart';
|
import 'package:merge_map/merge_map.dart';
|
||||||
import 'angel_websocket.dart';
|
import 'angel_websocket.dart';
|
||||||
|
export 'angel_websocket.dart';
|
||||||
|
|
||||||
part 'websocket_context.dart';
|
part 'websocket_context.dart';
|
||||||
|
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
library angel_websocket.server;
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
|
||||||
import 'package:json_god/json_god.dart' as god;
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
import 'angel_websocket.dart';
|
|
||||||
|
|
||||||
typedef Future<bool> WebSocketFilter(WebsocketContext context);
|
|
||||||
|
|
||||||
List<WebsocketContext> _clients = [];
|
|
||||||
Uuid _uuid = new Uuid();
|
|
||||||
|
|
||||||
class WebsocketContext {
|
|
||||||
WebSocket socket;
|
|
||||||
RequestContext request;
|
|
||||||
ResponseContext response;
|
|
||||||
|
|
||||||
WebsocketContext(WebSocket this.socket, RequestContext this.request,
|
|
||||||
ResponseContext this.response);
|
|
||||||
}
|
|
||||||
|
|
||||||
_broadcast(WebSocketEvent event) {
|
|
||||||
String json = god.serialize(event);
|
|
||||||
_clients.forEach((WebsocketContext client) {
|
|
||||||
client.socket.add(json);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_onData(Angel app) {
|
|
||||||
return (data) {
|
|
||||||
try {
|
|
||||||
WebSocketAction action = god.deserialize(
|
|
||||||
data, outputType: WebSocketAction);
|
|
||||||
|
|
||||||
List<String> split = action.eventName.split("::");
|
|
||||||
|
|
||||||
if (split.length >= 2) {
|
|
||||||
Service service = app.service(split[0]);
|
|
||||||
|
|
||||||
if (service != null) {
|
|
||||||
String event = split[1];
|
|
||||||
|
|
||||||
if (event == "index") {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_onError(e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class websocket {
|
|
||||||
static Map<String, WebSocketFilter> filters = {};
|
|
||||||
|
|
||||||
call({List<Pattern> endPoints: const['/ws']}) {
|
|
||||||
return (Angel app) async {
|
|
||||||
for (Pattern endPoint in endPoints) {
|
|
||||||
app.all(endPoint, (RequestContext req, ResponseContext res) async {
|
|
||||||
if (!WebSocketTransformer.isUpgradeRequest(req.underlyingRequest)) {
|
|
||||||
res.write("This endpoint is only accessible via WebSockets.");
|
|
||||||
res.end();
|
|
||||||
} else {
|
|
||||||
res
|
|
||||||
..willCloseItself = true
|
|
||||||
..end();
|
|
||||||
WebSocket socket = await WebSocketTransformer.upgrade(
|
|
||||||
req.underlyingRequest);
|
|
||||||
WebsocketContext context = new WebsocketContext(socket, req, res);
|
|
||||||
_clients.add(context);
|
|
||||||
|
|
||||||
socket.listen(_onData(app), onError: _onError, onDone: () {
|
|
||||||
_clients.remove(context);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.services.forEach((Pattern path, Service service) {
|
|
||||||
if (service is HookedService) {
|
|
||||||
String pathName = (path is RegExp) ? path.pattern : path;
|
|
||||||
List<HookedServiceEventDispatcher> dispatchers = [
|
|
||||||
service.afterIndexed,
|
|
||||||
service.afterCreated,
|
|
||||||
service.afterRead,
|
|
||||||
service.afterModified,
|
|
||||||
service.afterUpdated,
|
|
||||||
service.afterRemoved
|
|
||||||
];
|
|
||||||
|
|
||||||
for (HookedServiceEventDispatcher dispatcher in dispatchers) {
|
|
||||||
dispatcher.listen((HookedServiceEvent event) async {
|
|
||||||
bool canContinue = true;
|
|
||||||
String filterName = "$pathName::${event.eventName}";
|
|
||||||
WebSocketFilter filter = filters[filterName];
|
|
||||||
|
|
||||||
for (WebsocketContext client in _clients) {
|
|
||||||
if (filter != null)
|
|
||||||
canContinue = await filter(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canContinue) {
|
|
||||||
WebSocketEvent socketEvent = new WebSocketEvent(eventName: filterName,
|
|
||||||
data: event.result);
|
|
||||||
_broadcast(socketEvent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,4 +14,4 @@ class WebSocketContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
sendError(AngelHttpException error) => send("error", error);
|
sendError(AngelHttpException error) => send("error", error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: angel_websocket
|
name: angel_websocket
|
||||||
description: WebSocket plugin for Angel
|
description: WebSocket plugin for Angel
|
||||||
version: 1.0.0-dev+1
|
version: 1.0.0-dev+2
|
||||||
author: thosakwe <thosakwe@gmail.com>
|
author: thosakwe <thosakwe@gmail.com>
|
||||||
homepage: https://github.com/angel-dart/angel_websocket
|
homepage: https://github.com/angel-dart/angel_websocket
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:angel_framework/angel_framework.dart' as server;
|
import 'package:angel_framework/angel_framework.dart' as server;
|
||||||
import 'package:angel_websocket/client.dart' as client;
|
import 'package:angel_websocket/cli.dart' as client;
|
||||||
import 'package:angel_websocket/angel_websocket.dart';
|
|
||||||
import 'package:angel_websocket/server.dart';
|
import 'package:angel_websocket/server.dart';
|
||||||
import 'package:json_god/json_god.dart' as god;
|
import 'package:json_god/json_god.dart' as god;
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
Loading…
Reference in a new issue