2024-10-12 10:35:14 +00:00
# Protevus Websocket
2021-07-10 04:32:42 +00:00
2021-09-25 06:32:32 +00:00
![Pub Version (including pre-releases) ](https://img.shields.io/pub/v/angel3_websocket?include_prereleases )
2021-05-15 07:19:35 +00:00
[![Null Safety ](https://img.shields.io/badge/null-safety-brightgreen )](https://dart.dev/null-safety)
2024-07-07 15:02:49 +00:00
[![Discord ](https://img.shields.io/discord/1060322353214660698 )](https://discord.gg/3X6bxTUdCM)
2024-10-12 10:35:14 +00:00
[![License ](https://img.shields.io/github/license/dart-backend/protevus )](https://github.com/dart-backend/protevus/tree/master/packages/websocket/LICENSE)
2016-12-24 01:45:52 +00:00
2024-10-12 10:35:14 +00:00
WebSocket plugin for Protevus framework. This plugin broadcasts events from hooked services via WebSockets. In addition, it adds itself to the app's IoC container as `AngelWebSocket` , so that it can be used in controllers as well.
2016-09-17 20:00:17 +00:00
2016-12-24 01:45:52 +00:00
WebSocket contexts are add to `req.properties` as `'socket'` .
2016-09-03 12:34:01 +00:00
2021-07-10 04:32:42 +00:00
## Usage
2016-09-03 12:34:01 +00:00
2021-07-10 04:32:42 +00:00
### Server-side
2016-09-03 12:34:01 +00:00
```dart
2021-05-15 07:19:35 +00:00
import "package:angel3_framework/angel3_framework.dart";
import "package:angel3_websocket/server.dart";
2016-09-03 12:34:01 +00:00
2021-07-10 04:32:42 +00:00
void main() async {
2021-05-15 07:19:35 +00:00
var app = Angel();
2017-02-22 22:34:35 +00:00
2021-05-15 07:19:35 +00:00
var ws = AngelWebSocket();
2017-09-24 04:37:58 +00:00
2017-11-18 05:15:29 +00:00
// This is a plug-in. It hooks all your services,
// to automatically broadcast events.
2017-09-24 04:37:58 +00:00
await app.configure(ws.configureServer);
// Listen for requests at `/ws` .
app.all('/ws', ws.handleRequest);
2016-09-03 12:34:01 +00:00
}
```
2021-07-10 04:32:42 +00:00
Filtering events is easy with hooked services. Just return a `bool` , whether synchronously or asynchronously.
2017-01-29 20:02:19 +00:00
```dart
2017-04-10 01:45:45 +00:00
myService.properties['ws:filter'] = (HookedServiceEvent e, WebSocketContext socket) async {
2017-01-29 20:02:19 +00:00
return true;
}
2017-06-30 23:09:03 +00:00
myService.index({
'ws:filter': (e, socket) => ...;
});
2017-01-29 20:02:19 +00:00
```
2021-07-10 04:32:42 +00:00
#### Adding Handlers within a Controller
2016-09-18 01:35:16 +00:00
2016-09-18 02:53:58 +00:00
`WebSocketController` extends a normal `Controller` , but also listens to WebSockets.
2016-09-18 01:35:16 +00:00
```dart
import 'dart:async';
2021-07-10 04:32:42 +00:00
import "package:angel3_framework/angel3_framework.dart";
import "package:angel3_websocket/server.dart";
2016-09-18 01:35:16 +00:00
@Expose ("/")
2016-09-18 02:53:58 +00:00
class MyController extends WebSocketController {
2017-11-18 05:15:29 +00:00
// A reference to the WebSocket plug-in is required.
MyController(AngelWebSocket ws):super(ws);
2016-09-18 01:35:16 +00:00
@override
2016-09-18 02:53:58 +00:00
void onConnect(WebSocketContext socket) {
// On connect...
}
// Dependency injection works, too..
@ExposeWs ("read_message")
2017-04-17 18:19:27 +00:00
void sendMessage(WebSocketContext socket, WebSocketAction action, Db db) async {
2017-04-17 12:37:17 +00:00
socket.send(
"found_message",
db.collection("messages").findOne(where.id(action.data['message_id'])));
2016-09-18 01:35:16 +00:00
}
2017-01-29 20:02:19 +00:00
// Event filtering
@ExposeWs ("foo")
void foo() {
2021-05-15 07:19:35 +00:00
broadcast( WebSocketEvent(...), filter: (socket) async => ...);
2017-01-29 20:02:19 +00:00
}
2016-09-18 01:35:16 +00:00
}
```
2021-07-10 04:32:42 +00:00
### Client Use
2017-04-17 18:20:32 +00:00
2021-07-10 04:32:42 +00:00
This repo also provides two client libraries `browser` and `io` that extend the base `angel3_client` interface, and allow you to use a very similar API on the client to that of the server.
2017-04-17 12:37:17 +00:00
2021-07-10 04:32:42 +00:00
The provided clients also automatically try to reconnect their WebSockets when disconnected, which means you can restart your development server without having to reload browser windows.
2017-04-17 12:37:17 +00:00
They also provide streams of data that pump out filtered data as it comes in from the server.
Clients can even perform authentication over WebSockets.
2021-07-10 04:32:42 +00:00
#### In the Browser
2016-09-03 12:34:01 +00:00
```dart
2021-05-15 07:19:35 +00:00
import "package:angel3_websocket/browser.dart";
2016-09-03 12:34:01 +00:00
2021-07-10 04:32:42 +00:00
void main() async {
2021-05-15 07:19:35 +00:00
Angel app = WebSockets("/ws");
2016-12-24 01:45:52 +00:00
await app.connect();
2016-09-03 12:34:01 +00:00
var Cars = app.service("api/cars");
2017-12-21 20:15:47 +00:00
Cars.onCreated.listen((car) => print("New car: $car"));
2016-09-03 12:34:01 +00:00
// Happens asynchronously
Cars.create({"brand": "Toyota"});
2016-12-24 01:45:52 +00:00
2017-02-28 14:15:34 +00:00
// Authenticate a WebSocket, if you were not already authenticated...
app.authenticateViaJwt('< some-jwt > ');
2016-12-24 01:45:52 +00:00
// Listen for arbitrary events
app.on['custom_event'].listen((event) {
// For example, this might be sent by a
// WebSocketController.
print('Hi!');
});
2016-09-03 12:34:01 +00:00
}
```
2021-07-10 04:32:42 +00:00
#### CLI Client
2016-09-03 12:34:01 +00:00
```dart
2021-05-15 07:19:35 +00:00
import "package:angel3_framework/common.dart";
import "package:angel3_websocket/io.dart";
2016-09-03 12:34:01 +00:00
// You can include these in a shared file and access on both client and server
2017-04-17 12:37:17 +00:00
class Car extends Model {
2016-09-03 12:34:01 +00:00
int year;
String brand, make;
Car({this.year, this.brand, this.make});
@override String toString() => "$year $brand $make";
}
2021-09-25 06:32:32 +00:00
void main() async {
2021-05-15 07:19:35 +00:00
Angel app = WebSockets("/ws");
2016-12-24 01:45:52 +00:00
2016-09-17 20:00:17 +00:00
// Wait for WebSocket connection...
await app.connect();
2016-12-24 01:45:52 +00:00
2016-09-03 12:34:01 +00:00
var Cars = app.service("api/cars", type: Car);
2017-12-21 20:15:47 +00:00
Cars.onCreated.listen((Car car) {
2016-09-03 12:34:01 +00:00
// Automatically deserialized into a car :)
2017-12-21 20:15:47 +00:00
//
2016-09-03 12:34:01 +00:00
// 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"});
2017-02-28 14:15:34 +00:00
// Authenticate a WebSocket, if you were not already authenticated...
app.authenticateViaJwt('< some-jwt > ');
2021-07-10 04:32:42 +00:00
}
2021-09-25 06:32:32 +00:00
```