CodingStreaming HTTP

 

Press Ctrl+Enter to quickly submit your post
Quick Reply  
 
 
  
 From:  Mikee  
 To:  ALL
35556.1 
I'm writing a javascript / PHP library for handling 'push' streaming to the web browser. It can be used for stuff like a REALLY smooth web irc client or MSN client or live chat client..etc..

The javascript opens one constant connection to the PHP and never closes it, the PHP then pushes json objects down to the javascript when it needs to.

It's been a bit of a nightmare so far.. I've made one 'Stream' object which can take many forms depending on which browser you're using.
If you're in firefox it'll use XMLHttpRequest, If you're in internet explorer it uses "htmlpage" activeX object, then it'll fall back to a 'flash' proxy if flash is installed, and finally if all else fails it'll use a hidden iframe. (might even do a silverlight version if i can).

So, it works! Hurrah. I'm logged into IRC via the web browser and it keeps me permanently logged in, it's completely asyncronious, I recieve new messages instantly and it's very very simple to implement.. for example:

javascript code:
 
 var myStream = new Stream();
 myStream.onRecieveCommand = function (json){
  switch(json.type){
   case "RECIEVE_MESSAGE":
     this.onReceiveMessage(json.params["user"], json.params["time"], json.params["message"]);
     break;
   default:
     alert('no implementation');
  }
 }
 myStream.open("irc.php);
 
</span


php code:
 
 public class MessageStreamCommand extends StreamCommand {
   private $type = "RECIEVE_MESSAGE";
   function __construct ($user, $time, $message){
    $this->setUser($user);
    $this->setTime($time);
    $this->setMessage($message);
   }
 }
 
 $stream = new Stream();
 while (//reading from irc server) {
   if (//recieved a new mesasge){
     $stream->broadcast(new MessageStreamCommand($name, $time, $message));
   }
 }
 



This all works nicely. Quite proud of it, infact! The javascript involved in getting the actual 'streaming' work is a pretty sexy bit of work.

Now, my problem. I'm trying to work out how to send messages in the other direction (from the javascript to the PHP to the IRC or whatever).

One method I thought of was to open a second ajax connection for outgoing messages and those messages get stored in a database, and my main streaming script checks the database periodically for any messages that it needs to push.

Unfortunately with PHP being single threaded, I'm not sure how to achieve this. Anyone got any ideas???

In .NET this'd be nice and easy.. but I really want to start with a PHP solution first.
0/0
 Reply   Quote More 

 From:  Peter (BOUGHTONP)  
 To:  Mikee     
35556.2 In reply to 35556.1 
WTF?! Why would anyone make a server language single-threaded. That's dumb.

Does it work if you install multiple copies of PHP, associated with different file extensions, (e.g. .php and .phpb ) so you can split the requests based on that.

If not, I'd probably install mod_perl and look for some simple Perl examples - a quick Google suggests it's not too difficult to do what you want.
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  Peter (BOUGHTONP)     
35556.3 In reply to 35556.2 

It appears as though I 'might' be able to do something with stream_socket_client and STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT.

 

Really, I need the connection to be open and processing data whilst also checking a mysql database.

0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
35556.4 
Hurrah. I seem to have made it work. Not the nicest of ways to do it, but hell, it works. Probably quite CPU intensive though...

php code:
 
$socket = stream_socket_client("tcp://".$server_host.":".$server_port, $errno, $errstr, 2, STREAM_CLIENT_ASYNC_CONNECT);
stream_set_blocking($socket, 0);
$timer = time();
while(!feof($socket))
{
  	  $newtime = time(true);
          if (($newtime-$timer) > 2){
        	// do sql queries
                // maybe spit some stuff up into the stream
        	 $timer = $newtime;
           }
            $data = fgets($server['SOCKET'], 1024);
            if ($server['READ_BUFFER'] != ""){
              // if theres any data do whatever needs dong
              // maybe spit some more into the stream
              // maybe echo some stuff to the browser
            }
            flush();
}
 
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
35556.5 
Try this PHP script on some IRC server..


after a couple of minutes it jumps up to 50% CPU usage for me. Can anyone see any way to reduce that?

php code:
<?php
interface iStream {
	function onRecieve ($data);
}
abstract class Stream {
	private $socket, $host, $port;
	function __construct ($host, $port){
		if (!($this instanceof Stream)){
			throw new Exception(get_class()." must implement iStream");
		}
		set_time_limit(0);
		$this->host = $host;
		$this->port = $port;
	}
	function Connect (){
		$this->socket = stream_socket_client("tcp://".$this->host.":".$this->port, $errno, $errstr, 2);
		if($this->socket)
		{
			stream_set_blocking($this->socket, 0);
			$this->onConnect();
			$this->Start();
    		}
	}
	function onConnect (){}
	function Start (){
	   $timer = time();
	   while(!feof($this->socket)) //while we are connected to the server
        {
       	$now = time(true);
		if (($now-$timer) > 5){
			$timer = $now;
			// check database
        	}
 
        	$readBuffer = fgets($this->socket, 1024);
 
        	if ($readBuffer != ""){
        		$this->onRecieve($readBuffer);
        		flush();
        	}
        }
	}
	function onRecieve ($data){
	}
	function Send($data){
		$out = $data."\n\r";
		echo $out;
		@fwrite($this->socket, $out, strlen($out));
	}
	function Broadcast($data){
		// send data (json to web client
	}
}
class IRCStream extends Stream implements iStream {
	private $nickname;
	function __construct ($host, $port, $nickname){
		$this->nickname = $nickname;
		parent::__construct($host, $port);
	}
	function onConnect (){
		$this->Send("PASS NOPASS");
		$this->Send("NICK ".$this->nickname);
		$this->Send("USER ".$this->nickname." USING PHP IRC");
	}
	function onRecieve ($data){
		echo $data;
		if(strpos($data, "422"))
	  	{
		  	$this->Send("JOIN #poop");
		}
		if(substr($data, 0, 6) == "PING :")
		{
			$this->Send("PONG :".substr($data, 6));
		}
	}
}
 
$str = new IRCStream("localhost", 6667, "Mikeemoo");
$str->Connect();
?>
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
35556.6 

Heh.. fixed. It appears as though putting a small sleep like this:

 

usleep(100000);

 

is good enough to cause no CPU usage. :)

0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
35556.7 
This is my first attempt of streaming, if anyones interested in having a look..

Currently its minimized at 10kb of javascript... I dont expect it to get much bigger than that (maybe 15kb max).

Stick that on a PHP server somewhere and edit the details at the bottom of irc.php

php code:
 
$str = new IRCStream("localhost", 6667, $_GET["nick"]);
$str->Connect();
 


Connect to some random irc server somewhere. The room name is hardcoded in there somewhere too.. ($this->Send("JOIN #poop");) so you might wanan change that.

Then load up stream.html in your browser. It *should* work on most browsers. I've only been able to test this with a local IRC server, though.

For me, it works in IE6 and Firefox 2. I know chrome isnt working (iframe streaming isnt working).

Currently it only recieves data and sends data via the PHP script.. you cant send messages from the client yet (im gonna start work on that now).


Thoughts? :) locally, at least, it seems to work really smoothly.. im pretty sure it'd be quite easy to make a REALLY slick web msn client or IRC client using this technique.

Attachments:
stream.zip

0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
35556.8 

screen grab of it working.

 

the messages on the web irc client appear immediately.. locally, anyway.

Attachments:

0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
35556.9 

Huzzah. I got a new version working which now uses flash as a proxy if it can.

 

first it tries using ajax, then htmlfile, then flash then iframe :)

 

should work is pretty much every browser ever, now.

 

rather proud of this! just gotta get it sending messages now.. then THE WORLD IS MY OYSTER or something.

0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
35556.10 


Can anyone think of a better way to do that?

The 4 second check thing is the bit im most bothered about - I'd much rather messages get pushed straight to the server, but I cannae think of a way to do it.

red = outgoing data
purple = incoming data
0/0
 Reply   Quote More 

 From:  Mikee  
 To:  ALL
35556.11 

Can some people test this for me please?

 

I've tested in IE7/FF2/Chrome.

 

http://www.mikefranklin.me.uk/experiments/msn/msn.html

 

- it should look like MSN
- you should be able to drag it from side to side, and resize the width
- resizing the browser will cause the MSN app to resize. if you resize it smaller the image will get knocked out, like on the real msn.
- minimize button will set it to 0x, 0y, 300 px wide.
- maimize button will set it to full screen, as will double clicking
- close button should take you to google (dunno what else to do!)
- clicking on an input field with text in it should select it, unless its already selected (in which case it'll deselect)
- the 'email address' input field should have a down arrow on it.. the cursor should change to a 'arrow' cursor when its over the dropdown icon and clicking should make the menu appear. any clicks away from the menu will hide it. the menu items should have rollover states.
- all the elements title tags should match those on the real MSN

 


Issues i know about:
- moving the window to the right, then shrinking the browser window causes it to break
- the 'sign in' button is the wrong color
- the 'menu' doesnt fade in when it opens
- 'help' and 'online' menus dont work (yet)
- the tickboxes dont have the correct behaviors on them yet.
- signing in doesnt actually do anything yet.

0/0
 Reply   Quote More 

 From:  Manthorp  
 To:  Mikee     
35556.12 In reply to 35556.11 
All good.

Double clicking and maximize button don't revert to the original state if you use them a second time: don't know if that bothers you.

"We all have flaws, and mine is being wicked."
James Thurber, The Thirteen Clocks 1951

0/0
 Reply   Quote More 

 From:  ANT_THOMAS  
 To:  Mikee     
35556.13 In reply to 35556.11 

Double clicking obviously maximises the thing, but I feel once it is maximised double clicking should return it to previous or default size. If possible of course!

 

Otherwise it looks good.


0/0
 Reply   Quote More 

 From:  THERE IS NO GOD BUT (RENDLE)  
 To:  Mikee     
35556.14 In reply to 35556.11 
The title bar graphic is broken in IE8 without Compatibility View turned on. It becomes OK when you move the mouse over it, though.

Attachments:

0/0
 Reply   Quote More 

Reply to All    
 

1–14

Rate my interest:

Adjust text size : Smaller 10 Larger

Beehive Forum 1.5.2 |  FAQ |  Docs |  Support |  Donate! ©2002 - 2024 Project Beehive Forum

Forum Stats