Re: HTTP Streaming

Great implementation. This feature will become one of most usable in xajax i think.

Keep working on it.

We are with you!

Re: HTTP Streaming

Does anyone know if IE 7 will support streaming?
Bummer my users all have IE or Safari sad

Re: HTTP Streaming

You've tried the page then?  So far IE7 beta 3 doesn't support streaming.  It might have it in the final version, but probably not.  There is a way to do it, it just means a total rewrite of the code, just for ie, and uses lots of ActiveX controls to get it to work.

I'll work on it for u and give it a try smile

Re: HTTP Streaming

IE will support streaming!!! You just have to handle it correctly.

Ok, let me rephrase, I have played with this in the past and IE will support it if you trick it, the problem with IE is it doesn't render the HTML until certain "conditions" are met, I really wish I still had the code so I could provide detail but from what I remember right something as simple as sending a <BR> is enough to force IE to render the code sent, There where a couple other tricks to it as well.

Its possible, its a pain in the rear, and you may not be able to make it work in the fashion your using it to easy but it can be done.

Re: HTTP Streaming

Check out the comments in http://us3.php.net/manual/en/function.flush.php for more info on the IE issue

Re: HTTP Streaming

Not at this stage, cyberlot, or at least, not using the XMLHTTPRequest object.  MSDN says that even though the readyState of the object is 3/interactive, the data is not actually interactive, it just means that it's started to recieve data.

MSDN talks about doing Comet/HTTP Streaming, but to do so, requires the use of two activex controls to do XSLT processing and some other kind of XML transform.

I'll look for some links smile

Re: HTTP Streaming

nice example...  from where can i get the comet plugin. would like to try something like that too

33 (edited by dsherron 2006-11-28 1:35:31 AM)

Re: HTTP Streaming

BBC, I know you aren't done with the docs, but can you specify a different polling interval on clients that need polling?  1 sec may be too fast and create extra server load in many cases.

Also, is 'xajaxComet.inc.php' on SVN?

Thanks!

Re: HTTP Streaming

Hello everyone!

I've just signed up to this forum to contribute to this thread. I was looking for a clean push implementation for xajax and came up with following solution. It's neither streaming nor classical fixed-time polling: Simply wait in your xajax function for an event to occur, send back the update to the client and call the same ajax function again. The simple example below gets updates from the server in arbitrary time intervals.

<?php
require ('../xajax_core/xajax.inc.php');

function waitForEventAndShowChange()
{
  // wait until something happens... 
  // e.g. a new message arrives in your chat
  // here we wait between 0.1 and 3 seconds
    usleep(rand(100000,3000000));

  // show change
    $text = rand(1,1000);
    $objResponse = new xajaxResponse();
  $objResponse->assign("div1","innerHTML","value: ".$text);
  
  // recall Function to wait again
  $objResponse->script("xajax_waitForEventAndShowChange();");
    
    return $objResponse;
}

$xajax = new xajax(); 
$xajax->registerFunction("waitForEventAndShowChange");
$xajax->processRequest();

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <title>xajax example</title>
    <?php $xajax->printJavascript('../'); ?>
</head>
<body style="text-align:center;">
  <button onclick="xajax_waitForEventAndShowChange()">Start</button><br/>
    <div id="div1" name="div1"> </div>
</body>
</html>

Advantages:
- realizes comet functionality including an open connection waiting for server events
- no unneccessary polls as used in fixed time polling, data is sent immediatley after the event occurs
- no streaming necessary, should be absolutely compliant with normal XMLHTTPRequests

What do you guys think of that? Any problems with this solution?

Thanks for any feedback!
Steve

Re: HTTP Streaming

Has anybody tried that solution yet ... unfortunately I can't at the moment as my PC is a bit messed up.

I would be curious about this approach and hope that there'll soon be a plugin for V0.5 as well.

Greetings ... Andreas.

Re: HTTP Streaming

I just tryed it.

Had to make some mods in order for it to work but the idea and results are GREAT!!!

Re: HTTP Streaming

Wow ... now I'm curious ... if the changes are important, could you share it with us?

Thanks ... Andreas.

38 (edited by CarlitosWak 2006-12-22 1:02:16 PM)

Re: HTTP Streaming

For starters you would see the problem when you tried running the script.

current script above

  $objResponse->assign("div1","innerHTML","value: ".$text);
  
  // recall Function to wait again
  $objResponse->script("xajax_waitForEventAndShowChange();");

return $objResponse;

