Skip to content

WebSocket

dox_websocket adds a WebSocket server to the Dox HTTP server. Use it for live chat, notifications and other real-time updates.

Want Socket.IO clients?

Use Socket.IO. Turn it on with AppConfig(socketIo: SocketIoConfig(enabled: true)). It runs on the same port, works with the official Socket.IO clients, and has acks and namespaces. dox_websocket keeps working next to it.

Usage

1. Create websocket service with redis adapter

class WebsocketService implements DoxService {
  @override
  void setup() {
    Redis sub = Redis();
    Redis pub = sub.duplicate();

    WebsocketServer io = WebsocketServer(Dox());
    io.adapter(WebsocketRedisAdapter(
      subscriber: sub,
      publisher: pub,
    ));
  }
}

Many isolates need Redis

Dox runs one isolate per CPU core by default. Each isolate has its own memory. Without an adapter, a room only reaches clients on the same isolate.

  • Use the Redis adapter. It needs ioredis ^2.0.0-alpha.1.
  • Or set totalIsolate: 1 in lib/config/app.dart (or APP_TOTAL_ISOLATE=1).

2. Register websocket service to dox app/config/services.dart

List<DoxService> services = <DoxService>[
  ... /// other services
  WebsocketService,
];

3. Create websocket controller

dox create:controller SocketController -ws
import 'package:dox_core/dox_core.dart';
import 'package:dox_websocket/dox_websocket.dart';

class ChatWebSocketController {
  intro(WebsocketEmitter emitter, dynamic message) {
    // sent message to chart room but exclude the sender
    emitter.room('chat').emitExceptSender('intro', message);
  }

  noti(WebsocketEmitter emitter, dynamic message) {
    // sent message to chart room including the sender
    emitter.room('chat').emit('noti', message);
  }
}

Note

As webSocket maintains an open connection, there is no requirement to send back any values from your controller method.

4. register websocket route and events

ChatWebSocketController controller = ChatWebSocketController();

Router.websocket('ws', (WebsocketEvent event) {
    // when client sent an event called `intro`, 
    // it will execute `controller.intro` method
    event.on('intro', controller.intro);

    // when client sent an event called `noti`, 
    // it will execute `controller.noti` method
    event.on('noti', controller.noti);
});

Info

You can register websocket routes on lib/routes/web.dart or you can also create custom websocket router and register in lib/config/app.dart. Both option will create a websocket url on ws://127.0.0.1:{port}/ws.

Note

You also have the option to register WebSocket routes for multiple paths, rather than just the default /ws route.

Client Usage

You have the option to utilize either the built-in browser WebSocket or any WebSocket library for clients. The key requirement is that when sending data, it must be in the form of a JSON string containing both event and message attributes. Refer to the example below for clarification.

Example with Dart

import 'dart:io';

// The event name that is listening in your routes
// Eg. DoxWebsocket.on('intro', controller.intro);
String event = 'intro';

// Message can be any type such as int, float, map, string etc..
String message = "Mingalaba!"; 


// Encoding to json formatted string
var data = jsonEncode({
    "event": event,
    "message": message,
});

String url = 'ws://localhost:3000/ws';
WebSocket socket = await WebSocket.connect(url);

socket.add(data);


// If you would like to join the room, please use event name `joinRoom`
var joinRoomData = jsonEncode({
    "event": "joinRoom",
    "message": "chat", // sent room name as message
});

// Sent message to join the chat room
socket.add(joinRoomData);

Example with javascript

For Handling with javascript, we suggested you to use below library. https://github.com/dartondox/dox-web-socket-client

import DoxWebsocket from '@dartondox/websocket';

const socket = DoxWebsocket('ws://127.0.0.1:3000/ws', {
  maxRetries: 18, retryAfter: 2000 
})

socket.onConnected(() => {
  console.log(socket.id)
})

socket.onError(() => {
  console.log('socket error')
})

// Listen in client for intro event that will sent from the server
socket.on('intro', (msg) => {
  console.log(msg)
})

socket.onClose(() => {
  console.log('socket closed')
})

function sendMessage(message) {
  socket.emit('intro', message)
}

SocketEmitter

room

Set the room before emit to client

emitter.room('chat').emit('event-name', message);

Info

Use the same name the client sent with joinRoom. room() returns a new emitter. The room does not stay set for later events.

emit

Emit to all the client connected to the same websocket route.

emitter.emit('event-name', message);

emitExceptSender

Emit to all the client connected to the same websocket route except the sender.

emitter.emitExceptSender('event-name', message);