Skip to content
Browse files

first commit

  • Loading branch information...
0 parents commit 9cb31f42466ac3d314429e85fb1591505e8a9d2d @tbrasington committed
BIN .DS_Store
Binary file not shown.
53 controller.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Controller</title>
+
+ <link rel="stylesheet" type="text/css" href="css/style.css"/>
+
+ <script src="js/utility.class.js" type="text/javascript"></script>
+ <script src="js/connection_client.class.js" type="text/javascript"></script>
+ <script src="js/controller.js" type="text/javascript"></script>
+ <script src="js/view.js" type="text/javascript"></script>
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js" type="application/javascript"></script>
+
+ </head>
+ <body>
+
+ <div id="container">
+ <div class="block">
+ <div id="view"></div>
+ </div>
+ </div>
+
+ <script type="text/javascript">
+ $(document).ready(function() {
+
+
+ var connection_client = new Connection_Client();
+
+ // Set the name of the device for logging actions, debugging etc
+ connection_client.device_reference = Math.floor(Math.random()*99999999999).toString();
+
+
+ connection_client.init(function() {
+ console.log("Callback initiated");
+ });
+
+
+ var controller_object = new controller();
+ controller_object.node_connection_client = connection_client;
+
+ controller_object.init()
+
+ var view_object = new view();
+ view_object.node_connection_client = connection_client;
+
+ view_object.init()
+
+
+
+ });
+ </script>
+ </body>
+</html>
15 css/style.css
@@ -0,0 +1,15 @@
+html, body{
+ margin:0px;
+ padding: 0px:
+ color:#000;
+ background: #fff;
+ font-family: Monaco;
+ width: 100%;
+ height: 100%;
+ text-align: center;
+ overflow: hidden;
+}
+
+img
+{
+}
BIN image/.DS_Store
Binary file not shown.
BIN image/0.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN image/1.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN image/2.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN image/3.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN image/4.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
284 js/connection_client.class.js
@@ -0,0 +1,284 @@
+/**
+ * @fileoverview Connection_Client Class, contains the class known as Connection_Client
+ * @author tom@2c2d.com (Thomas Brasington)
+ */
+
+
+/**
+ * Connection_Client Class
+ * @class Connection_Client
+ * @version 2011 alpha 1.0
+ * @namespace Starts a connection to the node server
+ */
+ var Connection_Client = function() {
+
+ /**
+ * @description A reference to the constructed class
+ * @type Variable
+ * @borrows this as that
+ */
+ var that = this;
+
+ /**
+ * @description The instance of the views model
+ * @type Object
+ */
+ this.model = null,
+
+ /**
+ * @description The address of the node server
+ * @type String
+ */
+
+ this.node_server = "http://192.168.0.15",
+
+ /**
+ * @description The port of the node server
+ * @type String
+ */
+ this.node_port = "8001",
+ /**
+ * @description The name of the call to listen to node
+ * @type String
+ */
+ this.process_server_listen = "/recv",
+ /**
+ * @description The name of the call to see who is listening to node
+ * @type String
+ */
+ this.process_client_prescence_check = "/who",
+ /**
+ * @description The name of the call to join node
+ * @type String
+ */
+ this.process_client_join = "/join",
+
+ /**
+ * @description The name of the call to leave node
+ * @type String
+ */
+ this.process_client_part = "/part",
+
+ /**
+ * @description The name of the call to send to node
+ * @type String
+ */
+ this.process_client_send= "/send",
+
+ /**
+ * @description The name of the join sub-call used when sending to node
+ * @type String
+ */
+ this.sub_process_join = 'join',
+
+ /**
+ * @description The name of the command sub-call used when sending to node
+ * @type String
+ */
+ this.sub_process_command = 'command',
+
+ /**
+ * @description The name of the connected device to node.
+ * @type String
+ */
+ this.device_reference = null,
+
+ /**
+ * @description The id of the current connection to node.
+ * @type Number
+ */
+ this.my_current_id = null,
+
+ /**
+ * @description The last time node made a call. This is updated everytime a query is made with a unix timestamp
+ * @type Number
+ */
+ this.last_message_time = 1,
+
+ /**
+ * @description The count of how many errors have happened in query. If it hits the limit it stops and reconnects
+ * @type Number
+ */
+ this.transmission_errors = 0,
+
+
+ /**
+ * @description Starts the connection to node off
+ * @param {Function} callback provides a method for firing a callback after the JSON data has been loaded.
+ */
+ this.listener_setup = function(callback) {
+ jQuery(window).unload(function () {
+ jQuery.ajax({
+ url: that.node_server + ":" + that.node_port + that.process_client_part,
+ data: "id="+that.my_current_id,
+ success: function(result) {
+
+ if(callback != null) { callback(); }
+ },
+ dataType: "json"
+ });
+ });
+
+ if(callback != null) { callback(); }
+ },
+ /**
+ * @description Initialises the Connection_Client class<br>
+ * Joins with node and starts the listener.
+ * @param {Function} callback provides a method for firing a callback
+ */
+ this.init = function(callback) {
+
+ that.join(function()
+ {
+ that.listener_setup(function()
+ {
+ that.listen();
+ });
+ });
+ },
+
+ /**
+ * @description Joins the device with node
+ * @param {Function} callback provides a method for firing a callback after the JSON data has been loaded.
+ */
+ this.join = function(callback) {
+
+ //console.log("Node server address: " + that.node_server + ":" + that.node_port);
+
+ var url = that.node_server + ":" + that.node_port + that.process_client_join;
+
+ jQuery.ajax({
+ url: url,
+ data: "name="+that.device_reference,
+ success: function(result) {
+
+ // Set my_current_id with the session id
+ that.my_current_id = result.mySession.id;
+
+ if(callback != null) { callback(); }
+ },
+ dataType: "json"
+ });
+ },
+
+ /**
+ * @description Listens for new objects that the clients will process<br>
+ * The part that updates the model is taken from data.messages. This processes the message log and fires and update to the Model class
+ * which has been bound to the instance of the Connection_Client.
+ * @param {Object} data a JSON object.
+ */
+ this.listen = function(data) {
+
+ if (that.transmission_errors > 2) {
+ that.handle_reconnect();
+ return;
+ }
+
+ if (data && data.resource) {
+ resource = data.resource;
+ that.manage_memory(resource);
+ }
+
+ /*
+
+ Processess messages
+
+ Loops through message object
+ Organsies messages by command, join, recieve
+ updates controllers and views
+
+ */
+
+ var commandMessage = [], commands= 0, joinMessage = [], joins = 0;
+
+ // Process any updates if we have some...
+ if (data && data.messages)
+ {
+ for (var i = 0; i < data.messages.length; i++)
+ {
+ var message = data.messages[i];
+ //console.log(message.type)
+ //track oldest message so we only request newer messages from server
+ if (message.timestamp > that.last_message_time)
+ {
+ that.last_message_time = message.timestamp;
+ }
+ //dispatch new messages to their appropriate handlers
+ switch (message.type)
+ {
+ case that.sub_process_command:
+ //that.deal_with_command(message);
+ commandMessage[commands] = message;
+ commands++;
+ break;
+
+
+ case that.sub_process_join:
+ //that.deal_with_command(message);
+ joinMessage[joins] = message;
+ joins++;
+ break;
+ }
+
+ // Once we have looped through all messages, fire off the commands as single objects rather than multiple times
+ // This is somewhat blocking
+ if(i == data.messages.length-1)
+ {
+ if(commands>0)
+ {
+ var image = null;
+ //console.log()
+ jQuery(window).trigger('load_image',commandMessage[commandMessage.length-1])
+ }
+
+ }
+ }
+ }
+
+ //make another request
+ jQuery.ajax({
+ cache: false,
+ type: "GET",
+ url: that.node_server + ":" + that.node_port + that.process_server_listen,
+ dataType: "json",
+ data: { since: that.last_message_time, id: that.my_current_id },
+ error: function (error) {
+ console.log("Error");
+ that.deal_with_error(error);
+ that.transmission_errors += 1;
+ //don't flood the server on error, wait before retrying
+ setTimeout(that.listen, 10*1000);
+ },
+ success: function (data) {
+ that.transmission_errors = 0;
+ // Success, time to start listening again
+ that.listen(data);
+ }
+ });
+ },
+
+ /**
+ * @description Handles a reconnect to node
+ */
+ this.handle_reconnect = function() {
+ //console.log("Need to handle the reconnection here.");
+ },
+
+
+ /**
+ * @description Manages the memory being used by node
+ * @param {Object} memory Yet to be defined
+ */
+ this.manage_memory = function(memory) {
+ //console.log(resource);
+ },
+
+
+ /**
+ * @description Manages the errors thrown by node
+ * @param {Object} error Yet to be defined
+ */
+ this.deal_with_error = function(error) {
+ //console.log(error);
+ }
+}
53 js/controller.js
@@ -0,0 +1,53 @@
+var controller = function()
+{
+
+ var that = this;
+
+ this.node_connection_client=null,
+ this.total_items = 107,
+ this.position = 0,
+
+ this.init = function()
+ {
+ jQuery('body').keydown( function(e){
+
+
+ if(e.keyCode==32 || e.keyCode==39)
+ {
+ that.position++;
+ if(that.position>=that.total_items)
+ {
+ that.position = 0;
+ }
+ }
+
+
+ if(e.keyCode==37)
+ {
+ that.position--;
+
+ if(that.position<=0)
+ {
+ that.position = that.total_items-1;
+ }
+ }
+
+ if(e.keyCode == 32 || e.keyCode == 37 || e.keyCode == 39)
+ {
+ // URL that the request will use
+ var url = that.node_connection_client.node_server + ":" + that.node_connection_client.node_port + that.node_connection_client.process_client_send;
+ //console.log(url)
+ // The query string attached to url which will contain what command to use and any references to the DOM elements
+ var query_string = "id=" +that.node_connection_client.my_current_id +"&name="+that.node_connection_client.device_reference + "&command_data=" + encodeURIComponent(that.position);
+
+ // Send the request
+ jQuery.ajax({
+ url: url,
+ type : "GET",
+ data: query_string,
+ dataType: "json"
+ });
+ }
+ });
+ }
+}
42 js/utility.class.js
@@ -0,0 +1,42 @@
+/**
+ * @fileoverview Contains various helper utilities that the app
+ * needs that aren't in jQuery or another plugin
+ * @author tom@2c2d.co.uk (Thomas Brasington)
+ */
+
+/**
+ * Utility Class
+ * @class Utility
+ * @version 2011 alpha 1.0
+ * @namespace A collection of functions needed by the app
+ */
+var Utility = {
+
+ /**
+ * @description newElement builds a new DOM Element <br>jQuery has no method for building new elements in one line so this method takes care of that
+ * @type {Function}
+ * @param {DOMElement} el the type of DOMElement you want to construct. e.g. "div"
+ * @param {String} cssClass the name of the css class you wish to use
+ * @param {String} id the id of the DOMElement
+ * @returns {DOMElement} The new DOMElement.
+ */
+ newElement : function (el, cssClass, id)
+ {
+
+ var newEl = document.createElement(el);
+ newEl.className = cssClass.substr(1);
+ newEl.id = id;
+ return newEl;
+ },
+
+ /**
+ * @description escape_id for cleaning string<br>jQuery cannot cope with slashes, periods etc so they have to be escaped
+ * @type {Function}
+ * @param {String} my_id the name of an id that needs to be escaped
+ * @returns {String} The escape string prepended with a hash symbol
+ */
+ escape_id : function (my_id)
+ {
+ return '#' + my_id.replace(/(:|\.)/g,'\\$1');
+ }
+}
54 js/view.js
@@ -0,0 +1,54 @@
+var view = function()
+{
+
+ var that = this;
+
+ this.node_connection_client=null,
+
+ this.init = function()
+ {
+ jQuery(window).bind('load_image', function(e,data){
+ var alignX=0.5, alignY=0.5, fitX, fitY;
+
+
+ var new_image = new Image();
+ new_image.onload = function()
+ {
+ jQuery('body').empty();
+
+ var parentWidth = jQuery(window).width();
+ var parentHeight = jQuery(window).height();
+
+ // Get the image width and height
+ var imageWidth = new_image.width;
+ var imageHeight = new_image.height;
+
+
+ // Get the ratios which would stretch the image disproportionally to fit both dimensions exactly
+ var ratioX = parentWidth / imageWidth;
+ var ratioY = parentHeight / imageHeight;
+ var dimensionRatio = ratioX / ratioY
+
+
+ var new_width = parentWidth;
+ var new_height = parentWidth * dimensionRatio;
+
+ if(new_height>parentHeight)
+ {
+ new_height = parentHeight;
+ new_width = parentWidth/dimensionRatio
+ }
+
+ // Position the image element according to the alignment value
+ new_image.style.marginTop = (0.5 * (parentHeight-new_height)) + "px";
+ new_image.style.width = new_width + "px";
+ new_image.style.height = new_height + "px";
+
+ jQuery('body').append(new_image);
+ }
+
+ new_image.src = 'image/' + data.command_data + '.jpg';
+
+ })
+ }
+}
BIN server/.DS_Store
Binary file not shown.
266 server/fu.js
@@ -0,0 +1,266 @@
+var createServer = require("http").createServer;
+var readFile = require("fs").readFile;
+var sys = require("util");
+var url = require("url");
+DEBUG = false;
+
+var fu = exports;
+
+var NOT_FOUND = "Not Found\n";
+
+function notFound(req, res) {
+ res.writeHead(404, { "Content-Type": "text/plain"
+ , "Content-Length": NOT_FOUND.length
+ });
+ res.end(NOT_FOUND);
+}
+
+var getMap = {};
+
+fu.get = function (path, handler) {
+ getMap[path] = handler;
+};
+var server = createServer(function (req, res) {
+ if (req.method === "GET" || req.method === "HEAD") {
+ var handler = getMap[url.parse(req.url).pathname] || notFound;
+
+ res.simpleText = function (code, body) {
+ res.writeHead(code, { "Content-Type": "text/plain"
+ , "Content-Length": body.length
+ });
+ res.end(body);
+ };
+
+ res.simpleJSON = function (code, obj) {
+ var body = new Buffer(JSON.stringify(obj));
+ res.writeHead(code, { "Content-Type": "text/json"
+ , "Content-Length": body.length
+ });
+ res.end(body);
+ };
+
+ handler(req, res);
+ }
+});
+
+fu.listen = function (port, host) {
+ server.listen(port, host);
+ sys.puts("Server at http://" + (host || "127.0.0.1") + ":" + port.toString() + "/");
+};
+
+fu.close = function () { server.close(); };
+
+function extname (path) {
+ var index = path.lastIndexOf(".");
+ return index < 0 ? "" : path.substring(index);
+}
+
+fu.staticHandler = function (filename) {
+ var body, headers;
+ var content_type = fu.mime.lookupExtension(extname(filename));
+
+ function loadResponseData(callback) {
+ if (body && headers && !DEBUG) {
+ callback();
+ return;
+ }
+
+ sys.puts("loading " + filename + "...");
+ readFile(filename, function (err, data) {
+ if (err) {
+ sys.puts("Error loading " + filename);
+ } else {
+ body = data;
+ headers = { "Content-Type": content_type
+ , "Content-Length": body.length
+ };
+ if (!DEBUG) headers["Cache-Control"] = "public";
+ sys.puts("static file " + filename + " loaded");
+ callback();
+ }
+ });
+ }
+
+ return function (req, res) {
+ loadResponseData(function () {
+ res.writeHead(200, headers);
+ res.end(req.method === "HEAD" ? "" : body);
+ });
+ }
+};
+
+// stolen from jack- thanks
+fu.mime = {
+ // returns MIME type for extension, or fallback, or octet-steam
+ lookupExtension : function(ext, fallback) {
+ return fu.mime.TYPES[ext.toLowerCase()] || fallback || 'application/octet-stream';
+ },
+
+ // List of most common mime-types, stolen from Rack.
+ TYPES : { ".3gp" : "video/3gpp"
+ , ".a" : "application/octet-stream"
+ , ".ai" : "application/postscript"
+ , ".aif" : "audio/x-aiff"
+ , ".aiff" : "audio/x-aiff"
+ , ".asc" : "application/pgp-signature"
+ , ".asf" : "video/x-ms-asf"
+ , ".asm" : "text/x-asm"
+ , ".asx" : "video/x-ms-asf"
+ , ".atom" : "application/atom+xml"
+ , ".au" : "audio/basic"
+ , ".avi" : "video/x-msvideo"
+ , ".bat" : "application/x-msdownload"
+ , ".bin" : "application/octet-stream"
+ , ".bmp" : "image/bmp"
+ , ".bz2" : "application/x-bzip2"
+ , ".c" : "text/x-c"
+ , ".cab" : "application/vnd.ms-cab-compressed"
+ , ".cc" : "text/x-c"
+ , ".chm" : "application/vnd.ms-htmlhelp"
+ , ".class" : "application/octet-stream"
+ , ".com" : "application/x-msdownload"
+ , ".conf" : "text/plain"
+ , ".cpp" : "text/x-c"
+ , ".crt" : "application/x-x509-ca-cert"
+ , ".css" : "text/css"
+ , ".csv" : "text/csv"
+ , ".cxx" : "text/x-c"
+ , ".deb" : "application/x-debian-package"
+ , ".der" : "application/x-x509-ca-cert"
+ , ".diff" : "text/x-diff"
+ , ".djv" : "image/vnd.djvu"
+ , ".djvu" : "image/vnd.djvu"
+ , ".dll" : "application/x-msdownload"
+ , ".dmg" : "application/octet-stream"
+ , ".doc" : "application/msword"
+ , ".dot" : "application/msword"
+ , ".dtd" : "application/xml-dtd"
+ , ".dvi" : "application/x-dvi"
+ , ".ear" : "application/java-archive"
+ , ".eml" : "message/rfc822"
+ , ".eps" : "application/postscript"
+ , ".exe" : "application/x-msdownload"
+ , ".f" : "text/x-fortran"
+ , ".f77" : "text/x-fortran"
+ , ".f90" : "text/x-fortran"
+ , ".flv" : "video/x-flv"
+ , ".for" : "text/x-fortran"
+ , ".gem" : "application/octet-stream"
+ , ".gemspec" : "text/x-script.ruby"
+ , ".gif" : "image/gif"
+ , ".gz" : "application/x-gzip"
+ , ".h" : "text/x-c"
+ , ".hh" : "text/x-c"
+ , ".htm" : "text/html"
+ , ".html" : "text/html"
+ , ".ico" : "image/vnd.microsoft.icon"
+ , ".ics" : "text/calendar"
+ , ".ifb" : "text/calendar"
+ , ".iso" : "application/octet-stream"
+ , ".jar" : "application/java-archive"
+ , ".java" : "text/x-java-source"
+ , ".jnlp" : "application/x-java-jnlp-file"
+ , ".jpeg" : "image/jpeg"
+ , ".jpg" : "image/jpeg"
+ , ".js" : "application/javascript"
+ , ".json" : "application/json"
+ , ".log" : "text/plain"
+ , ".m3u" : "audio/x-mpegurl"
+ , ".m4v" : "video/mp4"
+ , ".man" : "text/troff"
+ , ".mathml" : "application/mathml+xml"
+ , ".mbox" : "application/mbox"
+ , ".mdoc" : "text/troff"
+ , ".me" : "text/troff"
+ , ".mid" : "audio/midi"
+ , ".midi" : "audio/midi"
+ , ".mime" : "message/rfc822"
+ , ".mml" : "application/mathml+xml"
+ , ".mng" : "video/x-mng"
+ , ".mov" : "video/quicktime"
+ , ".mp3" : "audio/mpeg"
+ , ".mp4" : "video/mp4"
+ , ".mp4v" : "video/mp4"
+ , ".mpeg" : "video/mpeg"
+ , ".mpg" : "video/mpeg"
+ , ".ms" : "text/troff"
+ , ".msi" : "application/x-msdownload"
+ , ".odp" : "application/vnd.oasis.opendocument.presentation"
+ , ".ods" : "application/vnd.oasis.opendocument.spreadsheet"
+ , ".odt" : "application/vnd.oasis.opendocument.text"
+ , ".ogg" : "application/ogg"
+ , ".p" : "text/x-pascal"
+ , ".pas" : "text/x-pascal"
+ , ".pbm" : "image/x-portable-bitmap"
+ , ".pdf" : "application/pdf"
+ , ".pem" : "application/x-x509-ca-cert"
+ , ".pgm" : "image/x-portable-graymap"
+ , ".pgp" : "application/pgp-encrypted"
+ , ".pkg" : "application/octet-stream"
+ , ".pl" : "text/x-script.perl"
+ , ".pm" : "text/x-script.perl-module"
+ , ".png" : "image/png"
+ , ".pnm" : "image/x-portable-anymap"
+ , ".ppm" : "image/x-portable-pixmap"
+ , ".pps" : "application/vnd.ms-powerpoint"
+ , ".ppt" : "application/vnd.ms-powerpoint"
+ , ".ps" : "application/postscript"
+ , ".psd" : "image/vnd.adobe.photoshop"
+ , ".py" : "text/x-script.python"
+ , ".qt" : "video/quicktime"
+ , ".ra" : "audio/x-pn-realaudio"
+ , ".rake" : "text/x-script.ruby"
+ , ".ram" : "audio/x-pn-realaudio"
+ , ".rar" : "application/x-rar-compressed"
+ , ".rb" : "text/x-script.ruby"
+ , ".rdf" : "application/rdf+xml"
+ , ".roff" : "text/troff"
+ , ".rpm" : "application/x-redhat-package-manager"
+ , ".rss" : "application/rss+xml"
+ , ".rtf" : "application/rtf"
+ , ".ru" : "text/x-script.ruby"
+ , ".s" : "text/x-asm"
+ , ".sgm" : "text/sgml"
+ , ".sgml" : "text/sgml"
+ , ".sh" : "application/x-sh"
+ , ".sig" : "application/pgp-signature"
+ , ".snd" : "audio/basic"
+ , ".so" : "application/octet-stream"
+ , ".svg" : "image/svg+xml"
+ , ".svgz" : "image/svg+xml"
+ , ".swf" : "application/x-shockwave-flash"
+ , ".t" : "text/troff"
+ , ".tar" : "application/x-tar"
+ , ".tbz" : "application/x-bzip-compressed-tar"
+ , ".tcl" : "application/x-tcl"
+ , ".tex" : "application/x-tex"
+ , ".texi" : "application/x-texinfo"
+ , ".texinfo" : "application/x-texinfo"
+ , ".text" : "text/plain"
+ , ".tif" : "image/tiff"
+ , ".tiff" : "image/tiff"
+ , ".torrent" : "application/x-bittorrent"
+ , ".tr" : "text/troff"
+ , ".txt" : "text/plain"
+ , ".vcf" : "text/x-vcard"
+ , ".vcs" : "text/x-vcalendar"
+ , ".vrml" : "model/vrml"
+ , ".war" : "application/java-archive"
+ , ".wav" : "audio/x-wav"
+ , ".wma" : "audio/x-ms-wma"
+ , ".wmv" : "video/x-ms-wmv"
+ , ".wmx" : "video/x-ms-wmx"
+ , ".wrl" : "model/vrml"
+ , ".wsdl" : "application/wsdl+xml"
+ , ".xbm" : "image/x-xbitmap"
+ , ".xhtml" : "application/xhtml+xml"
+ , ".xls" : "application/vnd.ms-excel"
+ , ".xml" : "application/xml"
+ , ".xpm" : "image/x-xpixmap"
+ , ".xsl" : "application/xml"
+ , ".xslt" : "application/xslt+xml"
+ , ".yaml" : "text/yaml"
+ , ".yml" : "text/yaml"
+ , ".zip" : "application/zip"
+ }
+};
296 server/server.js
@@ -0,0 +1,296 @@
+HOST = null; // localhost
+PORT = 8001;
+
+var SESSION_TIMEOUT = 900 * 1000,
+ MESSAGE_BACKLOG = 500;
+
+// Logging - Make sure to check on the memory usage
+var mem = process.memoryUsage(),
+memProcess = null,
+sessionProcess = null;
+
+/***********************************************************************
+/
+/ Repeating Methods
+/ Methods which repeat. Just putting them into a container to
+/ be able to control when they start running.
+/
+/
+***********************************************************************/
+
+function repeatingTasksSetup() {
+ setInterval(function () {
+ mem = process.memoryUsage();
+ }, 10*1000);
+
+ // interval to kill off old sessions
+ setInterval(function () {
+ //console.log("Dropping off all dead clients");
+ var now = new Date();
+ for (var id in connectedClients) {
+ if (!connectedClients.hasOwnProperty(id)) continue;
+ var connectedClient = connectedClients[id];
+ if (now - connectedClient['timestamp'] > SESSION_TIMEOUT) {
+ connectedClient.destroy();
+ }
+ }
+ }, 1000);
+}
+
+repeatingTasksSetup();
+
+// Global vars
+
+var connectedClients = {},
+fu = require("./fu"),
+sys = require("util"),
+url = require("url"),
+qs = require("querystring");
+
+// Start the server
+
+fu.listen(Number(process.env.PORT || PORT), HOST);
+
+/***********************************************************************
+/
+/ Main constructors
+/ These methods create any constructor which can be remade/respawned.
+/ Constructors should handle persisting themselves if appropriate.
+/
+/
+***********************************************************************/
+
+var bespoke_session = new function () {
+ var command_log = [], callbacks = [];
+
+ this.appendMessage = function (id, type, command_data) {
+ var m = {
+ id: id,
+ type: type, // "command", "join", "part"
+ command_data: command_data,
+ timestamp: (new Date()).getTime()
+ };
+
+ switch (type) {
+ case "command":
+ console.log(id + " commanded : " + type + " data : " + command_data);
+ break;
+ case "join":
+ console.log(id + " joined");
+ break;
+ case "part":
+ console.log(id + " parted");
+ break;
+ }
+
+ command_log.push(m);
+ while (callbacks.length > 0) {
+ callbacks.shift().callback([m]);
+ }
+
+ while (command_log.length > MESSAGE_BACKLOG) {
+ command_log.shift();
+ }
+
+ };
+
+ this.query = function (since, callback) {
+ var messages_to_send = [];
+ for (var i = 0; i < command_log.length; i++) {
+ var log = command_log[i];
+ if (log.timestamp > since)
+ messages_to_send.push(log)
+ }
+
+ if (messages_to_send.length != 0) {
+ callback(messages_to_send);
+ } else {
+ callbacks.push({ timestamp: new Date(), callback: callback });
+ }
+ };
+
+ // Reset the connection after 30 seconds to make sure we don't let a client hold on too long, the client should then handle a reconnect.
+ setInterval(function () {
+ var now = new Date();
+ while (callbacks.length > 0 && now - callbacks[0].timestamp > 30*1000) {
+ callbacks.shift().callback([]);
+ }
+ }, 1000);
+};
+
+
+
+/***********************************************************************
+/
+/ Main communication methods
+/ These methods handle sending, receiving, joining and parting
+/ communications. They should be extended to pass through all
+/ comms. between clients and controllers.
+/
+***********************************************************************/
+
+// Ask who is currently connected
+
+fu.get("/who", function (req, res) {
+ res.simpleJSON(200, {
+ clients: connectedClients,
+ resource: mem.resource
+ });
+});
+
+// Add a new client to the already existing stack
+
+fu.get("/join", function (req, res) {
+ //console.log(req);
+
+ var URLParams = parseURL(req);
+ var name = URLParams.name;
+ if(name == null) { console.log("No name given for join"); return null }
+ var session = createSession(name);
+ //console.log("Session created for : " + session.name);
+ res.writeHead(200, {
+ 'Content-Type': 'application/json',
+ 'Access-Control-Allow-Origin' : '*',
+ 'Access-Control-Allow-Methods': 'GET, POST'
+ });
+
+ var body = JSON.stringify({
+ clients: connectedClients,
+ mySession : session,
+ resource: mem.resource
+ });
+
+ res.end(body);
+
+ bespoke_session.appendMessage(session.id, "join");
+
+});
+
+// Send a new message to all connected clients
+
+fu.get("/send", function (req, res) {
+ var URLParams = parseURL(req);
+
+
+
+ var id = URLParams.id;
+ var name = URLParams.name;
+ var command_data = URLParams.command_data;
+
+ var session = connectedClients[id];
+
+ if (!session || !command_data) {
+
+ res.writeHead(400, {
+ 'Content-Type' : 'application/json',
+ 'Access-Control-Allow-Origin' : '*',
+ 'Access-Control-Allow-Methods': 'GET, POST'
+ });
+ var body = JSON.stringify({ error: "No such session id" });
+ res.end(body);
+ return;
+ }
+
+ session.poke();
+ res.writeHead(200, {
+ 'Content-Type' : 'application/json',
+ 'Access-Control-Allow-Origin' : '*'
+ });
+
+ bespoke_session.appendMessage(session.id, "command", command_data);
+
+ var body = JSON.stringify({ resource: mem.resource });
+ res.end(body);
+
+
+});
+
+// Listen for new messages
+
+fu.get("/recv", function (req, res) {
+
+ var URLParams = parseURL(req);
+
+ // Get the CORS working
+
+ if (!URLParams.since) {
+
+ res.writeHead(400, {
+ 'Content-Type' : 'application/json',
+ 'Access-Control-Allow-Origin' : '*'
+ });
+
+ var body = JSON.stringify({
+ error: "Must send a since parameter"
+ });
+
+ res.end(body);
+ return;
+ }
+
+ var id = URLParams.id;
+ var curSession;
+ if (id && connectedClients[id]) {
+ curSession = connectedClients[id];
+ curSession.poke();
+ }
+
+ var since = parseInt(URLParams.since, 10);
+
+ bespoke_session.query(since, function (messages) {
+ if (curSession) curSession.poke();
+ res.writeHead(200, {
+ 'Content-Type' : 'application/json',
+ 'Access-Control-Allow-Origin' : '*'
+ });
+ var body = JSON.stringify({ messages: messages, resource: mem.resource });
+ res.end(body);
+ });
+});
+
+/***********************************************************************
+/
+/ Utility Methods
+/ These methods are those which do work for the other main methods
+/ which are the ones that are used for main communication between
+/ the clients and controllers.
+/
+***********************************************************************/
+
+
+function parseURL(req) {
+ var queryStringObject = qs.parse(url.parse(req.url).query);
+ return queryStringObject;
+}
+
+function createSession (name) {
+ if (name.length > 50) return null;
+ if (/[^\w_\-^!]/.exec(name)) return null;
+
+ for (var i in connectedClients) {
+ var connectedClient = connectedClients[i];
+ if (connectedClient && connectedClient.name === name) return null;
+ }
+
+ var connectedClient = {
+ name: name,
+ id: Math.floor(Math.random()*99999999999).toString(),
+ timestamp: new Date(),
+
+ poke: function () {
+ connectedClient.timestamp = new Date();
+ },
+
+ destroy: function () {
+ bespoke_session.appendMessage(connectedClient, "part");
+ delete connectedClients[connectedClient.id];
+ }
+ };
+
+ connectedClients[connectedClient.id] = connectedClient;
+ return connectedClient;
+}
+
+
+
+// Push new message URL
51 view.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>view</title>
+
+ <link rel="stylesheet" type="text/css" href="css/style.css"/>
+
+ <script src="js/utility.class.js" type="text/javascript"></script>
+ <script src="js/connection_client.class.js" type="text/javascript"></script>
+ <script src="js/controller.js" type="text/javascript"></script>
+ <script src="js/view.js" type="text/javascript"></script>
+ <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js" type="application/javascript"></script>
+ <meta name="apple-mobile-web-app-capable" content="yes">
+<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
+<meta name=viewport
+ content="width=device-width, initial-scale=1.0, minimum-scale=1.0 maximum-scale=1.0">
+ </head>
+ <body>
+
+ <div id="container">
+ <div class="block">
+ <div id="view"></div>
+ </div>
+ </div>
+
+ <script type="text/javascript">
+ $(document).ready(function() {
+
+
+ var connection_client = new Connection_Client();
+
+ // Set the name of the device for logging actions, debugging etc
+ connection_client.device_reference = Math.floor(Math.random()*99999999999).toString();
+
+
+ connection_client.init(function() {
+ console.log("Callback initiated");
+ });
+
+
+ var view_object = new view();
+ view_object.node_connection_client = connection_client;
+
+ view_object.init()
+
+
+
+ });
+ </script>
+ </body>
+</html>

0 comments on commit 9cb31f4

Please sign in to comment.
Something went wrong with that request. Please try again.