to

  $objResponse->addassign("div1","innerHTML","value: ".$text);
  
  // recall Function to wait again
  $objResponse->addscript("xajax_waitForEventAndShowChange();");

return $objResponse->getXML();

Adios

Re: HTTP Streaming

stupid question:is it good to keep many connections open? Maybe I misunderstood your approach, but aren't you keeping the client connected while you wait for change?

Re: HTTP Streaming

@CarlitosWak: Yes, my code example is already written for xajax 0.5. So thanks for your corrections to make it work for older xajax versions.

@MindMaker: Yes, we keep the client connected. That is what Ajax Comet is all about. In order to send server events to the client without polling you need an open connection to that client. This certainly results in special requirements for your web server (e.g. handling as many open connections as concurrent users) but that's not avoidable if you want to do "real web push".

Re: HTTP Streaming

Interesting solution, Steve.  However the code you show doesn't keep the connection open.  When you return from the function, the xml is sent to the client and the connection closed and another one opened.

I'm not sure if the xajaxComet stuff in this example was in svn but I'll do a little code dump here of xajaxComet.php that I used

<?php

class xajaxComet extends xajax {
    var $cometFuncs = array();
    
    function xajaxComet()
    {
        $temp = func_get_args();
        call_user_func_array(array(&$this,"xajax"), $temp);
        $this->registerFunction(array("comet_poll_backup", &$this, "singleCheckResponse"));
    }
    
    function registerCometFunction($funcName, $funcTest, $funcArgs='')
    {
        $this->cometFuncs[] = array('funcName'=>$funcName,'funcTest'=>$funcTest,'funcArgs'=>$funcArgs);
        //@session_start();
        //$_SESSION['cometFuncs'] = $this->cometFuncs;
        //@session_write_close();
        $this->registerFunction(array("comet_poll_backup", &$this, "singleCheckResponse"));
    }
    
    function singleCheckResponse()
    {
        //@session_start();
        //if ($_SESSION['cometFuncs'])
        //    $this->cometFuncs = $_SESSION['cometFuncs'];
        //@session_write_close();
        if (!$this->cometFuncs)
            return;
        $objResponse = new xajaxResponse();
        for($i=0;$i<count($this->cometFuncs);$i++)
        {
            $cometArray = &$this->cometFuncs[$i];
            if (call_user_func($cometArray['funcTest']))
            {
                $objResponse->loadCommands( $this->_callFunction($cometArray['funcName'],$cometArray['funcArgs']) );
            }
        }
        $objResponse->script('if (xajax.cometStatus) setTimeout("xajax.call(\\"comet_poll_backup\\");",1000);');
        return $objResponse;
    }
    
    function processRequest()
    {
        parent::processRequest();
        
        if (!$_REQUEST['xajaxcomet'])
            return;
        
        while(@ob_end_clean());
        
        header('Content-type: text/javascript');
        
        $count = 0;
        while(true)
        {
            if ($count++ >= 10) exit; //just a test
            for($i=0;$i<count($this->cometFuncs);$i++)
            {
                $cometArray = &$this->cometFuncs[$i];
                if (call_user_func($cometArray['funcTest']))
                {
                    echo $this->sWrapperPrefix.$cometArray['funcName'].'('.$cometArray['funcArgs'].');'."\n";
                }
            }
            //echo "alert('".addslashes(str_replace("\n",'',(print_r($this->cometFuncs,true))))."');";
            sleep(1); //wait one second to not overload the server
            str_pad('', 4096);
            ob_flush();
            flush();
        }
    }
}

and xajax_comet.js

xajax.cometStatus = 0; //uninitialised
xajax.cometLastPosition = 0;
xajax.cometObject;
xajax.cometTimer = null;
xajax.processComet = function() {
    if (this.cometObject && this.cometObject.responseText) {
        cmd = this.cometObject.responseText.substring(this.cometLastPosition, this.cometObject.responseText.lastIndexOf(';')+1);
        this.cometLastPosition += cmd.length;
        eval(cmd);
    }
    this.cometTimer = setTimeout("xajax.processComet();", 100);
}
xajax.cometType = null;

xajax.cometStop = function() {
    this.cometStatus = 0;
    clearTimeout(this.cometTimer);
    if (this.cometObject)
    {
        this.cometObject.abort();
        delete this.cometObject;
        this.cometObject = null;
    }
    this.cometLastPosition = 0;
}

xajax.cometStart = function() {
    this.cometStatus = 1; //initialising
    this.cometObject = this.getRequestObject();
    if (!this.cometObject)
        return false;
    if (this.callOptions)
        uri = this.callOptions.URI;
    if (!uri)
        uri = xajaxConfig.requestURI;
    if (!uri)
        return false;
    this.cometObject.open('post', uri, true);
    this.cometObject.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    //this.cometObject.setRequestHeader( "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" );
    this.cometObject.onreadystatechange = function() {
        if (!xajax.cometObject)
            return;
        if (xajax.cometObject.readyState == 3) {
            try {
                errorTest = xajax.cometObject.responseText;
            } catch (e) {
                errorTest = "";
            }
            if (!errorTest)
            {
                //we're a browser that cant do http streaming properly
                xajax.cometType = 'polling';
                //close the connection
                xajax.cometObject.abort();
                delete xajax.cometObject;
                xajax.cometObject = null;
                //instead call the polling function every second
                xajax.call('comet_poll_backup');
                return;
            }
            xajax.cometType = 'comet';
            if (!xajax.cometTimer) {
                //get the ball rolling
                xajax.cometTimer = setTimeout("xajax.processComet();",10);
            } else {
                return;
            }
        } else if (xajax.cometObject.readyState == 4)
        {
            xajax.processComet();
            oldCometStatus = xajax.cometStatus;
            xajax.cometStop();
            if (oldCometStatus)
                xajax.cometStart();
        }
    }
    this.cometObject.send("xajaxcomet=xajaxcomet&xajaxr="+new Date().getTime());
    this.cometStatus = 2; //running
    return true;
}

setTimeout("xajax.cometStart();",10);

Apologies for the long delay to post... I havn't been on the xajax forums for several months now.  I'm hoping to change that.

Also, I'm not sure if it works with xajax 0.5 beta 1, and it probably doesn't work with xajax 0.5 beta 2.  Once I've caught up on the new code in SVN i'll (finally) make a plugin.

Re: HTTP Streaming

BigBrownChunx,   please tell your comet code work fine with what version xajax???

Re: HTTP Streaming

The code was written to work with 0.2.4

Re: HTTP Streaming

I have made a few updates to the Comet code, to work with 0.5 beta 2. Unfortinuatly when doing this i broke it for IE, but works beautifully in Firefox...   Maybe someone can help track down why it doesn't work in iE.  I believe IT has something to do with the Request Object.

New xajaxComet.php

<?php

class xajaxComet extends xajax {
    var $cometFuncs = array();
    
    function xajaxComet()
    {
        $temp = func_get_args();
        call_user_func_array(array(&$this,"xajax"), $temp);
        $this->registerFunction(array("comet_poll_backup", &$this, "singleCheckResponse"));
    }
    
    function registerCometFunction($funcName, $funcTest, $funcArgs='')
    {
        $this->cometFuncs[] = array('funcName'=>$funcName,'funcTest'=>$funcTest,'funcArgs'=>$funcArgs);
        //@session_start();
        //$_SESSION['cometFuncs'] = $this->cometFuncs;
        //@session_write_close();
        $this->registerFunction(array("comet_poll_backup", &$this, "singleCheckResponse"));
    }
    
    function singleCheckResponse()
    {
        //@session_start();
        //if ($_SESSION['cometFuncs'])
        //    $this->cometFuncs = $_SESSION['cometFuncs'];
        //@session_write_close();
        if (!$this->cometFuncs)
            return;
        $objResponse = new xajaxResponse();
        for($i=0;$i<count($this->cometFuncs);$i++)
        {
            $cometArray = &$this->cometFuncs[$i];
            if (call_user_func($cometArray['funcTest']))
            {
                $objResponse->loadCommands( $this->_callFunction($cometArray['funcName'],$cometArray['funcArgs']) );
            }
        }
        $objResponse->script('if (xajax.cometStatus) setTimeout("xajax.call(\\"comet_poll_backup\\");",1000);');
        return $objResponse;
    }
    
    function processRequest()
    {
        parent::processRequest();
        
        if (!$_REQUEST['xajaxcomet'])
            return;
        
        while(@ob_end_clean());
        
        header('Content-type: text/javascript');
        
        $count = 0;
        while(true)
        {
            //if ($count++ >= 25) exit; //just a test for auto reconnection
            for($i=0;$i<count($this->cometFuncs);$i++)
            {
                $cometArray = &$this->cometFuncs[$i];
                if (call_user_func($cometArray['funcTest']))
                {
                    echo $this->sWrapperPrefix.$cometArray['funcName'].'('.$cometArray['funcArgs'].');'."\n";
                }
            }
            //echo "alert('".addslashes(str_replace("\n",'',(print_r($this->cometFuncs,true))))."');";
            sleep(1); //wait one second to not overload the server
            str_pad('', 4096);
            ob_flush();
            flush();
        }
    }
}

and New xajax_comet.js

// JavaScript Document

cometServer = '';
xajax.cometStatus = 0; //uninitialised
xajax.cometLastPosition = 0;
xajax.cometObject;
xajax.cometTimer = null;
xajax.processComet = function() {
    if (this.cometObject && this.cometObject.responseText) {
        cmd = this.cometObject.responseText.substring(this.cometLastPosition, this.cometObject.responseText.lastIndexOf(';')+1);
        this.cometLastPosition += cmd.length;
        eval(cmd);
    }
    this.cometTimer = setTimeout("xajax.processComet();", 100);
}
xajax.cometType = null;

xajax.cometStop = function() {
    this.cometStatus = 0;
    clearTimeout(this.cometTimer);
    if (this.cometObject)
    {
        this.cometObject.abort();
        delete this.cometObject;
        this.cometObject = null;
    }
    this.cometLastPosition = 0;
}

xajax.cometStart = function(serverURI) {
    this.cometStatus = 1; //initialising
    this.cometObject = this.tools.getRequestObject();
    if (!this.cometObject)
        return false;
        
    uri = serverURI;
    if (this.callOptions)
        uri = this.callOptions.URI;
    if (!uri)
        uri = this.config.baseDocument.URL;
    if (!uri)
        return false;
            
    this.cometObject.open('post', uri, true);
    this.cometObject.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    //this.cometObject.setRequestHeader( "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" );
    
    this.cometObject.onreadystatechange = function() {
        if (!xajax.cometObject)
            return;
        if (xajax.cometObject.readyState == 3) {
            try {
                errorTest = xajax.cometObject.responseText;
            } catch (e) {
                errorTest = "";
            }
            if (!errorTest)
            {
                //we're a browser that cant do http streaming properly
                xajax.cometType = 'polling';
                //close the connection
                xajax.cometObject.abort();
                delete xajax.cometObject;
                xajax.cometObject = null;
                //instead call the polling function every second
                xajax.call('comet_poll_backup');
                return;
            }
            xajax.cometType = 'comet';
            if (!xajax.cometTimer) {
                //get the ball rolling
                xajax.cometTimer = setTimeout("xajax.processComet();",10);
            } else {
                return;
            }
        } else if (xajax.cometObject.readyState == 4)
        {
            xajax.processComet();
            oldCometStatus = xajax.cometStatus;
            xajax.cometStop();
            if (oldCometStatus)
                xajax.cometStart(serverURI);
        }
    }

    this.cometObject.send("xajaxcomet=xajaxcomet&xajaxr="+new Date().getTime());
    this.cometStatus = 2; //running
    return true;
}

Re: HTTP Streaming

Neat stuff smile Thanks for converting it.
How come you've added the serverURI to the xajax.cometStart() javascript function?
I had a good look over it and can't see why it would fail in IE. sad  Since I'm not at my development machine during the weekends, would you be able to put up a test page somewhere that we can look at?

Re: HTTP Streaming

hello, interesting encounter that you have made on this subject. I have tried to implement this in my problem, but I have not been able. My problem is that I have socket that receives messages, which I need to print in <div> that corresponds (in “indicated”). I need to apply Comet(Push) while messages exist, while socket is open. Hopefully they can help me, beforehand, thanks.
Excuse my bad English.
Greetings…

Re: HTTP Streaming

BBCs example file is no longer linked.  Does anyone have some code that they can post so that I can get an idea of how to use this?

Re: HTTP Streaming

bump: http://community.xajaxproject.org/viewtopic.php?id=6107 smile

Re: HTTP Streaming

Very nice plugin, annoyingly with my app I'm planning on having 1000+ users minimum online at once, all streaming and updating mysql data as the map runs, and a script like this would annoyingly crush the server, whereas a more robust update every 2 seconds + every move works better, it is slower sad

If only there was a way to have an open connection to mysql, that is scanning the data constantly, and automatically via ajax displaying it to all relevant users (therefore only one connection per map, and a user connects and the javascript requests the content). Is that even possible without serious custom coding software-wise?