From 1bb4fbf6f4665f7a49879ded92d017b995cf5e63 Mon Sep 17 00:00:00 2001 From: mog Date: Fri, 1 Mar 2013 17:51:11 +0100 Subject: [PATCH] Removed Websockify dependency / Bugfixes Was able to fix the "Rocket spasms out" issue, by not sending the row on deletions (or ctrl+z) - and not setting the row in render when the demo is paused anyways. Also fixed an issue, that floats in Rocket (eg 400.10) have been parsed as int (eg 400) - both have the same "unprecision". --- build/jsRocket.js | 904 ++------------------- build/jsRocket.min.js | 2 +- example/threeJS_Cube_with_sound/index.html | 11 +- grunt.js | 12 +- src/syncdeviceclient.js | 140 +--- src/websockifyDependency/util.js | 352 -------- src/websockifyDependency/websock.js | 399 --------- 7 files changed, 105 insertions(+), 1715 deletions(-) delete mode 100644 src/websockifyDependency/util.js delete mode 100644 src/websockifyDependency/websock.js diff --git a/build/jsRocket.js b/build/jsRocket.js index 356b422..d90f660 100644 --- a/build/jsRocket.js +++ b/build/jsRocket.js @@ -1,755 +1,4 @@ var JSRocket = {}; -/* - * from noVNC: HTML5 VNC client - * Copyright (C) 2012 Joel Martin - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * See README.md for usage and integration instructions. - */ -(function () { - - "use strict"; - - JSRocket.Util = {}; - - /* - * Make arrays quack - */ - - Array.prototype.push8 = function (num) { - this.push(num & 0xFF); - }; - - Array.prototype.push16 = function (num) { - this.push((num >> 8) & 0xFF, - (num ) & 0xFF); - }; - Array.prototype.push32 = function (num) { - this.push((num >> 24) & 0xFF, - (num >> 16) & 0xFF, - (num >> 8) & 0xFF, - (num ) & 0xFF); - }; - - // IE does not support map (even in IE9) - //This prototype is provided by the Mozilla foundation and - //is distributed under the MIT license. - //http://www.ibiblio.org/pub/Linux/LICENSES/mit.license - if (!Array.prototype.map) { - Array.prototype.map = function (fun /*, thisp*/) { - var len = this.length; - if (typeof fun !== "function") { - throw new TypeError(); - } - - var res = new Array(len); - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in this) { - res[i] = fun.call(thisp, this[i], i, this); - } - } - - return res; - }; - } - - // - // requestAnimationFrame shim with setTimeout fallback - // - - window.requestAnimFrame = (function () { - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { - window.setTimeout(callback, 1000 / 60); - }; - })(); - - /* - * ------------------------------------------------------ - * Namespaced in JSRocket.Util - * ------------------------------------------------------ - */ - - /* - * Logging/debug routines - */ - - JSRocket.Util._log_level = 'warn'; - JSRocket.Util.init_logging = function (level) { - if (typeof level === 'undefined') { - level = JSRocket.Util._log_level; - } else { - JSRocket.Util._log_level = level; - } - if (typeof window.console === "undefined") { - if (typeof window.opera !== "undefined") { - window.console = { - 'log' :window.opera.postError, - 'warn' :window.opera.postError, - 'error':window.opera.postError }; - } else { - window.console = { - 'log' :function (m) { - }, - 'warn' :function (m) { - }, - 'error':function (m) { - }}; - } - } - - JSRocket.Util.Debug = JSRocket.Util.Info = JSRocket.Util.Warn = JSRocket.Util.Error = function (msg) { - }; - switch (level) { - case 'debug': - JSRocket.Util.Debug = function (msg) { - console.log(msg); - }; - break; - case 'info': - JSRocket.Util.Info = function (msg) { - console.log(msg); - }; - break; - case 'warn': - JSRocket.Util.Warn = function (msg) { - console.warn(msg); - }; - break; - case 'error': - JSRocket.Util.Error = function (msg) { - console.error(msg); - }; - break; - case 'none': - break; - default: - throw("invalid logging type '" + level + "'"); - } - }; - JSRocket.Util.get_logging = function () { - return JSRocket.Util._log_level; - }; - // Initialize logging level - JSRocket.Util.init_logging(); - - // Set configuration default for Crockford style function namespaces - JSRocket.Util.conf_default = function (cfg, api, defaults, v, mode, type, defval, desc) { - var getter, setter; - - // Default getter function - getter = function (idx) { - if ((type in {'arr':1, 'array':1}) && - (typeof idx !== 'undefined')) { - return cfg[v][idx]; - } else { - return cfg[v]; - } - }; - - // Default setter function - setter = function (val, idx) { - if (type in {'boolean':1, 'bool':1}) { - if ((!val) || (val in {'0':1, 'no':1, 'false':1})) { - val = false; - } else { - val = true; - } - } else if (type in {'integer':1, 'int':1}) { - val = parseInt(val, 10); - } else if (type === 'str') { - val = String(val); - } else if (type === 'func') { - if (!val) { - val = function () { - }; - } - } - if (typeof idx !== 'undefined') { - cfg[v][idx] = val; - } else { - cfg[v] = val; - } - }; - - // Set the description - api[v + '_description'] = desc; - - // Set the getter function - if (typeof api['get_' + v] === 'undefined') { - api['get_' + v] = getter; - } - - // Set the setter function with extra sanity checks - if (typeof api['set_' + v] === 'undefined') { - api['set_' + v] = function (val, idx) { - if (mode in {'RO':1, 'ro':1}) { - throw(v + " is read-only"); - } else if ((mode in {'WO':1, 'wo':1}) && - (typeof cfg[v] !== 'undefined')) { - throw(v + " can only be set once"); - } - setter(val, idx); - }; - } - - // Set the default value - if (typeof defaults[v] !== 'undefined') { - defval = defaults[v]; - } else if ((type in {'arr':1, 'array':1}) && - (!(defval instanceof Array))) { - defval = []; - } - // Coerce existing setting to the right type - //JSRocket.Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]); - setter(defval); - }; - - // Set group of configuration defaults - JSRocket.Util.conf_defaults = function (cfg, api, defaults, arr) { - var i; - for (i = 0; i < arr.length; i++) { - JSRocket.Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1], - arr[i][2], arr[i][3], arr[i][4]); - } - }; - - /* - * Cross-browser routines - */ - - // Get DOM element position on page - JSRocket.Util.getPosition = function (obj) { - var x = 0, y = 0; - if (obj.offsetParent) { - do { - x += obj.offsetLeft; - y += obj.offsetTop; - obj = obj.offsetParent; - } while (obj); - } - return {'x':x, 'y':y}; - }; - - // Get mouse event position in DOM element - JSRocket.Util.getEventPosition = function (e, obj, scale) { - var evt, docX, docY, pos; - //if (!e) evt = window.event; - evt = (e ? e : window.event); - evt = (evt.changedTouches ? evt.changedTouches[0] : evt.touches ? evt.touches[0] : evt); - if (evt.pageX || evt.pageY) { - docX = evt.pageX; - docY = evt.pageY; - } else if (evt.clientX || evt.clientY) { - docX = evt.clientX + document.body.scrollLeft + - document.documentElement.scrollLeft; - docY = evt.clientY + document.body.scrollTop + - document.documentElement.scrollTop; - } - pos = JSRocket.Util.getPosition(obj); - if (typeof scale === "undefined") { - scale = 1; - } - return {'x':(docX - pos.x) / scale, 'y':(docY - pos.y) / scale}; - }; - - // Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events - JSRocket.Util.addEvent = function (obj, evType, fn) { - if (obj.attachEvent) { - var r = obj.attachEvent("on" + evType, fn); - return r; - } else if (obj.addEventListener) { - obj.addEventListener(evType, fn, false); - return true; - } else { - throw("Handler could not be attached"); - } - }; - - JSRocket.Util.removeEvent = function (obj, evType, fn) { - if (obj.detachEvent) { - var r = obj.detachEvent("on" + evType, fn); - return r; - } else if (obj.removeEventListener) { - obj.removeEventListener(evType, fn, false); - return true; - } else { - throw("Handler could not be removed"); - } - }; - - JSRocket.Util.stopEvent = function (e) { - if (e.stopPropagation) { - e.stopPropagation(); - } - else { - e.cancelBubble = true; - } - - if (e.preventDefault) { - e.preventDefault(); - } - else { - e.returnValue = false; - } - }; - - // Set browser engine versions. Based on mootools. - JSRocket.Util.Features = {xpath:!!(document.evaluate), air:!!(window.runtime), query:!!(document.querySelector)}; - - JSRocket.Util.Engine = { - // Version detection break in Opera 11.60 (errors on arguments.callee.caller reference) - //'presto': (function() { - // return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()), - 'presto':(function () { - return (!window.opera) ? false : true; - }()), - - 'trident':(function () { - return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); - }()), - 'webkit' :(function () { - try { - return (navigator.taintEnabled) ? false : ((JSRocket.Util.Features.xpath) ? ((JSRocket.Util.Features.query) ? 525 : 420) : 419); - } catch (e) { - return false; - } - }()), - //'webkit': (function() { - // return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((JSRocket.Util.Features.xpath) ? ((JSRocket.Util.Features.query) ? 525 : 420) : 419); }()), - 'gecko' :(function () { - return (!document.getBoxObjectFor && - window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); - }()) - }; - if (JSRocket.Util.Engine.webkit) { - // Extract actual webkit version if available - JSRocket.Util.Engine.webkit = (function (v) { - var re = new RegExp('WebKit/([0-9\\.]*) '); - v = (navigator.userAgent.match(re) || ['', v])[1]; - return parseFloat(v, 10); - })(JSRocket.Util.Engine.webkit); - } - - JSRocket.Util.Flash = (function () { - var v, version; - try { - v = navigator.plugins['Shockwave Flash'].description; - } catch (err1) { - try { - v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); - } catch (err2) { - v = '0 r0'; - } - } - version = v.match(/\d+/g); - return {version:parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build:parseInt(version[2], 10) || 0}; - }()); -}()); -/* - * Websock: high-performance binary WebSockets - * Copyright (C) 2012 Joel Martin - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * Websock is similar to the standard WebSocket object but Websock - * enables communication with raw TCP sockets (i.e. the binary stream) - * via websockify. This is accomplished by base64 encoding the data - * stream between Websock and websockify. - * - * Websock has built-in receive queue buffering; the message event - * does not contain actual data but is simply a notification that - * there is new data available. Several rQ* methods are available to - * read binary data off of the receive queue. - */ - -// Load Flash WebSocket emulator if needed - -// To force WebSocket emulator even when native WebSocket available -//window.WEB_SOCKET_FORCE_FLASH = true; -// To enable WebSocket emulator debug: -//window.WEB_SOCKET_DEBUG=1; - -if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) { - Websock_native = true; -} else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) { - Websock_native = true; - window.WebSocket = window.MozWebSocket; -} - -function Websock() { -"use strict"; - -var api = {}, // Public API - websocket = null, // WebSocket object - mode = 'base64', // Current WebSocket mode: 'binary', 'base64' - rQ = [], // Receive queue - rQi = 0, // Receive queue index - rQmax = 10000, // Max receive queue size before compacting - sQ = [], // Send queue - - eventHandlers = { - 'message' : function() {}, - 'open' : function() {}, - 'close' : function() {}, - 'error' : function() {} - }, - Util = JSRocket.Util, - test_mode = false; - - -// -// Queue public functions -// - -function get_sQ() { - return sQ; -} - -function get_rQ() { - return rQ; -} -function get_rQi() { - return rQi; -} -function set_rQi(val) { - rQi = val; -} - -function rQlen() { - return rQ.length - rQi; -} - -function rQpeek8() { - return (rQ[rQi] ); -} -function rQshift8() { - return (rQ[rQi++] ); -} -function rQunshift8(num) { - if (rQi === 0) { - rQ.unshift(num); - } else { - rQi -= 1; - rQ[rQi] = num; - } - -} -function rQshift16() { - return (rQ[rQi++] << 8) + - (rQ[rQi++] ); -} -function rQshift32() { - return (rQ[rQi++] << 24) + - (rQ[rQi++] << 16) + - (rQ[rQi++] << 8) + - (rQ[rQi++] ); -} -function rQshiftStr(len) { - if (typeof(len) === 'undefined') { len = rQlen(); } - var arr = rQ.slice(rQi, rQi + len); - rQi += len; - return String.fromCharCode.apply(null, arr); -} -function rQshiftBytes(len) { - if (typeof(len) === 'undefined') { len = rQlen(); } - rQi += len; - return rQ.slice(rQi-len, rQi); -} - -function rQslice(start, end) { - if (end) { - return rQ.slice(rQi + start, rQi + end); - } else { - return rQ.slice(rQi + start); - } -} - -// Check to see if we must wait for 'num' bytes (default to FBU.bytes) -// to be available in the receive queue. Return true if we need to -// wait (and possibly print a debug message), otherwise false. -function rQwait(msg, num, goback) { - var rQlen = rQ.length - rQi; // Skip rQlen() function call - if (rQlen < num) { - if (goback) { - if (rQi < goback) { - throw("rQwait cannot backup " + goback + " bytes"); - } - rQi -= goback; - } - //Util.Debug(" waiting for " + (num-rQlen) + - // " " + msg + " byte(s)"); - return true; // true means need more data - } - return false; -} - -// -// Private utility routines -// - -function encode_message() { - if (mode === 'binary') { - // Put in a binary arraybuffer - return (new Uint8Array(sQ)).buffer; - } else { - // base64 encode - return Base64.encode(sQ); - } -} - -function decode_message(data) { - //Util.Debug(">> decode_message: " + data); - if (mode === 'binary') { - // push arraybuffer values onto the end - rQ.push.apply(rQ, (new Uint8Array(data))); - } else { - // base64 decode and concat to the end - rQ = rQ.concat(Base64.decode(data, 0)); - } - //Util.Debug(">> decode_message, rQ: " + rQ); -} - - -// -// Public Send functions -// - -function flush() { - if (websocket.bufferedAmount !== 0) { - Util.Debug("bufferedAmount: " + websocket.bufferedAmount); - } - if (websocket.bufferedAmount < api.maxBufferedAmount) { - //Util.Debug("arr: " + arr); - //Util.Debug("sQ: " + sQ); - if (sQ.length > 0) { - websocket.send(encode_message(sQ)); - sQ = []; - } - return true; - } else { - Util.Info("Delaying send, bufferedAmount: " + - websocket.bufferedAmount); - return false; - } -} - -// overridable for testing -function send(arr) { - //Util.Debug(">> send_array: " + arr); - sQ = sQ.concat(arr); - return flush(); -} - -function send_string(str) { - //Util.Debug(">> send_string: " + str); - api.send(str.split('').map( - function (chr) { return chr.charCodeAt(0); } ) ); -} - -// -// Other public functions - -function recv_message(e) { - //Util.Debug(">> recv_message: " + e.data.length); - - try { - decode_message(e.data); - if (rQlen() > 0) { - eventHandlers.message(); - // Compact the receive queue - if (rQ.length > rQmax) { - //Util.Debug("Compacting receive queue"); - rQ = rQ.slice(rQi); - rQi = 0; - } - } else { - Util.Debug("Ignoring empty message"); - } - } catch (exc) { - if (typeof exc.stack !== 'undefined') { - Util.Warn("recv_message, caught exception: " + exc.stack); - } else if (typeof exc.description !== 'undefined') { - Util.Warn("recv_message, caught exception: " + exc.description); - } else { - Util.Warn("recv_message, caught exception:" + exc); - } - if (typeof exc.name !== 'undefined') { - eventHandlers.error(exc.name + ": " + exc.message); - } else { - eventHandlers.error(exc); - } - } - //Util.Debug("<< recv_message"); -} - - -// Set event handlers -function on(evt, handler) { - eventHandlers[evt] = handler; -} - -function init(protocols) { - rQ = []; - rQi = 0; - sQ = []; - websocket = null; - - var bt = false, - wsbt = false, - try_binary = false; - - // Check for full typed array support - if (('Uint8Array' in window) && - ('set' in Uint8Array.prototype)) { - bt = true; - } - - // Check for full binary type support in WebSockets - // TODO: this sucks, the property should exist on the prototype - // but it does not. - try { - if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) { - Util.Info("Detected binaryType support in WebSockets"); - wsbt = true; - } - } catch (exc) { - // Just ignore failed test localhost connections - } - - // Default protocols if not specified - if (typeof(protocols) === "undefined") { - if (wsbt) { - protocols = ['binary', 'base64']; - } else { - protocols = 'base64'; - } - } - - // If no binary support, make sure it was not requested - if (!wsbt) { - if (protocols === 'binary') { - throw("WebSocket binary sub-protocol requested but not supported"); - } - if (typeof(protocols) === "object") { - var new_protocols = []; - for (var i = 0; i < protocols.length; i++) { - if (protocols[i] === 'binary') { - Util.Error("Skipping unsupported WebSocket binary sub-protocol"); - } else { - new_protocols.push(protocols[i]); - } - } - if (new_protocols.length > 0) { - protocols = new_protocols; - } else { - throw("Only WebSocket binary sub-protocol was requested and not supported."); - } - } - } - - return protocols; -} - -function open(uri, protocols) { - protocols = init(protocols); - - if (test_mode) { - websocket = {}; - } else { - websocket = new WebSocket(uri, protocols); - } - - websocket.onmessage = recv_message; - websocket.onopen = function() { - Util.Debug(">> WebSock.onopen"); - if (websocket.protocol) { - mode = websocket.protocol; - Util.Info("Server chose sub-protocol: " + websocket.protocol); - } else { - mode = 'base64'; - Util.Error("Server select no sub-protocol!: " + websocket.protocol); - } - if (mode === 'binary') { - websocket.binaryType = 'arraybuffer'; - } - eventHandlers.open(); - Util.Debug("<< WebSock.onopen"); - }; - websocket.onclose = function(e) { - Util.Debug(">> WebSock.onclose"); - eventHandlers.close(e); - Util.Debug("<< WebSock.onclose"); - }; - websocket.onerror = function(e) { - Util.Debug(">> WebSock.onerror: " + e); - eventHandlers.error(e); - Util.Debug("<< WebSock.onerror"); - }; -} - -function close() { - if (websocket) { - if ((websocket.readyState === WebSocket.OPEN) || - (websocket.readyState === WebSocket.CONNECTING)) { - Util.Info("Closing WebSocket connection"); - websocket.close(); - } - websocket.onmessage = function (e) { return; }; - } -} - -// Override internal functions for testing -// Takes a send function, returns reference to recv function -function testMode(override_send) { - test_mode = true; - api.send = override_send; - api.close = function () {}; - return recv_message; -} - -function constructor() { - // Configuration settings - api.maxBufferedAmount = 200; - - // Direct access to send and receive queues - api.get_sQ = get_sQ; - api.get_rQ = get_rQ; - api.get_rQi = get_rQi; - api.set_rQi = set_rQi; - - // Routines to read from the receive queue - api.rQlen = rQlen; - api.rQpeek8 = rQpeek8; - api.rQshift8 = rQshift8; - api.rQunshift8 = rQunshift8; - api.rQshift16 = rQshift16; - api.rQshift32 = rQshift32; - api.rQshiftStr = rQshiftStr; - api.rQshiftBytes = rQshiftBytes; - api.rQslice = rQslice; - api.rQwait = rQwait; - - api.flush = flush; - api.send = send; - api.send_string = send_string; - - api.on = on; - api.init = init; - api.open = open; - api.close = close; - api.testMode = testMode; - - return api; -} - -return constructor(); - -} JSRocket.SyncData = function () { "use strict"; @@ -996,9 +245,7 @@ JSRocket.SyncDeviceClient = function (cfg) { CMD_PAUSE = 4, CMD_SAVE_TRACKS = 5; - var _currentCommand = -1, - _queue = [], - _ws, + var _ws = new WebSocket(cfg.socketURL), _syncData = new JSRocket.SyncData(), _eventHandler = { 'ready' :function () { @@ -1008,118 +255,83 @@ JSRocket.SyncDeviceClient = function (cfg) { 'play' :function () { }, 'pause' :function () { + }, + 'save' :function () { } }; - function onOpen(e) { - console.log("[onOpen]", e); + function onOpen() { + + _ws.binaryType = "arraybuffer"; _ws.send('hello, synctracker!'); } function onMessage(e) { - _queue = (new Uint8Array(e.data)); - - console.log("[onMessage]", _queue); - - readStream(); - } - - function readStream() { - - var len = _queue.length, + var queue = (new Uint8Array(e.data)), + cmd = queue[0], track, row, value, interpolation; - if (_currentCommand === -1) { - _currentCommand = _queue[0]; - } - //Handshake - if ((_currentCommand === 104) && (len >= 12)) { - console.log("[handshake]"); - - _queue = []; - _currentCommand = -1; + if (cmd === 104) { _eventHandler.ready(); - //PAUSE - } else if ((CMD_PAUSE === _currentCommand) && (len >= 2)) { - - value = parseInt(_queue[1], 10); - console.log("[stream] pause", value); - //_queue = _queue.slice(2); - _currentCommand = -1; + //PAUSE + } else if (CMD_PAUSE === cmd) { - if (value === 1) { + if( queue[1] === 1) { _eventHandler.pause(); } else { _eventHandler.play(); } - //SET_ROW - } else if ((CMD_SET_ROW === _currentCommand) && (len >= 5)) { - console.log("[stream] row"); + //SET_ROW + } else if (CMD_SET_ROW === cmd) { - row = toInt(_queue.subarray(1, 5)); - console.log("[stream] row>>",_queue.subarray(1, 5), row); - //_queue = _queue.slice(5); - _currentCommand = -1; + row = toInt(queue.subarray(1, 5)); _eventHandler.update(row); - //SET_KEY - } else if ((CMD_SET_KEY === _currentCommand) && (len >= 14)) { - console.log("[stream] key"); + //SET_KEY + } else if (CMD_SET_KEY === cmd) { - track = toInt(_queue.subarray(1, 5)); - row = toInt(_queue.subarray(5, 9)); - value = parseInt(Math.round(toFloat(_queue.subarray(9, 13)) * 1000) / 1000, 10); - interpolation = parseInt(_queue.subarray(13, 14)[0], 10); + track = toInt(queue.subarray(1, 5)); + row = toInt(queue.subarray(5, 9)); - _syncData.getTrack(track).add(row, value, interpolation); + //value = Math.round(toFloat(queue.subarray(9, 13)) * 100) / 100; //round to what's seen in Rocket tracks + value = toFloat(queue.subarray(9, 13)); //use the values you see in Rocket statusbar - console.log("setKey", track, row, value, interpolation, _queue.subarray(13, 14)); - - _currentCommand = -1; + interpolation = toInt(queue.subarray(13, 14)); + _syncData.getTrack(track).add(row, value, interpolation); //don't set row, as this could also be a interpolation change _eventHandler.update(); - //DELETE - } else if ((CMD_DELETE_KEY === _currentCommand) && (len >= 9)) { - console.log("[stream] delete"); + //DELETE + } else if (CMD_DELETE_KEY === cmd) { - track = toInt(_queue.subarray(1, 5)); - row = toInt(_queue.subarray(5, 9)); + track = toInt(queue.subarray(1, 5)); + row = toInt(queue.subarray(5, 9)); _syncData.getTrack(track).remove(row); - //_queue = _queue.slice(9); - _currentCommand = -1; - - _eventHandler.update(row); - - //SAVE - } else if (CMD_SAVE_TRACKS === _currentCommand) { - console.log("[stream] save"); - //console.log(">> TRACKS WERE SAVED"); + _eventHandler.update(); - //_queue = _queue.slice(1); - _currentCommand = -1; + //SAVE + } else if (CMD_SAVE_TRACKS === cmd) { + _eventHandler.save(); } } function onClose(e) { - console.log(">> connection closed", e); + console.warn(">> connection closed", e); } function onError(e) { console.error(">> connection error'd", e); } - console.log("pew", cfg.socketURL); - _ws = new WebSocket(cfg.socketURL); - _ws.binaryType = "arraybuffer"; + _ws.onopen = onOpen; _ws.onmessage = onMessage; _ws.onclose = onClose; @@ -1137,6 +349,7 @@ JSRocket.SyncDeviceClient = function (cfg) { _ws.send(name); _syncData.createIndex(name); + return _syncData.getTrack(_syncData.getTrackLength() - 1); } @@ -1150,43 +363,30 @@ JSRocket.SyncDeviceClient = function (cfg) { _ws.send(new Uint8Array([CMD_SET_ROW, streamInt[0], streamInt[1], streamInt[2], streamInt[3]]).buffer); } - function toInt(arr){ - var res = 0, - i = arr.length - 1; + function toInt(arr) { - for(; i > 0; i--) { - res += parseInt(arr[i], 10) * Math.pow(256, (arr.length - 1) - i); + var i = 0, + view = new DataView(new ArrayBuffer(arr.length)); + + for(;i < arr.length; i++) { + view.setUint8(i, arr[i]); } - return res; + if(view.byteLength === 1) { + return view.getInt8(0); + } else { + return view.getInt32(0); + } } function toFloat(arr) { - //identical to ws.rQshift32(), but no need to read the queue again - var i = 0, - n = (arr[i++] << 24) + - (arr[i++] << 16) + - (arr[i++] << 8) + - (arr[i++] ), - //https://groups.google.com/forum/?fromgroups=#!topic/comp.lang.javascript/YzqYOCyWlNA - sign = (n >> 31) * 2 + 1, // +1 or -1. - exp = (n >>> 23) & 0xff, - mantissa = n & 0x007fffff; - - if (exp === 0xff) { - // NaN or Infinity - return mantissa ? NaN : sign * Infinity; - } else if (exp) { - // Normalized value - exp -= 127; - - // Add implicit bit in normal mode. - mantissa |= 0x00800000; - } else { - // Subnormal number - exp = -126; - } - return sign * mantissa * Math.pow(2, exp - 23); + var view = new DataView(new ArrayBuffer(4)); + view.setUint8(0, arr[0]); + view.setUint8(1, arr[1]); + view.setUint8(2, arr[2]); + view.setUint8(3, arr[3]); + + return view.getFloat32(0); } function setEvent(evt, handler) { diff --git a/build/jsRocket.min.js b/build/jsRocket.min.js index 41f0360..cc64b76 100644 --- a/build/jsRocket.min.js +++ b/build/jsRocket.min.js @@ -2,4 +2,4 @@ * https://github.com/mog/jsRocket * Copyright (c) 2013 mog; Licensed MIT*/ -function Websock(){"use strict";function l(){return o}function c(){return r}function h(){return i}function p(e){i=e}function d(){return r.length-i}function v(){return r[i]}function m(){return r[i++]}function g(e){i===0?r.unshift(e):(i-=1,r[i]=e)}function y(){return(r[i++]<<8)+r[i++]}function b(){return(r[i++]<<24)+(r[i++]<<16)+(r[i++]<<8)+r[i++]}function w(e){typeof e=="undefined"&&(e=d());var t=r.slice(i,i+e);return i+=e,String.fromCharCode.apply(null,t)}function E(e){return typeof e=="undefined"&&(e=d()),i+=e,r.slice(i-e,i)}function S(e,t){return t?r.slice(i+e,i+t):r.slice(i+e)}function x(e,t,n){var s=r.length-i;if(s0&&(t.send(T(o)),o=[]),!0):(a.Info("Delaying send, bufferedAmount: "+t.bufferedAmount),!1)}function k(e){return o=o.concat(e),C()}function L(t){e.send(t.split("").map(function(e){return e.charCodeAt(0)}))}function A(e){try{N(e.data),d()>0?(u.message(),r.length>s&&(r=r.slice(i),i=0)):a.Debug("Ignoring empty message")}catch(t){typeof t.stack!="undefined"?a.Warn("recv_message, caught exception: "+t.stack):typeof t.description!="undefined"?a.Warn("recv_message, caught exception: "+t.description):a.Warn("recv_message, caught exception:"+t),typeof t.name!="undefined"?u.error(t.name+": "+t.message):u.error(t)}}function O(e,t){u[e]=t}function M(e){r=[],i=0,o=[],t=null;var n=!1,s=!1,u=!1;"Uint8Array"in window&&"set"in Uint8Array.prototype&&(n=!0);try{n&&"binaryType"in new WebSocket("ws://localhost:17523")&&(a.Info("Detected binaryType support in WebSockets"),s=!0)}catch(f){}typeof e=="undefined"&&(s?e=["binary","base64"]:e="base64");if(!s){if(e==="binary")throw"WebSocket binary sub-protocol requested but not supported";if(typeof e=="object"){var l=[];for(var c=0;c0))throw"Only WebSocket binary sub-protocol was requested and not supported.";e=l}}return e}function _(e,r){r=M(r),f?t={}:t=new WebSocket(e,r),t.onmessage=A,t.onopen=function(){a.Debug(">> WebSock.onopen"),t.protocol?(n=t.protocol,a.Info("Server chose sub-protocol: "+t.protocol)):(n="base64",a.Error("Server select no sub-protocol!: "+t.protocol)),n==="binary"&&(t.binaryType="arraybuffer"),u.open(),a.Debug("<< WebSock.onopen")},t.onclose=function(e){a.Debug(">> WebSock.onclose"),u.close(e),a.Debug("<< WebSock.onclose")},t.onerror=function(e){a.Debug(">> WebSock.onerror: "+e),u.error(e),a.Debug("<< WebSock.onerror")}}function D(){if(t){if(t.readyState===WebSocket.OPEN||t.readyState===WebSocket.CONNECTING)a.Info("Closing WebSocket connection"),t.close();t.onmessage=function(e){return}}}function P(t){return f=!0,e.send=t,e.close=function(){},A}function H(){return e.maxBufferedAmount=200,e.get_sQ=l,e.get_rQ=c,e.get_rQi=h,e.set_rQi=p,e.rQlen=d,e.rQpeek8=v,e.rQshift8=m,e.rQunshift8=g,e.rQshift16=y,e.rQshift32=b,e.rQshiftStr=w,e.rQshiftBytes=E,e.rQslice=S,e.rQwait=x,e.flush=C,e.send=k,e.send_string=L,e.on=O,e.init=M,e.open=_,e.close=D,e.testMode=P,e}var e={},t=null,n="base64",r=[],i=0,s=1e4,o=[],u={message:function(){},open:function(){},close:function(){},error:function(){}},a=JSRocket.Util,f=!1;return H()}var JSRocket={};(function(){"use strict";JSRocket.Util={},Array.prototype.push8=function(e){this.push(e&255)},Array.prototype.push16=function(e){this.push(e>>8&255,e&255)},Array.prototype.push32=function(e){this.push(e>>24&255,e>>16&255,e>>8&255,e&255)},Array.prototype.map||(Array.prototype.map=function(e){var t=this.length;if(typeof e!="function")throw new TypeError;var n=new Array(t),r=arguments[1];for(var i=0;i=e){n=s[r];break}return{low:t,high:n}}function a(e,t,n){f(e),s.push(e),i[e]={value:t,interpolation:n},s=s.sort(function(e,t){return e-t})}function f(e){s.indexOf(e)>-1&&(s.splice(s.indexOf(e),1),delete i[e])}var e=0,t=1,n=2,r=3,i=[],s=[];return{getValue:o,add:a,remove:f}},JSRocket.SyncDevicePlayer=function(e){"use strict";function i(e){t=new XMLHttpRequest;if(t===null){r.error();return}t.open("GET",e,!0),t.onreadystatechange=s,t.send()}function s(){t.readyState===4&&(t.status<300?o(t.responseText):r.error())}function o(e){var t=(new DOMParser).parseFromString(e,"text/xml"),n=t.getElementsByTagName("tracks");for(var i=0;i-1?n.getTrack(t):(n.createIndex(e),n.getTrack(n.getTrackLength()-1))}function a(e,t){r[e]=t}function f(){}var t,n=new JSRocket.SyncData,r={ready:function(){},error:function(){}};if(e.rocketXML===""||e.rocketXML===undefined||e.rocketXML===undefined)throw"[jsRocket] rocketXML is not set, try _syncDevice.setConfig({'rocketXML':'url/To/RocketXML.rocket'})";return i(e.rocketXML),{load:i,getTrack:u,update:f,on:a}},JSRocket.SyncDeviceClient=function(e){"use strict";function h(e){console.log("[onOpen]",e),f.send("hello, synctracker!")}function p(e){a=new Uint8Array(e.data),console.log("[onMessage]",a),d()}function d(){var e=a.length,r,f,h,p;u===-1&&(u=a[0]),u===104&&e>=12?(console.log("[handshake]"),a=[],u=-1,c.ready()):s===u&&e>=2?(h=parseInt(a[1],10),console.log("[stream] pause",h),u=-1,h===1?c.pause():c.play()):i===u&&e>=5?(console.log("[stream] row"),f=b(a.subarray(1,5)),console.log("[stream] row>>",a.subarray(1,5),f),u=-1,c.update(f)):t===u&&e>=14?(console.log("[stream] key"),r=b(a.subarray(1,5)),f=b(a.subarray(5,9)),h=parseInt(Math.round(w(a.subarray(9,13))*1e3)/1e3,10),p=parseInt(a.subarray(13,14)[0],10),l.getTrack(r).add(f,h,p),console.log("setKey",r,f,h,p,a.subarray(13,14)),u=-1,c.update()):n===u&&e>=9?(console.log("[stream] delete"),r=b(a.subarray(1,5)),f=b(a.subarray(5,9)),l.getTrack(r).remove(f),u=-1,c.update(f)):o===u&&(console.log("[stream] save"),u=-1)}function v(e){console.log(">> connection closed",e)}function m(e){console.error(">> connection error'd",e)}function g(e){var t=l.getIndexForName(e);return t>-1?l.getTrack(t):(f.send((new Uint8Array([r,0,0,0,e.length])).buffer),f.send(e),l.createIndex(e),l.getTrack(l.getTrackLength()-1))}function y(e){var t=[e>>24&255,e>>16&255,e>>8&255,e&255];f.send((new Uint8Array([i,t[0],t[1],t[2],t[3]])).buffer)}function b(e){var t=0,n=e.length-1;for(;n>0;n--)t+=parseInt(e[n],10)*Math.pow(256,e.length-1-n);return t}function w(e){var t=0,n=(e[t++]<<24)+(e[t++]<<16)+(e[t++]<<8)+e[t++],r=(n>>31)*2+1,i=n>>>23&255,s=n&8388607;return i===255?s?NaN:r*Infinity:(i?(i-=127,s|=8388608):i=-126,r*s*Math.pow(2,i-23))}function E(e,t){c[e]=t}var t=0,n=1,r=2,i=3,s=4,o=5,u=-1,a=[],f,l=new JSRocket.SyncData,c={ready:function(){},update:function(){},play:function(){},pause:function(){}};return console.log("pew",e.socketURL),f=new WebSocket(e.socketURL),f.binaryType="arraybuffer",f.onopen=h,f.onmessage=p,f.onclose=v,f.onerror=m,{getTrack:g,update:y,on:E}},JSRocket.SyncDevice=function(){"use strict";function s(e){e==="demo"?t=new JSRocket.SyncDevicePlayer(r):t=new JSRocket.SyncDeviceClient(r),t.on("ready",a),t.on("update",f),t.on("play",l),t.on("pause",c)}function o(){return r}function u(e){for(var t in e)e.hasOwnProperty(t)&&(r[t]=e[t]);return r}function a(){e=!0,i.ready()}function f(e){i.update(e)}function l(){i.play()}function c(){i.pause()}function h(n){return e?t.getTrack(n):null}function p(e){Math.floor(e)!==n&&(n=Math.floor(e),t.update(n))}function d(e,t){i[e]=t}var e=!1,t,n,r={socketURL:"ws://localhost:1338",rocketXML:""},i={ready:function(){},update:function(){},play:function(){},pause:function(){}};return{init:s,setConfig:u,getConfig:o,getTrack:h,update:p,on:d}}; \ No newline at end of file +var JSRocket={};JSRocket.SyncData=function(){"use strict";function t(t){return e[t]}function n(t){for(var n=0;n=e){n=s[r];break}return{low:t,high:n}}function a(e,t,n){f(e),s.push(e),i[e]={value:t,interpolation:n},s=s.sort(function(e,t){return e-t})}function f(e){s.indexOf(e)>-1&&(s.splice(s.indexOf(e),1),delete i[e])}var e=0,t=1,n=2,r=3,i=[],s=[];return{getValue:o,add:a,remove:f}},JSRocket.SyncDevicePlayer=function(e){"use strict";function i(e){t=new XMLHttpRequest;if(t===null){r.error();return}t.open("GET",e,!0),t.onreadystatechange=s,t.send()}function s(){t.readyState===4&&(t.status<300?o(t.responseText):r.error())}function o(e){var t=(new DOMParser).parseFromString(e,"text/xml"),n=t.getElementsByTagName("tracks");for(var i=0;i-1?n.getTrack(t):(n.createIndex(e),n.getTrack(n.getTrackLength()-1))}function a(e,t){r[e]=t}function f(){}var t,n=new JSRocket.SyncData,r={ready:function(){},error:function(){}};if(e.rocketXML===""||e.rocketXML===undefined||e.rocketXML===undefined)throw"[jsRocket] rocketXML is not set, try _syncDevice.setConfig({'rocketXML':'url/To/RocketXML.rocket'})";return i(e.rocketXML),{load:i,getTrack:u,update:f,on:a}},JSRocket.SyncDeviceClient=function(e){"use strict";function l(){u.binaryType="arraybuffer",u.send("hello, synctracker!")}function c(e){var r=new Uint8Array(e.data),u=r[0],l,c,h,p;u===104?f.ready():s===u?r[1]===1?f.pause():f.play():i===u?(c=m(r.subarray(1,5)),f.update(c)):t===u?(l=m(r.subarray(1,5)),c=m(r.subarray(5,9)),h=g(r.subarray(9,13)),p=m(r.subarray(13,14)),a.getTrack(l).add(c,h,p),f.update()):n===u?(l=m(r.subarray(1,5)),c=m(r.subarray(5,9)),a.getTrack(l).remove(c),f.update()):o===u&&f.save()}function h(e){console.warn(">> connection closed",e)}function p(e){console.error(">> connection error'd",e)}function d(e){var t=a.getIndexForName(e);return t>-1?a.getTrack(t):(u.send((new Uint8Array([r,0,0,0,e.length])).buffer),u.send(e),a.createIndex(e),a.getTrack(a.getTrackLength()-1))}function v(e){var t=[e>>24&255,e>>16&255,e>>8&255,e&255];u.send((new Uint8Array([i,t[0],t[1],t[2],t[3]])).buffer)}function m(e){var t=0,n=new DataView(new ArrayBuffer(e.length));for(;t\n' + '<%= pkg.homepage ? "* " + pkg.homepage + "\n" : "" %>' + '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + - ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>*/\n', - bannerWithWebsockify:'/* Contains util.js and websock.js from https://github.com/kanaka/websockify'+ - '* Licensed MPL 2.0 */\n' + ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>*/\n' }, concat:{ lite:{ @@ -24,8 +22,6 @@ module.exports = function (grunt) { dist:{ src:[ 'src/jsRocket.js', - 'src/websockifyDependency/util.js', - 'src/websockifyDependency/websock.js', 'src/syncdata.js', 'src/synctrack.js', 'src/syncdeviceplayer.js', @@ -40,7 +36,7 @@ module.exports = function (grunt) { dest:'build/<%= pkg.name %>.sans-socket.min.js' }, dist:{ - src :['','', ''], + src :['', ''], dest:'build/<%= pkg.name %>.min.js' } }, @@ -66,10 +62,6 @@ module.exports = function (grunt) { }, globals:{ 'JSRocket':true, - 'Websock':true, - 'ActiveXObject':true, - 'Base64':true, - 'Websock_native':true, module :false } } diff --git a/src/syncdeviceclient.js b/src/syncdeviceclient.js index b283930..d8da393 100644 --- a/src/syncdeviceclient.js +++ b/src/syncdeviceclient.js @@ -9,9 +9,7 @@ JSRocket.SyncDeviceClient = function (cfg) { CMD_PAUSE = 4, CMD_SAVE_TRACKS = 5; - var _currentCommand = -1, - _queue = [], - _ws, + var _ws = new WebSocket(cfg.socketURL), _syncData = new JSRocket.SyncData(), _eventHandler = { 'ready' :function () { @@ -21,118 +19,83 @@ JSRocket.SyncDeviceClient = function (cfg) { 'play' :function () { }, 'pause' :function () { + }, + 'save' :function () { } }; - function onOpen(e) { - console.log("[onOpen]", e); + function onOpen() { + + _ws.binaryType = "arraybuffer"; _ws.send('hello, synctracker!'); } function onMessage(e) { - _queue = (new Uint8Array(e.data)); - - console.log("[onMessage]", _queue); - - readStream(); - } - - function readStream() { - - var len = _queue.length, + var queue = (new Uint8Array(e.data)), + cmd = queue[0], track, row, value, interpolation; - if (_currentCommand === -1) { - _currentCommand = _queue[0]; - } - //Handshake - if ((_currentCommand === 104) && (len >= 12)) { - console.log("[handshake]"); - - _queue = []; - _currentCommand = -1; + if (cmd === 104) { _eventHandler.ready(); //PAUSE - } else if ((CMD_PAUSE === _currentCommand) && (len >= 2)) { - - value = parseInt(_queue[1], 10); - console.log("[stream] pause", value); - //_queue = _queue.slice(2); - _currentCommand = -1; + } else if (CMD_PAUSE === cmd) { - if (value === 1) { + if( queue[1] === 1) { _eventHandler.pause(); } else { _eventHandler.play(); } //SET_ROW - } else if ((CMD_SET_ROW === _currentCommand) && (len >= 5)) { - console.log("[stream] row"); + } else if (CMD_SET_ROW === cmd) { - row = toInt(_queue.subarray(1, 5)); - console.log("[stream] row>>",_queue.subarray(1, 5), row); - //_queue = _queue.slice(5); - _currentCommand = -1; + row = toInt(queue.subarray(1, 5)); _eventHandler.update(row); //SET_KEY - } else if ((CMD_SET_KEY === _currentCommand) && (len >= 14)) { - console.log("[stream] key"); + } else if (CMD_SET_KEY === cmd) { - track = toInt(_queue.subarray(1, 5)); - row = toInt(_queue.subarray(5, 9)); - value = parseInt(Math.round(toFloat(_queue.subarray(9, 13)) * 1000) / 1000, 10); - interpolation = parseInt(_queue.subarray(13, 14)[0], 10); + track = toInt(queue.subarray(1, 5)); + row = toInt(queue.subarray(5, 9)); - _syncData.getTrack(track).add(row, value, interpolation); - - console.log("setKey", track, row, value, interpolation, _queue.subarray(13, 14)); + //value = Math.round(toFloat(queue.subarray(9, 13)) * 100) / 100; //round to what's seen in Rocket tracks + value = toFloat(queue.subarray(9, 13)); //use the values you see in Rocket statusbar - _currentCommand = -1; + interpolation = toInt(queue.subarray(13, 14)); + _syncData.getTrack(track).add(row, value, interpolation); //don't set row, as this could also be a interpolation change _eventHandler.update(); //DELETE - } else if ((CMD_DELETE_KEY === _currentCommand) && (len >= 9)) { - console.log("[stream] delete"); + } else if (CMD_DELETE_KEY === cmd) { - track = toInt(_queue.subarray(1, 5)); - row = toInt(_queue.subarray(5, 9)); + track = toInt(queue.subarray(1, 5)); + row = toInt(queue.subarray(5, 9)); _syncData.getTrack(track).remove(row); - //_queue = _queue.slice(9); - _currentCommand = -1; - - _eventHandler.update(row); + _eventHandler.update(); //SAVE - } else if (CMD_SAVE_TRACKS === _currentCommand) { - console.log("[stream] save"); - //console.log(">> TRACKS WERE SAVED"); - - //_queue = _queue.slice(1); - _currentCommand = -1; + } else if (CMD_SAVE_TRACKS === cmd) { + _eventHandler.save(); } } function onClose(e) { - console.log(">> connection closed", e); + console.warn(">> connection closed", e); } function onError(e) { console.error(">> connection error'd", e); } - console.log("pew", cfg.socketURL); - _ws = new WebSocket(cfg.socketURL); - _ws.binaryType = "arraybuffer"; + _ws.onopen = onOpen; _ws.onmessage = onMessage; _ws.onclose = onClose; @@ -164,42 +127,29 @@ JSRocket.SyncDeviceClient = function (cfg) { } function toInt(arr){ - var res = 0, - i = arr.length - 1; - for(; i > 0; i--) { - res += parseInt(arr[i], 10) * Math.pow(256, (arr.length - 1) - i); + var i = 0, + view = new DataView(new ArrayBuffer(arr.length)); + + for(;i < arr.length; i++) { + view.setUint8(i, arr[i]); } - return res; + if(view.byteLength === 1) { + return view.getInt8(0); + } else { + return view.getInt32(0); + } } function toFloat(arr) { - //identical to ws.rQshift32(), but no need to read the queue again - var i = 0, - n = (arr[i++] << 24) + - (arr[i++] << 16) + - (arr[i++] << 8) + - (arr[i++] ), - //https://groups.google.com/forum/?fromgroups=#!topic/comp.lang.javascript/YzqYOCyWlNA - sign = (n >> 31) * 2 + 1, // +1 or -1. - exp = (n >>> 23) & 0xff, - mantissa = n & 0x007fffff; - - if (exp === 0xff) { - // NaN or Infinity - return mantissa ? NaN : sign * Infinity; - } else if (exp) { - // Normalized value - exp -= 127; - - // Add implicit bit in normal mode. - mantissa |= 0x00800000; - } else { - // Subnormal number - exp = -126; - } - return sign * mantissa * Math.pow(2, exp - 23); + var view = new DataView(new ArrayBuffer(4)); + view.setUint8(0, arr[0]); + view.setUint8(1, arr[1]); + view.setUint8(2, arr[2]); + view.setUint8(3, arr[3]); + + return view.getFloat32(0); } function setEvent(evt, handler) { diff --git a/src/websockifyDependency/util.js b/src/websockifyDependency/util.js deleted file mode 100644 index ffa1b5b..0000000 --- a/src/websockifyDependency/util.js +++ /dev/null @@ -1,352 +0,0 @@ -/* - * from noVNC: HTML5 VNC client - * Copyright (C) 2012 Joel Martin - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * See README.md for usage and integration instructions. - */ -(function () { - - "use strict"; - - JSRocket.Util = {}; - - /* - * Make arrays quack - */ - - Array.prototype.push8 = function (num) { - this.push(num & 0xFF); - }; - - Array.prototype.push16 = function (num) { - this.push((num >> 8) & 0xFF, - (num ) & 0xFF); - }; - Array.prototype.push32 = function (num) { - this.push((num >> 24) & 0xFF, - (num >> 16) & 0xFF, - (num >> 8) & 0xFF, - (num ) & 0xFF); - }; - - // IE does not support map (even in IE9) - //This prototype is provided by the Mozilla foundation and - //is distributed under the MIT license. - //http://www.ibiblio.org/pub/Linux/LICENSES/mit.license - if (!Array.prototype.map) { - Array.prototype.map = function (fun /*, thisp*/) { - var len = this.length; - if (typeof fun !== "function") { - throw new TypeError(); - } - - var res = new Array(len); - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in this) { - res[i] = fun.call(thisp, this[i], i, this); - } - } - - return res; - }; - } - - // - // requestAnimationFrame shim with setTimeout fallback - // - - window.requestAnimFrame = (function () { - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function (callback) { - window.setTimeout(callback, 1000 / 60); - }; - })(); - - /* - * ------------------------------------------------------ - * Namespaced in JSRocket.Util - * ------------------------------------------------------ - */ - - /* - * Logging/debug routines - */ - - JSRocket.Util._log_level = 'warn'; - JSRocket.Util.init_logging = function (level) { - if (typeof level === 'undefined') { - level = JSRocket.Util._log_level; - } else { - JSRocket.Util._log_level = level; - } - if (typeof window.console === "undefined") { - if (typeof window.opera !== "undefined") { - window.console = { - 'log' :window.opera.postError, - 'warn' :window.opera.postError, - 'error':window.opera.postError }; - } else { - window.console = { - 'log' :function (m) { - }, - 'warn' :function (m) { - }, - 'error':function (m) { - }}; - } - } - - JSRocket.Util.Debug = JSRocket.Util.Info = JSRocket.Util.Warn = JSRocket.Util.Error = function (msg) { - }; - switch (level) { - case 'debug': - JSRocket.Util.Debug = function (msg) { - console.log(msg); - }; - break; - case 'info': - JSRocket.Util.Info = function (msg) { - console.log(msg); - }; - break; - case 'warn': - JSRocket.Util.Warn = function (msg) { - console.warn(msg); - }; - break; - case 'error': - JSRocket.Util.Error = function (msg) { - console.error(msg); - }; - break; - case 'none': - break; - default: - throw("invalid logging type '" + level + "'"); - } - }; - JSRocket.Util.get_logging = function () { - return JSRocket.Util._log_level; - }; - // Initialize logging level - JSRocket.Util.init_logging(); - - // Set configuration default for Crockford style function namespaces - JSRocket.Util.conf_default = function (cfg, api, defaults, v, mode, type, defval, desc) { - var getter, setter; - - // Default getter function - getter = function (idx) { - if ((type in {'arr':1, 'array':1}) && - (typeof idx !== 'undefined')) { - return cfg[v][idx]; - } else { - return cfg[v]; - } - }; - - // Default setter function - setter = function (val, idx) { - if (type in {'boolean':1, 'bool':1}) { - if ((!val) || (val in {'0':1, 'no':1, 'false':1})) { - val = false; - } else { - val = true; - } - } else if (type in {'integer':1, 'int':1}) { - val = parseInt(val, 10); - } else if (type === 'str') { - val = String(val); - } else if (type === 'func') { - if (!val) { - val = function () { - }; - } - } - if (typeof idx !== 'undefined') { - cfg[v][idx] = val; - } else { - cfg[v] = val; - } - }; - - // Set the description - api[v + '_description'] = desc; - - // Set the getter function - if (typeof api['get_' + v] === 'undefined') { - api['get_' + v] = getter; - } - - // Set the setter function with extra sanity checks - if (typeof api['set_' + v] === 'undefined') { - api['set_' + v] = function (val, idx) { - if (mode in {'RO':1, 'ro':1}) { - throw(v + " is read-only"); - } else if ((mode in {'WO':1, 'wo':1}) && - (typeof cfg[v] !== 'undefined')) { - throw(v + " can only be set once"); - } - setter(val, idx); - }; - } - - // Set the default value - if (typeof defaults[v] !== 'undefined') { - defval = defaults[v]; - } else if ((type in {'arr':1, 'array':1}) && - (!(defval instanceof Array))) { - defval = []; - } - // Coerce existing setting to the right type - //JSRocket.Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]); - setter(defval); - }; - - // Set group of configuration defaults - JSRocket.Util.conf_defaults = function (cfg, api, defaults, arr) { - var i; - for (i = 0; i < arr.length; i++) { - JSRocket.Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1], - arr[i][2], arr[i][3], arr[i][4]); - } - }; - - /* - * Cross-browser routines - */ - - // Get DOM element position on page - JSRocket.Util.getPosition = function (obj) { - var x = 0, y = 0; - if (obj.offsetParent) { - do { - x += obj.offsetLeft; - y += obj.offsetTop; - obj = obj.offsetParent; - } while (obj); - } - return {'x':x, 'y':y}; - }; - - // Get mouse event position in DOM element - JSRocket.Util.getEventPosition = function (e, obj, scale) { - var evt, docX, docY, pos; - //if (!e) evt = window.event; - evt = (e ? e : window.event); - evt = (evt.changedTouches ? evt.changedTouches[0] : evt.touches ? evt.touches[0] : evt); - if (evt.pageX || evt.pageY) { - docX = evt.pageX; - docY = evt.pageY; - } else if (evt.clientX || evt.clientY) { - docX = evt.clientX + document.body.scrollLeft + - document.documentElement.scrollLeft; - docY = evt.clientY + document.body.scrollTop + - document.documentElement.scrollTop; - } - pos = JSRocket.Util.getPosition(obj); - if (typeof scale === "undefined") { - scale = 1; - } - return {'x':(docX - pos.x) / scale, 'y':(docY - pos.y) / scale}; - }; - - // Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events - JSRocket.Util.addEvent = function (obj, evType, fn) { - if (obj.attachEvent) { - var r = obj.attachEvent("on" + evType, fn); - return r; - } else if (obj.addEventListener) { - obj.addEventListener(evType, fn, false); - return true; - } else { - throw("Handler could not be attached"); - } - }; - - JSRocket.Util.removeEvent = function (obj, evType, fn) { - if (obj.detachEvent) { - var r = obj.detachEvent("on" + evType, fn); - return r; - } else if (obj.removeEventListener) { - obj.removeEventListener(evType, fn, false); - return true; - } else { - throw("Handler could not be removed"); - } - }; - - JSRocket.Util.stopEvent = function (e) { - if (e.stopPropagation) { - e.stopPropagation(); - } - else { - e.cancelBubble = true; - } - - if (e.preventDefault) { - e.preventDefault(); - } - else { - e.returnValue = false; - } - }; - - // Set browser engine versions. Based on mootools. - JSRocket.Util.Features = {xpath:!!(document.evaluate), air:!!(window.runtime), query:!!(document.querySelector)}; - - JSRocket.Util.Engine = { - // Version detection break in Opera 11.60 (errors on arguments.callee.caller reference) - //'presto': (function() { - // return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()), - 'presto':(function () { - return (!window.opera) ? false : true; - }()), - - 'trident':(function () { - return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); - }()), - 'webkit' :(function () { - try { - return (navigator.taintEnabled) ? false : ((JSRocket.Util.Features.xpath) ? ((JSRocket.Util.Features.query) ? 525 : 420) : 419); - } catch (e) { - return false; - } - }()), - //'webkit': (function() { - // return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((JSRocket.Util.Features.xpath) ? ((JSRocket.Util.Features.query) ? 525 : 420) : 419); }()), - 'gecko' :(function () { - return (!document.getBoxObjectFor && - window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); - }()) - }; - if (JSRocket.Util.Engine.webkit) { - // Extract actual webkit version if available - JSRocket.Util.Engine.webkit = (function (v) { - var re = new RegExp('WebKit/([0-9\\.]*) '); - v = (navigator.userAgent.match(re) || ['', v])[1]; - return parseFloat(v, 10); - })(JSRocket.Util.Engine.webkit); - } - - JSRocket.Util.Flash = (function () { - var v, version; - try { - v = navigator.plugins['Shockwave Flash'].description; - } catch (err1) { - try { - v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); - } catch (err2) { - v = '0 r0'; - } - } - version = v.match(/\d+/g); - return {version:parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build:parseInt(version[2], 10) || 0}; - }()); -}()); \ No newline at end of file diff --git a/src/websockifyDependency/websock.js b/src/websockifyDependency/websock.js deleted file mode 100644 index 8fd9f80..0000000 --- a/src/websockifyDependency/websock.js +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Websock: high-performance binary WebSockets - * Copyright (C) 2012 Joel Martin - * Licensed under MPL 2.0 (see LICENSE.txt) - * - * Websock is similar to the standard WebSocket object but Websock - * enables communication with raw TCP sockets (i.e. the binary stream) - * via websockify. This is accomplished by base64 encoding the data - * stream between Websock and websockify. - * - * Websock has built-in receive queue buffering; the message event - * does not contain actual data but is simply a notification that - * there is new data available. Several rQ* methods are available to - * read binary data off of the receive queue. - */ - -// Load Flash WebSocket emulator if needed - -// To force WebSocket emulator even when native WebSocket available -//window.WEB_SOCKET_FORCE_FLASH = true; -// To enable WebSocket emulator debug: -//window.WEB_SOCKET_DEBUG=1; - -if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) { - Websock_native = true; -} else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) { - Websock_native = true; - window.WebSocket = window.MozWebSocket; -} - -function Websock() { -"use strict"; - -var api = {}, // Public API - websocket = null, // WebSocket object - mode = 'base64', // Current WebSocket mode: 'binary', 'base64' - rQ = [], // Receive queue - rQi = 0, // Receive queue index - rQmax = 10000, // Max receive queue size before compacting - sQ = [], // Send queue - - eventHandlers = { - 'message' : function() {}, - 'open' : function() {}, - 'close' : function() {}, - 'error' : function() {} - }, - Util = JSRocket.Util, - test_mode = false; - - -// -// Queue public functions -// - -function get_sQ() { - return sQ; -} - -function get_rQ() { - return rQ; -} -function get_rQi() { - return rQi; -} -function set_rQi(val) { - rQi = val; -} - -function rQlen() { - return rQ.length - rQi; -} - -function rQpeek8() { - return (rQ[rQi] ); -} -function rQshift8() { - return (rQ[rQi++] ); -} -function rQunshift8(num) { - if (rQi === 0) { - rQ.unshift(num); - } else { - rQi -= 1; - rQ[rQi] = num; - } - -} -function rQshift16() { - return (rQ[rQi++] << 8) + - (rQ[rQi++] ); -} -function rQshift32() { - return (rQ[rQi++] << 24) + - (rQ[rQi++] << 16) + - (rQ[rQi++] << 8) + - (rQ[rQi++] ); -} -function rQshiftStr(len) { - if (typeof(len) === 'undefined') { len = rQlen(); } - var arr = rQ.slice(rQi, rQi + len); - rQi += len; - return String.fromCharCode.apply(null, arr); -} -function rQshiftBytes(len) { - if (typeof(len) === 'undefined') { len = rQlen(); } - rQi += len; - return rQ.slice(rQi-len, rQi); -} - -function rQslice(start, end) { - if (end) { - return rQ.slice(rQi + start, rQi + end); - } else { - return rQ.slice(rQi + start); - } -} - -// Check to see if we must wait for 'num' bytes (default to FBU.bytes) -// to be available in the receive queue. Return true if we need to -// wait (and possibly print a debug message), otherwise false. -function rQwait(msg, num, goback) { - var rQlen = rQ.length - rQi; // Skip rQlen() function call - if (rQlen < num) { - if (goback) { - if (rQi < goback) { - throw("rQwait cannot backup " + goback + " bytes"); - } - rQi -= goback; - } - //Util.Debug(" waiting for " + (num-rQlen) + - // " " + msg + " byte(s)"); - return true; // true means need more data - } - return false; -} - -// -// Private utility routines -// - -function encode_message() { - if (mode === 'binary') { - // Put in a binary arraybuffer - return (new Uint8Array(sQ)).buffer; - } else { - // base64 encode - return Base64.encode(sQ); - } -} - -function decode_message(data) { - //Util.Debug(">> decode_message: " + data); - if (mode === 'binary') { - // push arraybuffer values onto the end - rQ.push.apply(rQ, (new Uint8Array(data))); - } else { - // base64 decode and concat to the end - rQ = rQ.concat(Base64.decode(data, 0)); - } - //Util.Debug(">> decode_message, rQ: " + rQ); -} - - -// -// Public Send functions -// - -function flush() { - if (websocket.bufferedAmount !== 0) { - Util.Debug("bufferedAmount: " + websocket.bufferedAmount); - } - if (websocket.bufferedAmount < api.maxBufferedAmount) { - //Util.Debug("arr: " + arr); - //Util.Debug("sQ: " + sQ); - if (sQ.length > 0) { - websocket.send(encode_message(sQ)); - sQ = []; - } - return true; - } else { - Util.Info("Delaying send, bufferedAmount: " + - websocket.bufferedAmount); - return false; - } -} - -// overridable for testing -function send(arr) { - //Util.Debug(">> send_array: " + arr); - sQ = sQ.concat(arr); - return flush(); -} - -function send_string(str) { - //Util.Debug(">> send_string: " + str); - api.send(str.split('').map( - function (chr) { return chr.charCodeAt(0); } ) ); -} - -// -// Other public functions - -function recv_message(e) { - //Util.Debug(">> recv_message: " + e.data.length); - - try { - decode_message(e.data); - if (rQlen() > 0) { - eventHandlers.message(); - // Compact the receive queue - if (rQ.length > rQmax) { - //Util.Debug("Compacting receive queue"); - rQ = rQ.slice(rQi); - rQi = 0; - } - } else { - Util.Debug("Ignoring empty message"); - } - } catch (exc) { - if (typeof exc.stack !== 'undefined') { - Util.Warn("recv_message, caught exception: " + exc.stack); - } else if (typeof exc.description !== 'undefined') { - Util.Warn("recv_message, caught exception: " + exc.description); - } else { - Util.Warn("recv_message, caught exception:" + exc); - } - if (typeof exc.name !== 'undefined') { - eventHandlers.error(exc.name + ": " + exc.message); - } else { - eventHandlers.error(exc); - } - } - //Util.Debug("<< recv_message"); -} - - -// Set event handlers -function on(evt, handler) { - eventHandlers[evt] = handler; -} - -function init(protocols) { - rQ = []; - rQi = 0; - sQ = []; - websocket = null; - - var bt = false, - wsbt = false, - try_binary = false; - - // Check for full typed array support - if (('Uint8Array' in window) && - ('set' in Uint8Array.prototype)) { - bt = true; - } - - // Check for full binary type support in WebSockets - // TODO: this sucks, the property should exist on the prototype - // but it does not. - try { - if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) { - Util.Info("Detected binaryType support in WebSockets"); - wsbt = true; - } - } catch (exc) { - // Just ignore failed test localhost connections - } - - // Default protocols if not specified - if (typeof(protocols) === "undefined") { - if (wsbt) { - protocols = ['binary', 'base64']; - } else { - protocols = 'base64'; - } - } - - // If no binary support, make sure it was not requested - if (!wsbt) { - if (protocols === 'binary') { - throw("WebSocket binary sub-protocol requested but not supported"); - } - if (typeof(protocols) === "object") { - var new_protocols = []; - for (var i = 0; i < protocols.length; i++) { - if (protocols[i] === 'binary') { - Util.Error("Skipping unsupported WebSocket binary sub-protocol"); - } else { - new_protocols.push(protocols[i]); - } - } - if (new_protocols.length > 0) { - protocols = new_protocols; - } else { - throw("Only WebSocket binary sub-protocol was requested and not supported."); - } - } - } - - return protocols; -} - -function open(uri, protocols) { - protocols = init(protocols); - - if (test_mode) { - websocket = {}; - } else { - websocket = new WebSocket(uri, protocols); - } - - websocket.onmessage = recv_message; - websocket.onopen = function() { - Util.Debug(">> WebSock.onopen"); - if (websocket.protocol) { - mode = websocket.protocol; - Util.Info("Server chose sub-protocol: " + websocket.protocol); - } else { - mode = 'base64'; - Util.Error("Server select no sub-protocol!: " + websocket.protocol); - } - if (mode === 'binary') { - websocket.binaryType = 'arraybuffer'; - } - eventHandlers.open(); - Util.Debug("<< WebSock.onopen"); - }; - websocket.onclose = function(e) { - Util.Debug(">> WebSock.onclose"); - eventHandlers.close(e); - Util.Debug("<< WebSock.onclose"); - }; - websocket.onerror = function(e) { - Util.Debug(">> WebSock.onerror: " + e); - eventHandlers.error(e); - Util.Debug("<< WebSock.onerror"); - }; -} - -function close() { - if (websocket) { - if ((websocket.readyState === WebSocket.OPEN) || - (websocket.readyState === WebSocket.CONNECTING)) { - Util.Info("Closing WebSocket connection"); - websocket.close(); - } - websocket.onmessage = function (e) { return; }; - } -} - -// Override internal functions for testing -// Takes a send function, returns reference to recv function -function testMode(override_send) { - test_mode = true; - api.send = override_send; - api.close = function () {}; - return recv_message; -} - -function constructor() { - // Configuration settings - api.maxBufferedAmount = 200; - - // Direct access to send and receive queues - api.get_sQ = get_sQ; - api.get_rQ = get_rQ; - api.get_rQi = get_rQi; - api.set_rQi = set_rQi; - - // Routines to read from the receive queue - api.rQlen = rQlen; - api.rQpeek8 = rQpeek8; - api.rQshift8 = rQshift8; - api.rQunshift8 = rQunshift8; - api.rQshift16 = rQshift16; - api.rQshift32 = rQshift32; - api.rQshiftStr = rQshiftStr; - api.rQshiftBytes = rQshiftBytes; - api.rQslice = rQslice; - api.rQwait = rQwait; - - api.flush = flush; - api.send = send; - api.send_string = send_string; - - api.on = on; - api.init = init; - api.open = open; - api.close = close; - api.testMode = testMode; - - return api; -} - -return constructor(); - -} \ No newline at end of file