简体   繁体   中英

Sending subsets of streaming data to Node clients using Sockets.io

I have a Node server which sends streaming tweets to clients as they connect, using Sockets.io and ntwitter. At the moment all the tweets (from different users) get sent to every client. But each client only requires a certain subset of tweets, and I'd like to the server to only send that subset (or category).

I think that having each category being like a room, in Sockets, would work, but I can't quite work out how to adapt my code to use them. Or, given that there's no communication between clients, maybe that's not the best solution?

The relevant, simplified, bits of current code...

Client:

var socket = io.connect(window.location.hostname);

socket.on('messages', function(messages_packet) {
    $.each(messages_packet, function(idx, tweet) {
        if (tweet_is_in_this_clients_category(tweet)) {
            display_messages(messages_packet);
        };
    }
});

Server:

// [A function which, on start-up, fetches existing tweets and caches them.]

// Send cached messages when a client connects.
sockets.sockets.on('connection', function(socket) {
    socket.emit('messages', cached_messages);
});

// Fetch tweets from the stream, and send new ones to clients.
twitter.stream('statuses/filter', {follow: [12345, 345678, etc]}, function(stream) {
    stream.on('data', function(tweet) {
        add_tweet_to_cache(tweet);
        sockets.sockets.emit('messages', [tweet]);
    }
});

So, the sockets.emit() part is currently sending every tweet to all the clients. And then the client decides whether to show that tweet, if it's in the client's category. It would obviously be more efficient if the server only sent tweets to the clients in the correct category. Given the server already knows which tweets are in which categories, how do I only emit them to those categories, rather than every client?

After some trial and error I seem to have it working. No idea if this is the best or correct way, but... the above code has been tweaked so it's now something like that shown below. There's one addition to the client code, and two to the server code.

Client:

var socket = io.connect(window.location.hostname);
// NEW CLIENT PART:
socket.on('connect', function(){
    // room_name was created based on the URL this page was requested at:
    socket.emit('subscribe', room_name);
};

socket.on('messages', function(messages_packet) {
    $.each(messages_packet, function(idx, tweet) {
        if (tweet_is_in_this_clients_category(tweet)) {
            display_messages(messages_packet);
        };
    }
});

Server:

// [A function which, on start-up, fetches existing tweets and caches them.]

// Send cached messages when a client connects.
sockets.sockets.on('connection', function(socket) {
    // NEW SERVER PART 1:
    socket.on('subscribe', function(room_name) {
        socket.join(room_name);
        socket.emit('messages', cached_messages_for_this_room);
    });
});

// Fetch tweets from the stream, and send new ones to clients.
twitter.stream('statuses/filter', {follow: [12345, 345678, etc]}, function(stream) {
    stream.on('data', function(tweet) {
        add_tweet_to_cache(tweet);
        // NEW SERVER PART 2:
        // Gets the array of room_names this twitter account is associated with:
        var rooms = get_rooms_for_twitter_account(tweet.user.screen_name);
        rooms.forEach(
            function(room_name) {
                sockets.sockets.in(room_name).emit('messages', [tweet]);
            };
        );
    };
});

So, when a client connects it sends a 'subscribe' message, and the name of the room it wants to join.

When the server receives a 'subscribe' event it sends only the existing tweets associated with that room (the logic for getting that list of tweets is done elsewhere; not relevant to this particular issue).

And whenever a new tweet is picked up by the server, it finds the room(s) this tweet is associated with, and then emits the tweet to every client in each of them.

This seems to work... do point out anything that makes no sense, or could be done much better!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM