Solved

Long polling

Posted on 2014-07-25
10
236 Views
Last Modified: 2014-07-28
Hi,

I am having some problems with long polling working on one of my projects.

i created this long polling function (it is a mix of jquery and js im going to change this)
//LONG POLLING
function messages_longpolling( timestamp, last_id, id){
   var t;
 
   if( typeof last_id == 'undefined' ){
      last_id = 0;
   }
 
   $.ajax({
      url: 'ajax/messages_main.php?message_id=' + id + '&timestamp=' + timestamp + '&last_id=' + last_id, 
      type: 'POST',
      dataType: 'json',
      success: function( payload ){
         clearInterval( t );
         if( payload.status == 'results' || payload.status == 'no-results' ){
            t=setTimeout( function(){
               messages_longpolling( payload.timestamp, payload.last_id                         );
            }, 1000 );
            if( payload.status == 'results' ){
				//UPDATE CONTENT
  					document.getElementById('message_thread').innerHTML=payload.content;
					document.getElementById('show_msg_form').style.display='block';
					
					//MAKE SURE THERE IS A SUBJECT AND IT IS NOT EMPTY
					if(payload.subject){
						//CHANGE HEADER TO SUBJECT
						document.getElementById('users_name_heading').innerHTML='Group Message: ' + payload.subject;
						
					}else{
						//DEFAULT SHOW NAMES
						document.getElementById('users_name_heading').innerHTML=payload.heading;
					}
					
					//EDIT FORM VALUES
					document.getElementById('msg_id').value =payload.msg_id; 	
					document.getElementById('msg_indi').value =payload.msg_indi; 	
					document.getElementById('msg_sub').value =payload.msg_sub; 
							
					//ADJUST THE SIDE PANEL SETTINGS
					var badge =document.getElementById('msg_badge'+id).innerHTML;
					if( badge =='unread'){
						document.getElementById('msg_badge'+id).innerHTML =payload.badge; 
					}
					//GO TO BOTTOM
					var div =document.getElementById('chat-content');
					div.scrollTop= div.scrollHeight;
					
					//STOP PROPIGRATION
					//a.stopPropagation();
					//a.cancelBubble = true	
                  
            }
         } else if( payload.status == 'error' ){
			 //THERE WAS AN ERROR 
			 alert('Ooops! Something has gone wrong. Please try again!'); 
			 
         }
      },
      error: function(payload){
         clearInterval( t );
         t=setTimeout( function(){
            messages_longpolling( payload.timestamp, payload.last_id );
         }, 15000 );
      }
   });
}

Open in new window


i then use an inline on click event to trigger the function like so
<a href="#" class="active" id="msg3" onclick="messages_longpolling( 1406321552,'',3); return false">  

Open in new window


the ajax code fires once someone has clicked one of the chats (there a different chats)

The ajax request gets the information using the following code

