Skip to content

Broadcast

Gerasimos (Makis) Maropoulos edited this page Aug 10, 2019 · 7 revisions

Neffos has an entirely different and much more efficient approach to broadcasting compared to alternatives that usually are hinder the whole connections list as a result not a single new client can connect or disconnect as long a message is broadcasting which it is unacceptable for high-scale systems. Neffos broadcasting system does not require blocking.

As we've seen on the Getting Started section, a client cannot directly communicate with the rest of the clients, they can communicate only through server. Therefore the only broadcaster is the Server itself. To send a message to all connections we use the Server#Broadcast(exceptConnID, neffos.Message{...}).

Message broadcasting

When we want to broadcast an incoming message except the client who sent this message through an event we use the following snippet:

neffos.Events {
    "onSomething": func(c *neffos.NSConn, msg neffos.Message) error {
        if !c.Conn.IsClient() {
            c.Conn.Server().Broadcast(c, msg)
            return nil
        }

        // [...]
    },
}

Now, as you can imagine we can pass any neffos.Message as an input argument to the Server#Broadcast method. The Message data structure looks like this:

type Message struct {
    Namespace string
    Room string
    Event string

    Body []byte
    Err error

    To string

    // [...]
}

To fire a particular remote event with a specific message body to a set of connections that are joined to a particular room inside a "default" namespace:

// [websocketServer := neffos.New...]

websocketServer.Broadcast(nil, neffos.Message{
    Namespace: "default", // <-
    Event: "toThatEvent", // <-
    Room: "room1",        // <-
    Body: []byte("the data"),
})

Let's see how we can broadcast a message to a specific connection. To send a message to a specific connection you need to know its ID and set it to the Message.To field, let's assume that ID is "X-User-1".

// [websocketServer := neffos.New...]

websocketServer.Broadcast(nil, neffos.Message{
    Namespace: "default", // <-
    Event: "toThatEvent", // <-
    Body: []byte("the data"),
    To: "X-User-1",       // <-
})

The first parameter sets whether a message should be broadcasted to all except this, i.e neffos.Exclude("connectionID") or a Conn instance. So, if it's nil it broadcasts to all connected connections based on their connected Namespace and Room (if any).

Another way to send a message to a particular client when you have access to the connection is by its Conn#Emit or Conn#Write.

There is a Server.SyncBroadcaster option field. If set to true, changes the default behavior and synchronizes Server.Broadcast calls when Server.StackExchange is nil (or Server.UseStackExchange is not used). When StackExchange is used then this field is ignored, published messages are correctly handled by Redis or Nats.

Perform connection actions outside of events

Except Server#Broadcast you can use the Server#Do method, which blocks new connections, to execute actions on connections from the server side.

// Do loops through all connected connections and fires the "fn", with this method
// callers can do whatever they want on a connection outside of a event's callback,
// but make sure that these operations are not taking long time to complete
// because it delays the new incoming connections.
// If "async" is true then this method does not block the flow of the program.
Do(fn func(*Conn), async bool)

For example to force-disconnect all clients from a namespace outside of an event callback you can use the following code:

// [websocketServer := neffos.New...]

websocketServer.Do(func(c *neffos.Conn){
    c.Namespace("default").Disconnect(context.Background())
}, false)

log.Printf("%d clients are forcely disconnected from 'default' namespace by the server.",
    websocketServer.GetTotalConnections())

Server#GetTotalConnections method returns the total number of active client connections.

Or to force-close the connections entirely:

// [websocketServer := neffos.New...]

websocketServer.Do(func(c *neffos.Conn){
    c.Close()
}, false)

log.Println("all clients are terminated by the server.")