Search code examples
javascriptangularjsclient-servercometd

How to handle broadcasting a dynamic list to javascript clients in cometd


I have a dynamic list on my web server. I would like my Javascript clients to be able to subscribe to a channel that will broadcast as items are added and taken away from the list on the server. The problem lies in how to communicate the list when a client subscribes to the channel. Ideally, the client ends up with the list of items as it is on the server, and then starts processing the adds and removes.

Given my understanding of cometd, I don't see a way to trigger a message from the server that sends the contents of the list on subscription. And if I can't do that, then I have to resort to a call to the server to a non-cometd service that sends the list. That solution leaves me with a situation in which an add or remove might be missed.

This seems to me to be a more general problem, but not something I have seen solved elsewhere.

Any input appreciated.


Solution

  • In CometD, there are two approaches that you may use to broadcast the list to clients:

    • send the whole list upon every change
    • send the whole list when a client first connects, and then send only the changes

    The first approach works well for small lists, the second for larger lists.

    I will be discussing the second approach, since the techniques used are applicable also for the first approach.

    As an example to make the code snippets clearer, let's assume that you want to send the list of members of a chat room over channel /room1/members.

    Send the whole list at subscription

    In your room configuration code, you register a SubscriptionListener to the members channel:

    private void configureRoom(String roomName) {
        final String channelName = "/" + roomName + "/members";
        ServerChannel channel = bayeuxServer.createChannelIfAbsent(channelName).getReference();
        channel.addListener(new SubscriptionListener() {
            @Override
            public void subscribed(ServerSession session, ServerChannel channel, ServerMessage message) {
                // Send back the whole list to the subscriber.
                session.deliver(sender, channelName, memberList);
            }
        });
    

    Note that here you want to use ServerSession.deliver() to send the whole list just to that subscriber: the other subscribers already have the list so there is no need to broadcast it to all subscribers.

    Send the list changes

    When the list changes, you can broadcast only the change, for example when a member leaves the chat room:

    private void memberLeft(String roomName, String memberName) { 
        int index = memberList.indexOf(memberName);
        if (index < 0) {
            return;
        }
        memberList.remove(index);
        Map<String, Object> data = new HashMap<>();
        data.put("action", "remove");
        data.put("index", index);
        String channelName = "/" + roomName + "/members";
        ServerChannel channel = bayeuxServer.getChannel(channelName);
        channel.publish(sender, data);
    }
    

    Note that here you want to use ServerChannel.publish() to broadcast the change to all subscribers.

    The client will see two types of messages arriving on channel /room1/members: one whose data is a list of strings - and then it will know it's the whole list, and one whose data is an object - and then it will know it's a list change.

    For the latter, the data will have an action field that tells what action needs to be performed and an index fields that tells at what index you need to operate. The format of these two messages is entirely up to you.

    Coping with network interruptions

    It could happen that the server sends a list change while the client is temporarily offline. For this scenario, CometD offers the message acknowledgement extension, which offers server-to-client guaranteed message delivery.

    For longer offline periods, the client will re-handshake with the server, and therefore it will get the full list upon resubscription. Please follow the guidelines described at this section of the CometD documentation.