function get_all_messages($sql, $array){
	//SET THE GLOBALS
	global $conn;
	
	//SETUP SOME STANDARD VARS
	$messages='';
	$heading='';
	$all_senders='';
	$count=0;
	$dir=$_SERVER['SERVER_NAME'].'/profile/images/profile_pics/'; //profile directory path
	$timestamp = (int) trim( $_GET['timestamp'] );
	$last_id = isset( $_GET['last_id'] ) && !empty( $_GET['last_id'] ) ? $_GET['last_id'] : 0;
	$time_wasted = 0;
	$last_id = '';	
	$data=array();
		
	//PREPARE SQL
	$prep=$conn->prepare($sql);
	$ex=$prep->execute($array);
	
	//CHECK IF THERE ARE ZERO ENTRIES
	$num = $prep->rowCount();
	if($num <=0){
		//CHANGE HEADING
		$heading='<li class="conversation-divider"><span>* No Messages * </span></li>';
		
		//PERFORM SOME CHECKS
		while($num <=0){
			if($num <=0){
				if($time_wasted>=60){
					//CREATE JSON ARRAY
					$data=array(
						"status"=>"no results", 
						"timestamp"=>time(),
						"last_id"=>0, 
					);
				}
				
				//SLOW DOWN PROCESS TO LIMIT SYSTEM RESOURCES
				sleep(1);
				
				//CHECK MESSAGES AGAIN
				$ex=$prep->execute($array);
				$num = $prep->rowCount();
				$time_wasted++;
			}
		}
	
	//EXECUTE REMAINING FUNCTIONS IF TEST PASSES
	}else{
		
		//THERE ARE NEW MESSAGES
		if($num>=1){
			//GET NEW MESSAGES
			
			//SETUP THE SQL FOR GETTING PEOPLE INFORMATION
			$ppl='SELECT user_nickname, avatar FROM bb_users WHERE username=(:user) LIMIT 1';
			$ppl_prep=$conn->prepare($ppl);
	
			while($fetch= $prep->fetch(PDO::FETCH_ASSOC)){
				//SETUP VARS
				$id=isset($fetch['id'])?$fetch['id']:'';	
				$original_id=isset($fetch['original_id'])?$fetch['original_id']:'';	
				$composed_date=isset($fetch['composed_date'])?date("F j Y, g:i a",strtotime($fetch['composed_date'])):'';
				$sender=isset($fetch['sender'])?$fetch['sender']:'';
				$recipient=isset($fetch['recipient'])?$fetch['recipient']:'';
				$subject=isset($fetch['subject'])?$fetch['subject']:'';
				$message=isset($fetch['message'])?$fetch['message']:'';
				$heading=' <li class="conversation-divider"><span>Conversation started at '.$composed_date.'</span></li>';
				$individuals=isset($fetch['individuals'])?$fetch['individuals']:'';
				$avatar=$_SESSION['avatar'];
				$nickname=$_SESSION['user_nickname'];
				$sent_class='sent';
						
				//TEST TO SEE IF SENDER AND RECIPIENT ARE EQUAL
				if(($sender !== $recipient)){
					//THE USER VIEWING IS NOT THE SENDER
					$ppl_array=array(":user"=> $sender);
					$ppl_ex=$ppl_prep->execute($ppl_array);
					
					//GET THE DATA
					if($person = $ppl_prep->fetch(PDO::FETCH_ASSOC)){
						$avatar=$person['avatar'];
						$nickname=$person['user_nickname'];
						$sent_class='receive';
						
						//GET ALL RECIPIENTS
						$all_senders[]=$nickname;
					}
				}	
				
				//CREATE THE START OF THE MESSAGE
				if($count==0){
					//ADD HEADER TO START OF MESSAGE THREAD
					$messages.=$heading;
					
				}elseif($count % 20 ==0){
					//ADD THE DATE OF THE TENTH POST
					$sub_date=date("F Y", strtotime($composed_date));
					$messages.='<li class="conversation-divider"><span>'.$sub_date.'</span></li>';
				}
				
				//DISPLAY TO CONTENT
				$messages.='
					<li class="message '.$sent_class.'">
					  <div class="media">
						<div class="pull-left user-avatar">
						  <img class="media-object img-circle" src="//'.$dir.$avatar.'">
						</div>
						<div class="media-body">
						  <p class="media-heading"><a href="#">'.ucwords($nickname).'</a> <span class="time">'.$composed_date.'</span></p>
						  '.$message.'
						</div>
					  </div>
					</li>
							
				';
						
				//INCREASE COUNT
				$count++;	
				
			}
			
			//CONVERT ALL_SENDERS INTO A STRING
			if(is_array($all_senders)){
				//REMOVE DUPLICATES
				$all_senders=array_unique($all_senders);
					
				//CONVERT TO STING
				$all_senders= implode(", ",$all_senders);
			
			}
			
			//SETUP ARRAY
			$data=array(
				'status'=> 'results',
				'timestamp'=>time(),
				'last_id'=>$id,
				'heading'=> ucwords($all_senders),
				'subject' => $subject,
				'content'=> $messages,
				'badge'=>'',
				'msg_id'=> $original_id,
				'msg_indi'=> $individuals,
				'msg_sub'=> $subject,
			);
			
		}

	}
	
	//JSON ENCODE
	$data=json_encode($data);
	
	//DISPLAY DATA
	die( $data);
}

Open in new window


declared in messages_main.php
       $sql='SELECT * FROM messages WHERE original_id=(:msg_id) AND recipient=(:user) AND composed_date>=(:time) ORDER BY id ASC LIMIT 100';
	$array=array(":msg_id"=>$ID, ":user"=>$_SESSION['username'], ":time"=>time());
	get_all_messages($sql, $array);

Open in new window



since using the code my project takes considerably longer to load. and im not getting a "real" time response

When i let my page site and wait and pull up google console i get the following errrors

http://www.bushbrigade.com/bushbase/system/ajax/messages_main.php?message_id=undefined&timestamp=undefined&last_id=0
where have i gone wrong and what can i do to make this work?

if you would like to see a working example it can be found here

http://www.bushbrigade.com/bushbase/system/messages.php

user: expert-exchange
pass: 3XP3rt!!!!

