4
votes

I'm looking to implement real time notification updates on my social networking website. I have done some research on comet and i'm really fascinated by it.

From what I understand, this is the basic flow of what happens on a comet server.

Webpage: 
Sends an ajax request to server when the document is ready. 

Server:
Queries the database every x amount of seconds and returns a json string containing results if any are found.

Webpage:
Receives the result of the json string from the server and sends out another ajax request  to do the above process again.

By understanding the flow of how comet works, I've written some PHP and Javascript code.

The JavaScript code uses the jQuery library and sends an ajax request out to the server with the current time in a unix timestamp format as a GET parameter.

    $(document).ready(function(){
       var timestamp = Math.round(new Date().getTime() / 1000);

        function comet2(){
            $.ajax({
                type : 'GET',
                url  : 'comet.activities.php?timestamp=' + timestamp,
                async : true,
                cache : false,

                success : function(data) {
                    alert("current timestamp "+timestamp)

                    var json = JSON.parse(data);
                    if(json !== null){
                        alert(data);
                    }

                    timestamp  = json[0].timestamp;
                    setTimeout('comet2()', 1000);

                },
                error : function(XMLHttpRequest, textstatus, error) { 
                    setTimeout('comet2()', 15000);
                }       
            });
        }

        //call the comet function because the page has loaded.
        comet2();

    });

The PHP code will query for new activities by searching the database for new rows by using a timestamp paramater (in this case, a unix timestamp in a query). For this example, I have limited the amount of results to 1.

<?php 
    set_time_limit(0);
    include("models/config.php");
    global $mysqli,$db_table_prefix;

    $last = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
    $results = null;
    $flag=true;

    $stmt = $mysqli->prepare("SELECT id,timestamp FROM uc_user_activity WHERE timestamp > ? ORDER BY timestamp DESC LIMIT 0,1");
    $stmt->bind_param("i", $last);
    $stmt->bind_result($id,$timestamp);

    while($flag){
        $stmt -> execute();    

        while ($row = $stmt->fetch()){
            $flag = false;
            $results[] = array(
                "id" => $id,       
                "timestamp" => $timestamp  
            );
        }

        $stmt -> close();  

        usleep(100000);
        clearstatcache();
    }

    echo json_encode($results);    

?> 

The code above doesn't actually 'work' The problem is that if a user posts a new comment, it will fail to add to the database when the comet script is running. This means that the comet script will never return any json result because the statement in the sql query is never met (no new activities are added with a newer timestamp). My ajax code for posting new comments is working 100%, so I know that isn't the problem. Simply 'nothing happens', that is - nothing (no errors) are alerted or outputted to the browser console.

Edit number 3: I'm seriously struggling to explain what I mean by 'nothing is happening', so I have uploaded an image showing that the database insert fails when the comet script is being called from jquery (notice how the textbox is disabled whilst the comment is being posted via ajax).

enter image description here

What can I do about this? I've spent hours searching the internet trying to fix this/find a similar working example with no avail.

If I change the query in my PHP code to be:

$stmt = $mysqli->prepare("SELECT id,timestamp FROM uc_user_activity WHERE timestamp **<** ? ORDER BY timestamp DESC LIMIT 0,1");

instead of:

 $stmt = $mysqli->prepare("SELECT id,timestamp FROM uc_user_activity WHERE timestamp > ? ORDER BY timestamp DESC LIMIT 0,1");

results are instantly alerted to the browser window, comments can be posted again and the script is called again and new posts are displayed. This shows that my code 'is working' fine afterall and it looks like the query is causing the problem...

enter image description here

Can anyone see what is going on here? I have edited this question 7 times now and any guidance would be great as I'm just getting nowhere.

Just so this doesn't get closed, here is my question to round up what I have discussed above:

Are there any better ways of implementing a comet server? I'm not the most experienced guy ever, but I would really like to learn how to do this. It seems StackOverflow has this functionality and it works perfectly - how are they doing it?

I can't possibly write my post in any further detail than this and I would REALLY appreciate some guidance from you awesome people. A suggestion as to why my code 'isn't working' or links to any tutorials explaining how to implement this would be amazing! Thanks in advance and apologies for this monster of a question and all of the edits!

2
"it will fail to add to the database because this script is already querying the database for new posts" --- ?? So one script performs selects, another script performs insert. What should cause a fail? - zerkms
I will make an edit to explain this. +1 for being so quick to comment! - Joel Murphy
"Am I doing this properly?" --- comet-server written in php is already a bad decision. - zerkms
Made an edit, I hope it makes more sense. What would you recommend? I'm completely new to the topic, so any guidance would be a huge help. Cheers :) - Joel Murphy
"What would you recommend?" --- any programming language, that can serve http itself and supports threads. - zerkms

2 Answers

0
votes

My hunch is that the timestamp value which you are passing returns no results. You get the current time through Javascript. The query queries for all posts after this timestamp.

Can you try to print the query and run the same query manually to ensure that it retrieves data from the DB?

0
votes

So, for the best available tutorial for Comet with PHP is here. http://www.zeitoun.net/articles/comet_and_php/start

Like it, if it helps :)

For those who want to use the simple chat solution above in the link with jQuery here is the solution.

<script type="text/javascript">
    var Comet = {};
    Comet.jquery = {
        timestamp: 0,
        url: './backend.php',
        noerror: true,
        initialize: function () {
        },
        connect: function ()
        {
            this.ajax = $.ajax({
                type: "get",
                url: this.url,
                data: {timestamp: this.timestamp},
                success: function (data) {
                    // handle the server response
                    var response = JSON.parse(data);
                    console.log(response);
                    //alert(response.timestamp);
                    Comet.jquery.timestamp = response.timestamp;
                    Comet.jquery.handleResponse(response);
                    Comet.jquery.noerror = true;
                },
                complete: function (data) {
                    // send a new ajax request when this request is finished
                    if (!Comet.jquery.noerror) {
                        // if a connection problem occurs, try to reconnect each 5 seconds
                        setTimeout(function () {
                            Comet.jquery.connect()
                        }, 5000);
                    }
                    else {
                        Comet.jquery.connect();
                    }
                    Comet.jquery.noerror = false;
                }
            });
        },
        disconnect: function ()
        {
        },
        handleResponse: function (response)
        {
            $('#content').append('<div>' + response.msg + '</div>');
        },
        doRequest: function (request)
        {
            $.ajax({
                type: "get",
                url: this.url,
                data: {'msg': request}
            });
        }
    }
</script>