Atmosphere: Multiple subscriptions over single HttpConnection
Asked Answered
P

1

6

I'm using Atmosphere in my Spring MVC app to facilitate push, using a streaming transport.

Throughout the lifecycle of my app, the client will subscribe and unsubscribe for many different topics.

Atmosphere seems to use a single http connection per subscription - ie., every call to $.atmosphere.subscribe(request) creates a new connection. This quickly exhausts the number of connections allowed from the browser to the atmosphere server.

Instead of creating a new resource each time, I'd like to be able to add and remove the AtmosphereResource to broadcasters after it's initial creation.

However, as the AtmosphereResource is a one-to-one representation of the inbound request, each time the client sends a request to the server, it arrives on a new AtomsphereResource, meaning I have no way to reference the original resource, and append it to the topic's Broadcaster.

I've tried using both $.atmosphere.subscribe(request) and calling atmosphereResource.push(request) on the resource returned from the original subscribe() call. However, this made no difference.

What is the correct way to approach this?

Plemmons answered 30/11, 2012 at 2:20 Comment(2)
I have exactly the same question: client subscribes to many broadcasters over one connection, with client adding and removing broadcasters at will. I didn't get as far as you in my tests though. Did you get any further with this? Surely it should be possible? Did you try the mailing list?Vying
@Vying Yep, got it going, thanks to some pointers from the guys on the IRC channel. Posted my solution below.Plemmons
P
9

Here's how I got it working:

First, when the client does their initial connect, ensure that the atmosphere-specific headers are accepted by the browser before calling suspend():

@RequestMapping("/subscribe")
public ResponseEntity<HttpStatus> connect(AtmosphereResource resource)
{
    resource.getResponse().setHeader("Access-Control-Expose-Headers", ATMOSPHERE_TRACKING_ID + "," + X_CACHE_DATE);
    resource.suspend();
}

Then, when the client sends additional subscribe requests, although they come in on a different resource, they contain the ATMOPSHERE_TRACKING_ID of the original resource. This allows you to look it up via the resourceFactory:

@RequestMapping(value="/subscribe", method=RequestMethod.POST)
public ResponseEntity<HttpStatus> addSubscription(AtmosphereResource resource, @RequestParam("topic") String topic)
{
    String atmosphereId = resource.getResponse().getHeader(ATMOSPHERE_TRACKING_ID);
    if (atmosphereId == null || atmosphereId.isEmpty())
    {
        log.error("Cannot add subscription, as the atmosphere tracking ID was not found");
        return new ResponseEntity<HttpStatus>(HttpStatus.BAD_REQUEST);
    }
    AtmosphereResource originalResource = resourceFactory.find(atmosphereId);
    if (originalResource == null)
    {
        log.error("The provided Atmosphere tracking ID is not associated to a known resource");
        return new ResponseEntity<HttpStatus>(HttpStatus.BAD_REQUEST);
    }

    Broadcaster broadcaster = broadcasterFactory.lookup(topic, true);
    broadcaster.addAtmosphereResource(originalResource);
    log.info("Added subscription to {} for atmosphere resource {}",topic, atmosphereId);

    return getOkResponse();
}
Plemmons answered 13/12, 2012 at 19:55 Comment(2)
'resource.getResponse().getHeader(ATMOSPHERE_TRACKING_ID)' doesn't seem to work for me (could be my fault). I have to call 'atmosphereResource.uuid()' instead.Cloyd
How did you get an instance of the broadcasterFactory variable?Annettaannette

© 2022 - 2024 — McMap. All rights reserved.