Gateways
Gateways are a way to create real-time applications using WebSockets. Most of the concepts discussed before in the documentation, such as dependency injection, pipes and exception filters apply to gateways as well.
In Serinus, a gateway is a class that extends the WebSocketGateway class. The WebSocketGateway class is a special type of provider that is used to handle WebSocket connections. Right now Serinus supports only basic WebSocket connections, but in the future, other protocols such as Socket.IO will be supported as well.
INFO
Since Gatways are a special type of provider, they can be injected into other providers, such as services and controllers.
Getting Started
First of all let's create a WebSocketGateway. To do so, we need to create a class that extends the WebSocketGateway class.
import 'package:serinus/serinus.dart';
class MyGateway extends WebSocketGateway {
}In general all the classes created as before are listening on the same port as the underlying HTTP server. If you want to listen on a different port, you can specify the port in the constructor of the WebSocketGateway class or by overriding the port getter.
import 'package:serinus/serinus.dart';
class MyGateway extends WebSocketGateway {
MyGateway();
@override
int get port => 3001;
}If the port of the gateway is different from the port of the HTTP server, a new server will be created to handle the WebSocket connections.
Now that we have created a gateway, we need to register it in a module.
import 'package:serinus/serinus.dart';
import 'my_gateway.dart';
class AppModule extends Module {
AppModule() : super(
imports: [
WsModule(),
]
providers: [
MyGateway(),
],
);
}As you can see, we need to import the WsModule in order to use WebSocket gateways. Now that we have registered the gateway, we can start using it.
Sending and Receiving Messages
To receive messages from the client, we need to override the onMessage method. The onMessage method is called whenever a message is received from the client.
import 'package:serinus/serinus.dart';
class MyGateway extends WebSocketGateway {
@override
void onMessage(dynamic data, WebSocketContext context) {
// Handle incoming messages
}
}The onMessage method receives two parameters: the data parameter contains the message sent by the client, while the context parameter contains information about the connection, such as the client ID and the request context.
You can either send text or binary messages to the client using the sendText and sendBinary methods of the WebSocketContext class. You can also broadcast messages to all connected clients using the broadcastText and broadcastBinary methods.
import 'package:serinus/serinus.dart';
class MyGateway extends WebSocketGateway {
@override
Future<void> onMessage(dynamic data, WebSocketContext context) async {
// Send a message to all connected clients
context.broadcastText('Hello from the server!');
// Send a message to a specific client
context.sendText('Hello client!');
}
}Lifecycle Events
You can also listen to lifecycle events of the WebSocket connection by augmenting the class with the mixins:
| Mixin | Description |
|---|---|
| OnClientConnect | Called when the gateway is initialized. |
| OnClientDisconnect | Called when a client disconnects from the gateway. |
| OnClientError | Called when an error occurs on the client. |
import 'package:serinus/serinus.dart';
class MyGateway extends WebSocketGateway with OnClientConnect, OnClientDisconnect, OnClientError {
@override
void onClientConnect(WebSocketContext context) {
print('Client connected: ${context.clientId}');
}
@override
void onClientDisconnect(WebSocketContext context) {
print('Client disconnected: ${context.clientId}');
}
@override
void onClientError() {
print('An error occurred');
}
}Dependency Injection
Since gateways are providers, they can be called from other providers and controllers. They can also have dependencies injected into them using the constructor.
import 'package:serinus/serinus.dart';
class MyService extends Provider {
void doSomething() {
print('Doing something...');
}
}
class MyGateway extends WebSocketGateway {
final MyService myService;
MyGateway(this.myService);
@override
void onMessage(dynamic data, WebSocketContext context) {
myService.doSomething();
}
}
class AppModule extends Module {
AppModule() : super(
imports: [WsModule()],
providers: [
MyService(),
Provider.composed<MyGateway>(
(CompositionContext context) async => MyGateway(context.use<MyService>()),
inject: [MyService]
),
],
);
}