thanks

Jayme
0
Comment
Question by:M. Jayme Nagy
  • 5
  • 4
10 Comments
 
LVL 58

Expert Comment

by:Gary
ID: 40220491
Login not working and is this link where the problem is?
0
 
LVL 6

Author Comment

by:M. Jayme Nagy
ID: 40220529
Hi,

looks like someone change the password i have changed it back and it works now



Yes the link is the page i would i am using.
0
 
LVL 58

Expert Comment

by:Gary
ID: 40220573
Here you are not passing the msg.id - should you be?

            t=setTimeout( function(){
               messages_longpolling( payload.timestamp, payload.last_id                         );
            }, 1000 );

Open in new window

0
 
LVL 6

Author Comment

by:M. Jayme Nagy
ID: 40220593
Yea I noticed that too

I adjusted that to include payload.msg_I'd

Still really slow and no response
 And get the undefined for message_id
0
 
LVL 58

Expert Comment

by:Gary
ID: 40220611
In the error function of your ajax call you are rerunning the ajax call but you have invalid values which ends up in a continual loop with errors.

      error: function(payload){
         clearInterval( t );
         t=setTimeout( function(){
            messages_longpolling( payload.timestamp, payload.last_id, payload.msg_id );
         }, 15000 );

Open in new window

0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 6

Author Comment

by:M. Jayme Nagy
ID: 40220632
So what should I adjust it too mine looks just like the one u just posted. I still have funny stuff happening
0
 
LVL 58

Expert Comment

by:Gary
ID: 40220639
That is your code, I was pointing out where the problem is.
As to what to do - I'm not sure as I haven't figured out your logic flow yet but I would guess you have some default values there that it can fall back to if there is an error
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 40220682
No points for this please.  I don't want to rain on anyone's parade, but PHP is really built for HTTP client/server work in a RESTful environment.  The requests are atomic, complete and stateless and the responses are complete and usually instantaneous.  If you're using Apache It may be the wrong tool for a long-polling application, since the Apache threads can be eaten up pretty quickly.  

These seem to be built for long-polling:
http://www.tornadoweb.org/en/stable/
http://cometdproject.dojotoolkit.org/

I don't know what a good PHP answer might be.
0
 
LVL 58

Accepted Solution

by:
Gary earned 500 total points
ID: 40221915
Ray is right - Apache is not built for this.
You may want to look at nGinx or node.js for handling your long polling - both are single threaded and can easily handle thousands of concurrent connections without belching.
If you know js then using node.js will be relatively easy
nGinx requires a bit more hands on work

I personally use nGinx and after the initial 'How the hell do you do...' its pretty easy to get on with.
0
 
LVL 6

Author Comment

by:M. Jayme Nagy
ID: 40223414
Hi,

i have considered using node.js however i would need to switch my server and im not interested in doing this right now.

the app im building is small so i would like to keep php

ive updated my js however im not getting my desired results

//LONG POLLING
function messages_longpolling( timestamp, last_id, msg_id){
   var t;
 
   if( typeof last_id == 'undefined' ){
      last_id = 0;
   }
 
   $.ajax({
      url: 'ajax/messages_main.php?message_id=' + msg_id + '&timestamp=' + timestamp + '&last_id=' + last_id, 
      type: 'GET',
      dataType: 'json',
      success: function( payload ){
         clearInterval( t );
         if( payload.status == 'results' || payload.status == 'no-results' ){
            t=setTimeout( function(){
               messages_longpolling( payload.timestamp, payload.last_id , payload.msg_id);
            }, 1000 );
            if( payload.status == 'results' ){
		 //UPDATE CONTENT
  					
                  
            }
      },
      error: function(payload){
         clearInterval( t );
		 alert('error');
         t=setTimeout( function(){
            messages_longpolling( payload.timestamp, payload.last_id, payload.msg_id );
		  
         }, 15000 );
      }
   });
}

Open in new window


i didnt make the code i got it from a website and then adapted it to my stuff. im not really sure how i can change it to get the desired output. the one big item is that my app has multiple chats and not one large one.

the website i used is http://webcooker.net/ajax-polling-requests-php-jquery/
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

This article covers the basics of the Sass, which is a CSS extension language. You will learn about variables, mixins, and nesting.
This article discusses how to create an extensible mechanism for linked drop downs.
Viewers will learn about arithmetic and Boolean expressions in Java and the logical operators used to create Boolean expressions. We will cover the symbols used for arithmetic expressions and define each logical operator and how to use them in Boole…
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now