1 /**
  2  * Socketbug - Web Socket Remote Debugging
  3  * 
  4  * Copyright (c) 2011 Manifest Interactive, LLC
  5  *
  6  * Licensed under the LGPL v3 licenses.
  7  *
  8  * @version v0.2.1 ( 7/4/2011 )
  9  *
 10  * @author <a href="http://www.socketbug.com">Website</a>
 11  * @author <a href="http://www.vimeo.com/user7532036/videos">Video Tutorials ( HD )</a>
 12  * @author <a href="http://www.twitter.com/socketbug_dev">Twitter</a>
 13  * @author <a href="http://github.com/manifestinteractive/socketbug">Source Code</a>
 14  * @author <a href="http://socketbug.userecho.com">Support & Feature Requests</a>
 15  */
 16 
 17 if(typeof(socketbug) === 'undefined')
 18 {
 19 	/**
 20 	 * @private
 21 	 */
 22 	var _encryption_salt = 'Ch4ng3^M3';
 23 	
 24 	/**
 25 	 * @namespace Socketbug Console 
 26 	 */
 27 	var socketbug = {
 28 
 29 		/** 
 30 		 * Check if we're connected to Socketbug 
 31 		 * 
 32 		 * @param {Boolean} connected
 33 		 */
 34 		connected: false,
 35 		
 36 		/**
 37 		 * Store Socketbug Session ID 
 38 		 * 
 39 		 * @param {String} session_id
 40 		 */
 41 		session_id: null,
 42 		
 43 		/** 
 44 		 * Define Group Data 
 45 		 * 
 46 		 * @param {Object} group
 47 		 */
 48 		group:
 49 		{
 50 			'id': hex_md5(_encryption_salt + _sbs.group_id),
 51 			'name': _sbs.group_name
 52 		}, 
 53 		
 54 		/** 
 55 		 * Define Application Data 
 56 		 * 
 57 		 * @param {Object} application
 58 		 */
 59 		application:
 60 		{
 61 			'id': hex_md5(_encryption_salt + _sbs.application_id),
 62 			'name': _sbs.application_name
 63 		}, 
 64 		
 65 		/** 
 66 		 * Define Client Data 
 67 		 * 
 68 		 * @param {Object} client
 69 		 */
 70 		client:
 71 		{
 72 			'id': hex_md5(_encryption_salt + GUID.create()),
 73 			'name': ''
 74 		}, 
 75 		
 76 		/** 
 77 		 * Debug Level
 78 		 * 
 79 		 * @example 5 = log, debug, info, warn, & error
 80 		 * @example 4 = debug, info, warn, & error
 81 		 * @example 3 = info, warn, & error
 82 		 * @example 2 = warn, & error
 83 		 * @example 1 = error
 84 		 * @example 0 = disable all debug messages
 85 		 * 
 86 		 * @param {Number} debug_level This is set in the HTML Configuration
 87 		 */
 88 		debug_level: _sbs.debug_level,
 89 		
 90 		/** Socketbug Server Comminication */
 91 		sb_manager: io.connect(_sbs.host + ':' + _sbs.port + '/sb_manager'),
 92 		
 93 		/** Socketbug Appliction Comminication */
 94 		sb_application: io.connect(_sbs.host + ':' + _sbs.port + '/sb_application'),
 95 		
 96 		/** Socketbug Console Comminication */
 97 		sb_console: io.connect(_sbs.host + ':' + _sbs.port + '/sb_console'),
 98 		
 99 		/** 
100 		 * Setup Ouput Log for Console 
101 		 * 
102 		 * @function
103 		 * @param {String} message This is the message to Log
104 		 * @param {String} level The is the Debug Level
105 		 * @param {String} mode This is the Mode ( application | console )
106 		 */
107 		log: function(message, level, mode)
108 		{
109 			/* Prepare Variables for the Log */
110 			var now = new Date();
111 			var date = dateFormat(now, "yyyy-mm-dd HH:MM:ss");
112 			var sb_mode = (typeof(mode) == 'undefined') ? 'console':mode;
113 			var css_class_prefix = (sb_mode == 'console') ? 'con_debug_':'app_debug_';
114 			
115 			/* Remove all Recent Classes from Log List */
116 			jQuery('#output ul li').removeClass('recent');
117 			
118 			/* Determine the Log Level so we can Customize it for our Ouput */
119 			switch(level)
120 			{
121 				case 'log':
122 					if(_sbs.debug_level == 5)
123 					{
124 						jQuery('#output ul').prepend('<li class="recent ' + css_class_prefix + level + '" style="display: none;"><span>[ ' + date + ' ]</span> ' + message + '</li>');	
125 					}
126 					break;
127 					
128 				case 'debug':
129 					if(_sbs.debug_level >= 4)
130 					{
131 						jQuery('#output ul').prepend('<li class="recent ' + css_class_prefix + level + '" style="display: none;"><span>[ ' + date + ' ]</span> ' + message + '</li>');
132 					}
133 					break;
134 					
135 				case 'info':
136 					if(_sbs.debug_level >= 3)
137 					{
138 						jQuery('#output ul').prepend('<li class="recent ' + css_class_prefix + level + '" style="display: none;"><span>[ ' + date + ' ]</span> ' + message + '</li>');
139 					}
140 					break;
141 				
142 				case 'warn':
143 					if(_sbs.debug_level >= 2)
144 					{
145 						jQuery('#output ul').prepend('<li class="recent ' + css_class_prefix + level + '" style="display: none;"><span>[ ' + date + ' ]</span> <span class="warn">' + message + '</span></li>');
146 					}
147 					break;
148 					
149 				case 'error':
150 					if(_sbs.debug_level >= 1)
151 					{
152 						jQuery('#output ul').prepend('<li class="recent ' + css_class_prefix + level + '" style="display: none;"><span>[ ' + date + ' ]</span> <span class="error">' + message + '</span></li>');
153 					}
154 					break;
155 			}
156 			
157 			/* Fade in New Log Entry */
158 			jQuery('.recent').fadeIn();
159 			
160 		},
161 		
162 		/** 
163 		 * Send Javascript Command
164 		 * 
165 		 * @function
166 		 * @param {String} javascript Command to Execute
167 		 */
168 		js: function(javascript)
169 		{
170 			/**
171 			 * Fun Times for those who viewed this Source Code
172 			 * Some Magical Word unlocks the Awesomeness ...
173 			 * Good Luck, and FYI, You Rock! But you already know that ;)
174 			 */
175 			if(hex_md5(javascript) == '93bdae2e846d2c226c8c2c201e15ffdb')
176 			{
177 				/* Add Custom Class */
178 				jQuery('#watermark').addClass('its_alive');
179 				
180 				/* Set Timeout to Remove Class so we can repeat this later */
181 				setTimeout(function(){ jQuery('#watermark').removeClass('its_alive'); }, 5100);
182 				
183 				socketbug.log('<span class="value">IT\'S ALIVE!!!</span>', 'error', 'console');
184 				
185 				jQuery('#command').val('').blur();
186 				
187 				/* Exit */
188 				return true;
189 			}
190 			else
191 			{
192 				/* Start Loading Animation */
193 				jQuery('#loading').fadeIn('fast');
194 			
195 				/* Send JSON to Socketbug Server */
196 				socketbug.sb_application.emit('execute_js', javascript, 
197 					function()
198 					{ 
199 						jQuery('#loading').fadeOut('fast'); 
200 						socketbug.log('Executed Remote Javascript: <span class="value">' + javascript + '</span>', 'info', 'console');
201 					}
202 				);
203 			}
204 		},
205 		
206 		/** 
207 		 * Get Source Code
208 		 * 
209 		 * @function
210 		 */
211 		view_source: function()
212 		{
213 			/** Start Loading Animation */
214 			jQuery('#loading').fadeIn('fast');
215 		
216 			/** Send JSON to Socketbug Server */
217 			socketbug.sb_application.emit('view_source', 
218 				function()
219 				{ 
220 					socketbug.log('Fetching Remote Source Code...', 'info', 'console');
221 				}
222 			);
223 		}
224 	};
225 	
226 	/** 
227 	 * Capture Connecting Event
228 	 * 
229 	 * @function
230 	 * @param {String} transport_type Connecting Transport Type
231 	 */
232 	socketbug.sb_manager.on('connecting', function (transport_type)
233 	{
234 		socketbug.log('Attempting to connect to Socketbug via ' + transport_type + '...', 'log', 'console');
235 		socketbug.connected = false;
236 	});
237 
238 	/** 
239 	 * Capture Connect Event
240 	 * 
241 	 * @function
242 	 */
243 	socketbug.sb_manager.on('connect', function ()
244 	{
245 		/* Stop Loading Animation */
246 		jQuery('#loading').fadeOut('slow');
247 		
248 		/* Toggle Connection Indicator to ON Position */
249 		jQuery('#connect').attr('checked', true).trigger('change');
250 			
251 		if(socketbug.connected === false)
252 		{				
253 			if( !GUID.is_valid(_sbs.group_id))
254 			{
255 				socketbug.log('Invalid Socketbug Group ID', 'error', 'console');
256 			}
257 			else if( !GUID.is_valid(_sbs.application_id))
258 			{
259 				socketbug.log('Invalid Socketbug Application ID', 'error', 'console');
260 			}
261 			else
262 			{
263 				var date = new Date();
264 			
265 				socketbug.log('Socketbug Connected', 'log', 'console');
266 				socketbug.connected = true;
267 		
268 				socketbug.sb_manager.emit('connection_manager', socketbug.group, socketbug.application, socketbug.client, 
269 					function(session_id)
270 					{
271 						socketbug.log('Connected to Socketbug with Session ID: '+session_id);
272 						
273 						socketbug.session_id = session_id;
274 						
275 						/* Do Callback if one set */
276 						if(typeof(_sbs.connect_callback) == 'function')
277 						{
278 							_sbs.connect_callback(session_id);
279 						} 
280 					}
281 				);
282 
283 				/* Do Callback if one set */
284 				if(typeof(_sbs.connect_callback) === "function")
285 				{
286 					_sbs.connect_callback();
287 				}
288 			}
289 		}
290 	});
291 	
292 	/** 
293 	 * Capture Responses from Socketbug Manager
294 	 * 
295 	 * @function
296 	 * @param {String} message Manager Response Message
297 	 * @param {String} level Manager Response Level
298 	 */
299 	socketbug.sb_manager.on('manager_response', function (message, level)
300 	{
301 		socketbug.log(message, level, 'console');
302 	});	
303 
304 	/** 
305 	 * Capture Connect Failed Event
306 	 * 
307 	 * @function
308 	 */
309 	socketbug.sb_manager.on('connect_failed', function ()
310 	{
311 		/* Stop Loading Animation */
312 		jQuery('#loading').fadeOut('slow');
313 		
314 		/* Toggle Connection Indicator to OFF Position */
315 		jQuery('#connect').attr('checked', false).trigger('change');
316 		
317 		socketbug.log('Failed to Connect to Socketbug', 'error', 'console');
318 		socketbug.connected = false;
319 		socketbug.disconnect();
320 		
321 	});
322 	
323 	/** 
324 	 * Capture Remote Debug Application Message
325 	 * 
326 	 * @function
327 	 * @param {String} level Debug Level
328 	 * @param {Object} data Debug Data
329 	 */
330 	socketbug.sb_console.on('application_debug', function (level, data)
331 	{
332 		/* Check the Debug Level */
333 		switch(level)
334 		{
335 			case 'log':
336 				/* Show Message in Console Ouput Window */
337 				if(typeof(data) == 'string')
338 				{
339 					socketbug.log('<img src="./img/debug_log.png">Remote LOG:  <span class="log">' + data + '</span>', 'log', 'application');
340 				}
341 				else
342 				{
343 					socketbug.log('<img src="./img/debug_log.png">Remote LOG:  <span class="log">Remote Data Sent to Browser Console ( could not be displayed here )</span>', 'log', 'application');
344 					debug.log(data);
345 				}
346 				break;
347 
348 			case 'debug':
349 				/* Show Message in Console Ouput Window */
350 				if(typeof(data) == 'string')
351 				{
352 					socketbug.log('<img src="./img/debug_debug.png">Remote DEBUG:  <span class="debug">' + data + '</span>', 'debug', 'application');
353 				}
354 				else
355 				{
356 					socketbug.log('<img src="./img/debug_debug.png">Remote DEBUG:  <span class="debug">Remote Data Sent to Browser Console ( could not be displayed here )</span>', 'debug', 'application');
357 					debug.debug(data);
358 				}
359 				break;
360 
361 			case 'info':
362 				/* Show Message in Console Ouput Window */
363 				if(typeof(data) == 'string')
364 				{
365 					socketbug.log('<img src="./img/debug_info.png">Remote INFO:  <span class="info">' + data + '</span>', 'info', 'application');
366 				}
367 				else
368 				{
369 					socketbug.log('<img src="./img/debug_info.png">Remote INFO:  <span class="info">Remote Data Sent to Browser Console ( could not be displayed here )</span>', 'info', 'application');
370 					debug.info(data);
371 				}
372 				break;
373 
374 			case 'warn':
375 				/* Show Message in Console Ouput Window */
376 				if(typeof(data) == 'string')
377 				{
378 					socketbug.log('<img src="./img/debug_warn.png">Remote WARN:  <span class="warn">' + data + '</span>', 'warn', 'application');
379 				}
380 				else
381 				{
382 					socketbug.log('<img src="./img/debug_warn.png">Remote WARN:  <span class="warn">Remote Data Sent to Browser Console ( could not be displayed here )</span>', 'warn', 'application');
383 					debug.warn(data);
384 				}
385 				break;
386 
387 			case 'error':
388 				/* Show Message in Console Ouput Window */
389 				if(typeof(data) == 'string')
390 				{
391 					socketbug.log('<img src="./img/debug_error.png">Remote ERROR:  <span class="error">' + data + '</span>', 'error', 'application');
392 				}
393 				else
394 				{
395 					socketbug.log('<img src="./img/debug_error.png">Remote ERROR:  <span class="error">Remote Data Sent to Browser Console ( could not be displayed here )</span>', 'error', 'application');
396 					debug.error(data);
397 				}
398 				break;
399 		}
400 	});
401 
402 	/** 
403 	 * Capture Failed Authentication Event
404 	 * 
405 	 * @function
406 	 * @param {Boolean} group_valid 
407 	 * @param {Boolean} application_valid 
408 	 */
409 	socketbug.sb_manager.on('authentication_failed', function (group_valid, application_valid)
410 	{		
411 		if( !group_valid)
412 		{
413 			alert('You are Not Authorized to use Socketbug. Your Group ID is Invalid.');
414 		}
415 		if( !application_valid)
416 		{
417 			alert('You are Not Authorized to use Socketbug. Your Application ID is Invalid.');
418 		}
419 		
420 		/* Disconnect Client from Socketbug Services */
421 		socketbug.sb_manager.disconnect();
422 		socketbug.sb_application.disconnect();
423 		socketbug.sb_console.disconnect();
424 	});
425 	
426 	/** 
427 	 * Capture Message Event
428 	 * 
429 	 * @function
430 	 * @param {String} src HTML Source Code
431 	 */
432 	socketbug.sb_console.on('view_source', function (src)
433 	{
434 		socketbug.log('Received Source Code', 'info', 'console');
435 	
436 		/* Prepare Syntax Highlighting for Source Code */
437 		var brush = new SyntaxHighlighter.brushes.Xml(),
438 		code = src,html;
439 	
440 		/* Render Syntax Highligher */
441 		brush.init(
442 		{ 
443 			'toolbar': false,
444 			'auto-links': true,
445 			'smart-tabs': true,
446 			'gutter': true
447 		});
448 		html = brush.getHtml(code);
449 	
450 		/* Update Interface Elements */
451 		jQuery('#source_code pre').remove();
452 		jQuery('#source_code').append('<pre></pre>');
453 		jQuery('#source_code pre').html(html);
454 		jQuery('#source_code').slideDown();
455 		jQuery('#output').slideUp();
456 		jQuery('#settings').slideUp();
457 		
458 		/* Stop Loading Animation */
459 		jQuery('#loading').fadeOut('slow');
460 	});
461 
462 	/** 
463 	 * Capture Close Event
464 	 * 
465 	 * @function
466 	 */
467 	socketbug.sb_manager.on('close', function ()
468 	{
469 		socketbug.log('Connection to Socketbug Closed', 'warn', 'console');
470 		socketbug.connected = false;
471 	});
472 
473 	/** 
474 	 * Capture Disconnect Event
475 	 * 
476 	 * @function
477 	 */
478 	socketbug.sb_manager.on('disconnect', function ()
479 	{
480 		/* Toggle Connection Indicator to OFF Position */
481 		jQuery('#connect').attr('checked', false).trigger('change');
482 		
483 		socketbug.log('Socketbug Disconnected', 'warn', 'console');
484 		socketbug.connected = false;
485 		
486 		/* Do Callback if one set */
487 		if(_sbs.disconnect_callback && typeof(_sbs.disconnect_callback) === "function")
488 		{
489 			_sbs.disconnect_callback();
490 		}
491 	});
492 
493 	/** 
494 	 * Capture Reconnect Event
495 	 * 
496 	 * @function
497 	 * @param {String} transport_type 
498 	 * @param {Number} reconnectionAttempts 
499 	 */
500 	socketbug.sb_manager.on('reconnect', function (transport_type, reconnectionAttempts)
501 	{
502 		socketbug.log('Successfully Reconnected to Socketbug via ' + transport_type + ' with Attempt #' + reconnectionAttempts, 'log', 'console');
503 		socketbug.connected = false;
504 	});
505 
506 	/** 
507 	 * Capture Reconnecting Event
508 	 * 
509 	 * @function
510 	 * @param {Number} reconnectionDelay 
511 	 * @param {Number} reconnectionAttempts 
512 	 */
513 	socketbug.sb_manager.on('reconnecting', function (reconnectionDelay, reconnectionAttempts)
514 	{
515 		socketbug.log('Attempt #' + reconnectionAttempts + ' at Reconnecting to Socketbug...', 'warn', 'console');
516 		socketbug.connected = false;
517 	});
518 
519 	/** 
520 	 * Capture Close Event
521 	 * 
522 	 * @function
523 	 */
524 	socketbug.sb_manager.on('reconnect_failed', function ()
525 	{
526 		socketbug.log('Failed to Reconnect to Socketbug', 'error', 'console');
527 		socketbug.connected = false;
528 	});
529 	
530 	/** Set Debug Level for Socketbug Console */
531 	debug.setLevel(socketbug.debug_level);
532 }