Listen to messages with multiple customers(pub/sub)

Asked

Viewed 336 times

0

If I want to be able to have multiple users and channels, do I need to have each user create a client in redis (or whatever the pub/sub used) to subscribe to the channel? And how would you get the messages? I am thinking this way, clients redis-pub/sub would need to be at the level where the websocket server is, because the client server communication would only be by websocket, I do not know what pub/sub uses for communication, but I am only wanting websocket between client and server, and redis(database + pub/sub) communicating locally within the server:

'use strict';

//CREATE WEB SERVER
var express = require('express');
var app = express();
var http = require('http').Server(app);
//CREATE WS
const WebSocket = require('ws');
const wss = new WebSocket.Server({ server: http, port: 8080 });
//CREATE REDIS
var redis = require('redis');
var redisClient = redis.createClient({host : 'localhost', port : 6379});

var clients = {};

wss.on('connection', function connection(ws) {
    ws.on('message', function incoming(message) {
         // Aqui dependendo de certa mensagem recebida,
         // como um login por exemplo, eu faria algo assim:
         ws['user'] = obj.login.user.toString();
         //CRIAR UM NOVO CLIENTE REDIS SUBS
        clients[obj.login.user.toString()]['cliRedis'] = redis.createClient({host : 'localhost', port : 6379});
        // SE INSCREVER NO CANAL 
        clients[obj.login.user.toString()]['cliRedis'].subscribe();
    });

   if("user" in ws) {
        clients[ws.user]['cliRedis'].on("message", function(channel, message) {
             console.log("Msg on subscriber: " + message);
             //aqui enviaria os dados por websocket para o cliente
        });
   }
});

Up 1:

With the reply and comments of @rodorgas I was able to clarify a lot what I have to do. So I came to the conclusion that there are two possibilities, for the various customers to be able to listen to the messages sent by the pub/sub system:

1 - Using Centrifuge as indicated in the @rodorgas response:

inserir a descrição da imagem aqui

2 - Using the pub/sub redis:

inserir a descrição da imagem aqui

Comparisons:

Way 1 would have to have two active websockets connections, one for Centrifuge and one for Ws-server, at least I didn’t find anything in the Centrifuge documentation where I can handle messages that aren’t specific to the pub/sub, something like centrifuge-server.on("message", then I think it would even take two websockect connections in that mode. Then both would spend almost the same amount of sockets, because the sockets necessary for communication of pub/sub redis that would be won using the way 1, are lost having to open a new connection for communication with the client-Odot. The advantage of the way 1 is that it seems to be easier to understand, because the pub/sub client is even in the client, which does not even exist in fact, because Centrifugo only requires messages by websocket, there is no cli-Centrifugo as there is a cli-redis, the client-centrifuge is just the client-Godot sending messages via websocket. Already the way 2 clients-redis would be stored inside a javascript object in the nodejs script. Way 1 I will have to send messages in Centrifuge pattern that are big compared to what I can do by sending in Way 2.

Anyway, I’m wondering which way to start implementing, maybe I’ll do both and pick the one that’s faster. Anyway I’m running out of time in the next few days to start working on it, so I still have time to think about what to do.

Completion:

I chose to implement with the pub/sub redis, so I studied I would have more control over what I am doing. But I did not rule out Centrifugo, it will serve me very well if I come to implement a chat in the game, because it is very good for this task, with it I have like, for example, create private conversations between only two clients, among other facilities that are already implemented for you to use.

  • Do you want to distribute messages to people through the browser? I don’t know how the redis pubsub is going to help you with this, because it’s not a web technology. It would be useful if you wanted to distribute messages to native servers or applications. In what appears to be your case, only websocket is sufficient. And maybe you want to use the socket.io instead of ws (as the socket.io implements several fallbacks).

  • I don’t think I could pass on what I want very well, the messages from the pub/sub would not go directly to the customer, there would arrive the message and by websocket would go to the client, I will even edit.

  • What I want: to create channels that are "pieces of the map" and all the players that are in this piece will hear the messages from this channel, my doubt is if I’m doing right above, creating the clients and storing in the server script. It would be: client sends message by websocket to the server, the server saved in the database/cache, client enters a channel where will be listening to the messages, redis pub/sub sends message searched in the database/cache, and so is sent via websocket to the client.

  • Under " client sends message by websocket", the client is the browser. Under "client enters a channel ..." the client is the server in Node-js. It’s confusing. But I guess that’s right.

  • I’m sorry, it is. Yes in "client sends message by webscoket" he is the browser. And "client enters a channel" it is the redis client that is on the same server, within var clients, and that’s where it comes in doubt, I really have to create a redis client for each websocket client?

  • The two questions. 1 - Do I have to create a redis client for each websocket client? if yes, enter the question 2 - The way(... clients[ws.user]['cliRedis'].on("message" ...) as I am listening to the above messages is correct?

    1. Are you sure you need redis/pubsub? Who will generate the messages? You can send websocket messages straight from the backend, using multiple languages. For the purpose you described, I would not use redis no. Take a look at the diagram of centrifuge, Isn’t that all you need? Of course you can do it using redis but it looks like a loop in circles, maybe I’m not understanding your architecture. Who will generate the messages? 2. I have no experience with this library.
  • i am already using redis as cache for information, the pub/sub would be for channels, it is necessary, if not would have to send update message of the position of everyone online on the server to everyone, which would be bad.

  • I have the client-game(can call browser) that connects to the server, when this happens, is created a cli-redis for it, the client-game sends its position to the server by websocket, then the server saved in redis that information, cli-redis subscribes to a channel that is the area around it, so it only interests you information in that area, avoiding unnecessary information to be sent. Another client-game connects in the same area, creates another cli-redis for it, which will enter the same channel, so each gets the position of the other, synchronizing their positions in the game.

Show 4 more comments

1 answer

1

The Centrifuge is a pubsub server, it "creates channels" in websocket (actually it’s an abstraction layer, it takes care of unique users and allows you to group them into channels). This without having the redis as intermediary.

So let’s assume that your map is divided into sectors. The intention is to deliver a message to thousands of players who are in the (1.1) sector of the map. Put it like this in the browser:

<script type="text/javascript">

    var centrifuge = new Centrifuge({
        url: 'http://localhost:8000/connection',
        user: "USER ID",
        timestamp: "UNIX TIMESTAMP SECONDS",
        token: "SHA-256 HMAC TOKEN"
    });

    // inscreva o usuário no setor correspondente
    centrifuge.subscribe("(1,1)", function(message) {
        console.log(message);
    });

    centrifuge.connect();

</script>

In the backend, on the server side. Send a message like this (to assuming backend in nodejs, but centrifuge supports multiple languages):

Client = require("jscent");

var c = new Client({url: "http://localhost:8000", secret: "secret"});

c.publish("(1,1)", {"input": "test"}, function(err, resp){console.log(err, resp)});

When your game is huge and you have many servers, you put the redis in the parade. Centrifuge uses redis to load Alancing, for example, in high-scale situations.

Maybe someone comes up with an idea using the redis in the middle. But I see that the redis will always stay in the middle: you will need to pass to the browser later. The Centrifuge actually already solves it in one shot. I would use it.

  • now understood, but I would not give for me to use the Centrifugo, because the client-game actually is not a browser, said "browser" just to make it clear that it was not the client-redis, then there would be no such library Centrifugo, the client am doing in Godot(game engine), unless I make a module for the centrifuge, but as I have already saved the customer data in redis, I think it would be a lot of work to make a module for this, so I had the idea of using cli-redis in the backend.

  • But does this Godot support websockets? Does it support javascript? You program in it in what language?

  • No, I’m having to use a websocket module, but Godot 3 will have to implement webscoket. It does not support javascript, it uses its own scripting language called Gdscript. I had thought to do so by putting the cli-redis in the client-game. But you would have to create a module for that too, so deal with cli-redis in the backend.

  • Look what it says here "Connections can use Pure Websockets Protocol" doesn’t need Centrifuge.js https://fzambia.gitbooks.io/centrifugal/content/server/index.html If you really don’t want to use centrifuge, you’ll basically end up rewriting something like what it already does. At least you can look at the source code and copy a little hehe.

  • And this way using Centrifuge, the data is not being saved, which I also need to anyway send to a database first.

  • Redis pubsub does not save anything, anyway

  • yes, but redis yes, I’m sending information to redis cache/persistence, where I look to send to customers with pubsub.

  • You cannot send to the redis and to the centrifuge simultaneously?

  • That’s what I thought now, and I was typing kkkkk is what I could do, and maybe it would be faster. But you’d have a problem, sometimes you’d have to search the database and send it to Centrifuge the same way, not everything would always be accessible in the game scene. The project is in dire need of a database, because all for noise and changes are saved in the redis. I think there is no way, will have to go in the bank anyway, so I chose the redis, at least would be in memory, but fast.

  • kind of here c.publish("(1,1)",{ Where would you get the information to send to the channel? That’s where the redis database comes in, but using Centrifuge, I wouldn’t have to do all the work with the redis pub/sub, less sockets being used, since Centrifuge sends via websocket. Anyway the redis would be there as cache/bd, but I really prefer to leave the client in the client. I will study this Centrifuge, I think I will use it. Does it work as the pub/sub redis to subscribe/delete etc on the channels? because it would need to change several times, since the players move and change channels.

  • The problem with using Centrifuge is that the messages it sends/receives are too big. With pub/redis sub I would have control over how to create the message, and reduce the maximum. With him, I lose control, because I have to follow his pattern, but if it doesn’t bother me, I don’t care, I have to test and see how it goes. I think I will implement both ways, using the pub/sub redis and the Centrifuge, which get better I use.

Show 6 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.