Search code examples
jquerynginxlong-polling

nginx comet long polling with jquery


Recently I have been trying to set up a comet server for my application on a Ngnix server using this plugin:https://github.com/wandenberg/nginx-push-stream-module

due to the restrictive nature of GNU/GPL I am unable to use the JS provided with the plugin, so I am trying to implement it on my own using jquery ajax requests.

my Nginx config looks like this:

  location /channels-stats {
        # activate channels statistics mode for this location
        push_stream_channels_statistics;

        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

        # query string based channel id
        set $push_stream_channel_id             $arg_id;
    }

    location ~ /pub/(.*) {
        # activate publisher (admin) mode for this location
        push_stream_publisher admin;

        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

        # query string based channel id
        set $push_stream_channel_id             $1;
    }

    location ~ /sub/(.*) {
        # activate subscriber (streaming) mode for this location
        push_stream_subscriber;   

        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';


       # positional channel path
        set $push_stream_channels_path              $1;
    }

and the code snippets I am trying to use(in firebug) to test the both way communication is:

//reciever
$.ajax({
    url:'sub/test?callback=mycallback',
    dataType:'json',
    success:function(data){
          console.log(data);
    }
});

//sender
$.ajax({
    url:'pub/test',
    dataType:'json',
    type:'POST',
    data:'mycallback({"J":5,"0":"N"})'

});

I am trying to make it work cross domain, however I can not manage to get it to work even on the same domain, what acctualy happens is:

when I use the recieving code, it initiates a connection to the server and is endlessly loading as it is supposed to be, and then I try to respond to the long poll with the sender code.

now in the console on the NET tab(firebug) I can see that once I send the POST it recieves it in the response as plain text, but still maintains connection without giving a callback! so if i repeatedly send the post I can see in firebug in the net response tab that they are just collecting, but no callback is given from the reciever function! thus I am unable to acctualy extract the data!

now I tried this both on another domain and in the same origin domain so I think the policy is not the problem here, what the problem is that the jquery snippet does not ever get to the callback, although it does reach the callback once the request timeouts ONLY! please help.

on a side note, if you think there is an alternative plugin for NGINX which would suit me better please let me know.


Solution

  • Ok after some research I managed to figure out that I had a mistake in my nginx config which made the connection endless, what I changed it to:

     location /channels-stats {
            # activate channels statistics mode for this location
            push_stream_channels_statistics;
    
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    
            # query string based channel id
            set $push_stream_channel_id             $arg_id;
        }
    
        location ~ /pub/(.*) {
            # activate publisher (admin) mode for this location
            push_stream_publisher admin;
    
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    
            # query string based channel id
            set $push_stream_channel_id             $1;
        }
    
        location ~ /sub/(.*) {
            # activate subscriber (streaming) mode for this location
            push_stream_subscriber long-polling; //<----------------------EDITED LINE
    
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
    
    
           # positional channel path
            set $push_stream_channels_path              $1;
        }
    

    and I wrapped up two tiny functions for dual way communication

    var datalink={
            listen:function(success,error,complete,url){
            //reciever
                $.ajax({
                    url:url,
                    dataType:'jsonp',
                    success:success,
                    error:error,
                    complete:complete
                });
            },
            send:function(data,success,error,complete,url){
            //sender
                $.ajax({
                    url:url,
                    dataType:'json',
                    success:success,
                    error:error,
                    complete:complete
                    type:'POST',
                    data:JSON.stringify(data)
                }); 
            }   
    
        };
    

    note: the function for sending the data use the method JSON.stringify(your-object) while most browsers support it, it is recommended to use something like this: http://bestiejs.github.io/json3/ in order to add support to older browsers for json.stringfying.

    usage example:

    listen from the server(subscribe):

    datalink.listen(function(data){
    
                        console.log(data);//<---your recieved object
                                    },undefined,undefined,'http://example.com/sub/foo');
    

    send to server(publish):

    datalink.send({x:5}//<--the object you are about to send
                   ,undefined,undefined,undefined,'http://chessbless.com/pub/test');
    

    So that is my solution and I hope you find this helpful I apologize if something is unclear, first time answering on SO.