Created
November 8, 2013 13:16
-
-
Save kanaka/7370898 to your computer and use it in GitHub Desktop.
noVNC patch file to add Chrome packaged app support. It uses the Chrome packaged app socket support so it can connect directly to normal TCP VNC servers. This is an old patch and does not cleanly apply to head any longer but the changes needed are probably fairly minor.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/include/chrome-app/launcher.js b/include/chrome-app/launcher.js | |
| new file mode 100644 | |
| index 0000000..7a5f585 | |
| --- /dev/null | |
| +++ b/include/chrome-app/launcher.js | |
| @@ -0,0 +1,11 @@ | |
| +console.log(">> launcher.js"); | |
| + | |
| +chrome.app.runtime.onLaunched.addListener(function() { | |
| + chrome.app.window.create('vnc.html', { | |
| + 'width': 800, | |
| + 'height': 800, | |
| + 'type': 'shell' | |
| + }); | |
| +}); | |
| + | |
| +console.log("<< launcher.js"); | |
| diff --git a/include/chrome-app/socket.js b/include/chrome-app/socket.js | |
| new file mode 100644 | |
| index 0000000..bc0062e | |
| --- /dev/null | |
| +++ b/include/chrome-app/socket.js | |
| @@ -0,0 +1,296 @@ | |
| +/* | |
| + * Websock: high-performance binary WebSockets | |
| + * Copyright (C) 2012 Joel Martin | |
| + * Licensed under LGPL-3 (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. | |
| + */ | |
| + | |
| +/*jslint browser: true, bitwise: false, plusplus: false */ | |
| +/*global Util, Base64 */ | |
| + | |
| + | |
| +Websock_native = true; | |
| + | |
| +function Websock() { | |
| +"use strict"; | |
| + | |
| +var api = {}, // Public API | |
| + socket = null, // Chrome socket object | |
| + 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() {} | |
| + }, | |
| + | |
| + 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 arr.map(function (num) { | |
| + return String.fromCharCode(num); } ).join(''); | |
| + | |
| +} | |
| +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() { | |
| + /* base64 encode */ | |
| + return (new Uint8Array(sQ)).buffer; | |
| +} | |
| + | |
| +function decode_message(data) { | |
| + //Util.Debug(">> decode_message: " + data); | |
| + rQ.push.apply(rQ, (new Uint8Array(data))); | |
| + //Util.Debug(">> decode_message, rQ: " + rQ); | |
| +} | |
| + | |
| + | |
| +// | |
| +// Public Send functions | |
| +// | |
| + | |
| +function flush() { | |
| + if (sQ.length > 0) { | |
| + socket.sendBuffer(encode_message(sQ)); | |
| + sQ = []; | |
| + } | |
| + return true; | |
| +} | |
| + | |
| +// 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(data) { | |
| + //Util.Debug(">> recv_message: " + data.length); | |
| + | |
| + try { | |
| + decode_message(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() { | |
| + rQ = []; | |
| + rQi = 0; | |
| + sQ = []; | |
| + socket = null; | |
| +} | |
| + | |
| +function open(uri) { | |
| + init(); | |
| + | |
| + var parts = uri.split("/")[2].split(":"), | |
| + host = parts[0], | |
| + port = parseInt(parts[1], 10); | |
| + | |
| + socket = new TcpClient(host, port); | |
| + | |
| + socket.addResponseListener(recv_message, "arraybuffer"); | |
| + socket.addDisconnectListener(function() { | |
| + Util.Debug(">> WebSock.onclose"); | |
| + eventHandlers.close({}); | |
| + Util.Debug("<< WebSock.onclose"); | |
| + }); | |
| + | |
| + socket.connect(function() { | |
| + Util.Debug(">> WebSock.onopen"); | |
| + eventHandlers.open(); | |
| + Util.Debug("<< WebSock.onopen"); | |
| + }); | |
| +} | |
| + | |
| +function close() { | |
| + if (socket) { | |
| + socket.disconnect(); | |
| + } | |
| +} | |
| + | |
| +// 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(); | |
| + | |
| +} | |
| diff --git a/include/rfb.js b/include/rfb.js | |
| index 5b46c12..859725c 100644 | |
| --- a/include/rfb.js | |
| +++ b/include/rfb.js | |
| @@ -134,6 +134,7 @@ Util.conf_defaults(conf, that, defaults, [ | |
| ['focusContainer', 'wo', 'dom', document, 'DOM element that captures keyboard input'], | |
| ['encrypt', 'rw', 'bool', false, 'Use TLS/SSL/wss encryption'], | |
| + ['chrome_socket', 'rw', 'bool', false, 'Use Chrome package app raw sockets'], | |
| ['true_color', 'rw', 'bool', true, 'Request true color pixel data'], | |
| ['local_cursor', 'rw', 'bool', false, 'Request locally rendered cursor'], | |
| ['shared', 'rw', 'bool', true, 'Request shared mode'], | |
| @@ -187,6 +188,18 @@ that.set_local_cursor = function(cursor) { | |
| } | |
| }; | |
| +that.set_chrome_socket = function (enable) { | |
| + if ((!enable) || (enable in {'0':1, 'no':1, 'false':1})) { | |
| + conf.chrome_socket = false; | |
| + } else { | |
| + if (window.chrome && window.chrome.socket) { | |
| + conf.chrome_socket = true; | |
| + } else { | |
| + Util.Warn("Chrome raw sockets are only availble in Chrome packaged apps"); | |
| + } | |
| + } | |
| +}; | |
| + | |
| // These are fake configuration getters | |
| that.get_display = function() { return display; }; | |
| @@ -293,7 +306,9 @@ function connect() { | |
| if (typeof UsingSocketIO !== "undefined") { | |
| uri = "http://" + rfb_host + ":" + rfb_port + "/" + rfb_path; | |
| } else { | |
| - if (conf.encrypt) { | |
| + if (conf.chrome_socket) { | |
| + uri = "tcp://"; | |
| + } else if (conf.encrypt) { | |
| uri = "wss://"; | |
| } else { | |
| uri = "ws://"; | |
| diff --git a/include/ui.js b/include/ui.js | |
| index f6eda04..679ad52 100644 | |
| --- a/include/ui.js | |
| +++ b/include/ui.js | |
| @@ -11,9 +11,34 @@ | |
| /*global window, $D, Util, WebUtil, RFB, Display */ | |
| // Load supporting scripts | |
| -window.onscriptsload = function () { UI.load(); }; | |
| -Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js", | |
| - "input.js", "display.js", "jsunzip.js", "rfb.js"]); | |
| +var jsList = ["webutil.js", "base64.js", "websock.js", "des.js", | |
| + "input.js", "display.js", "jsunzip.js", "rfb.js"]; | |
| +if (window.chrome && chrome.app && chrome.app.window) { | |
| + // We are a Chrome app/extension, load raw socket support | |
| + | |
| + jsList.push("chrome-app/tcp-client.js"); | |
| + | |
| + // Hook it into the UI initialization | |
| + window.onscriptsload = function () { | |
| + UI.load(function (rfb) { | |
| + rfb.set_onFBResize(function (rfb, width, height) { | |
| + // Title + control bar + status bar + a bit more | |
| + var sbar = $D('noVNC_status_bar'), | |
| + extra = sbar.offsetTop + sbar.offsetHeight + 4; | |
| + console.log("FB width, height:", width, height); | |
| + console.log("Resizing to width, height:", width, height+extra); | |
| + chrome.app.window.current().resizeTo(width, height+extra); | |
| + }); | |
| + }); | |
| + }; | |
| +} else { | |
| + // We are just a web app, do the usual | |
| + window.onscriptsload = function () { | |
| + UI.load(); | |
| + }; | |
| +} | |
| +Util.load_scripts(jsList); | |
| + | |
| var UI = { | |
| @@ -109,11 +134,15 @@ start: function(callback) { | |
| UI.setViewClip(); | |
| Util.addEvent(window, 'resize', UI.setViewClip); | |
| - Util.addEvent(window, 'beforeunload', function () { | |
| - if (UI.rfb_state === 'normal') { | |
| - return "You are currently connected."; | |
| - } | |
| - } ); | |
| + try { | |
| + Util.addEvent(window, 'beforeunload', function () { | |
| + if (UI.rfb_state === 'normal') { | |
| + return "You are currently connected."; | |
| + } | |
| + } ); | |
| + } catch (e) { | |
| + Util.Warn("Could not register beforeunload handler"); | |
| + } | |
| // Show description by default when hosted at for kanaka.github.com | |
| if (location.host === "kanaka.github.com") { | |
| @@ -547,6 +576,11 @@ connect: function() { | |
| UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout')); | |
| UI.rfb.set_repeaterID(UI.getSetting('repeaterID')); | |
| + // TODO: configurable | |
| + if (window.chrome && window.chrome.socket) { | |
| + UI.rfb.set_chrome_socket(true); | |
| + } | |
| + | |
| UI.rfb.connect(host, port, password, path); | |
| //Close dialog. | |
| @@ -697,7 +731,12 @@ addOption: function(selectbox,text,value ) | |
| }, | |
| setBarPosition: function() { | |
| - $D('noVNC-control-bar').style.top = (window.pageYOffset) + 'px'; | |
| + var extra = 0; | |
| + if (window.chrome && chrome.app && chrome.app.window) { | |
| + extra = 24; | |
| + $D('noVNC-menu-bar').style.display = "block"; | |
| + } | |
| + $D('noVNC-control-bar').style.top = (window.pageYOffset+extra) + 'px'; | |
| $D('noVNC_mobile_buttons').style.left = (window.pageXOffset) + 'px'; | |
| var vncwidth = $D('noVNC_screen').style.offsetWidth; | |
| diff --git a/include/websock.js b/include/websock.js | |
| index 9d6a306..47a749b 100644 | |
| --- a/include/websock.js | |
| +++ b/include/websock.js | |
| @@ -52,7 +52,9 @@ function Websock() { | |
| var api = {}, // Public API | |
| websocket = null, // WebSocket object | |
| + chrsocket = null, // Chrome socket object | |
| mode = 'base64', // Current WebSocket mode: 'binary', 'base64' | |
| + wsBinaryTypes = false, // whether we have WebSocket binaryType support | |
| rQ = [], // Receive queue | |
| rQi = 0, // Receive queue index | |
| rQmax = 10000, // Max receive queue size before compacting | |
| @@ -186,21 +188,29 @@ function decode_message(data) { | |
| // | |
| 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 (websocket) { | |
| + 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; | |
| + } | |
| + } else if (chrsocket) { | |
| if (sQ.length > 0) { | |
| - websocket.send(encode_message(sQ)); | |
| + chrsocket.sendBuffer(encode_message(sQ)); | |
| sQ = []; | |
| } | |
| return true; | |
| - } else { | |
| - Util.Info("Delaying send, bufferedAmount: " + | |
| - websocket.bufferedAmount); | |
| - return false; | |
| } | |
| } | |
| @@ -220,11 +230,11 @@ function send_string(str) { | |
| // | |
| // Other public functions | |
| -function recv_message(e) { | |
| - //Util.Debug(">> recv_message: " + e.data.length); | |
| +function recv_message(data) { | |
| + //Util.Debug(">> recv_message: " + data.length); | |
| try { | |
| - decode_message(e.data); | |
| + decode_message(data); | |
| if (rQlen() > 0) { | |
| eventHandlers.message(); | |
| // Compact the receive queue | |
| @@ -259,15 +269,20 @@ function on(evt, handler) { | |
| eventHandlers[evt] = handler; | |
| } | |
| -function init(protocols) { | |
| +function init() { | |
| rQ = []; | |
| rQi = 0; | |
| sQ = []; | |
| websocket = null; | |
| + chrsocket = null; | |
| var bt = false, | |
| - wsbt = false, | |
| - try_binary = false; | |
| + try_binary = false, | |
| + supportedProtocols = []; | |
| + | |
| + if (window.chrome && window.chrome.socket && window.TcpClient) { | |
| + supportedProtocols.push("chrome-socket"); | |
| + } | |
| // Check for full typed array support | |
| if (('Uint8Array' in window) && | |
| @@ -281,56 +296,72 @@ function init(protocols) { | |
| try { | |
| if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) { | |
| Util.Info("Detected binaryType support in WebSockets"); | |
| - wsbt = true; | |
| + wsBinaryTypes = true; | |
| + supportedProtocols.push('binary'); | |
| } | |
| } 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'; | |
| - } | |
| - } | |
| + supportedProtocols.push('base64'); | |
| + return supportedProtocols; | |
| +} | |
| - // 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."); | |
| - } | |
| - } | |
| - } | |
| +function openChromeSocket(uri) { | |
| + var parts = uri.split("/")[2].split(":"), | |
| + host = parts[0], | |
| + port = parseInt(parts[1], 10); | |
| - return protocols; | |
| + mode = 'binary'; | |
| + chrsocket = new TcpClient(host, port); | |
| + | |
| + chrsocket.addResponseListener(recv_message, "arraybuffer"); | |
| + chrsocket.addDisconnectListener(function() { | |
| + Util.Debug(">> WebSock.onclose"); | |
| + eventHandlers.close({}); | |
| + Util.Debug("<< WebSock.onclose"); | |
| + }); | |
| + | |
| + chrsocket.connect(function() { | |
| + Util.Debug(">> WebSock.onopen"); | |
| + eventHandlers.open(); | |
| + Util.Debug("<< WebSock.onopen"); | |
| + }); | |
| } | |
| -function open(uri, protocols) { | |
| - protocols = init(protocols); | |
| +function openWebSocket(uri, protocols) { | |
| - if (test_mode) { | |
| - websocket = {}; | |
| - } else { | |
| - websocket = new WebSocket(uri, protocols); | |
| + console.log("uri:", uri, " protocols:", protocols); | |
| + | |
| + // If no binary support, make sure it was not requested | |
| + if (!wsBinaryTypes && (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 (!wsBinaryTypes && (protocols[i] === 'binary')) { | |
| + Util.Error("Skipping unsupported WebSocket binary sub-protocol"); | |
| + } else if (protocols[i] === 'chrome-socket') { | |
| + Util.Warn("Skipping Chrome raw socket sub-protocol"); | |
| + } else { | |
| + new_protocols.push(protocols[i]); | |
| + } | |
| + } | |
| + if (new_protocols.length === 0) { | |
| + throw("No valid WebSocket sub-protocol found from: " + protocols); | |
| + } | |
| + protocols = new_protocols; | |
| } | |
| - websocket.onmessage = recv_message; | |
| + console.log("uri:", uri, " new protocols:", protocols); | |
| + mode = 'base64'; | |
| + websocket = new WebSocket(uri, protocols); | |
| + websocket.onmessage = function (e) { | |
| + //Util.Debug(">> WebSock.onmessage"); | |
| + recv_message(e.data); | |
| + //Util.Debug("<< WebSock.onmessage"); | |
| + }; | |
| websocket.onopen = function() { | |
| Util.Debug(">> WebSock.onopen"); | |
| if (websocket.protocol) { | |
| @@ -358,6 +389,22 @@ function open(uri, protocols) { | |
| }; | |
| } | |
| +function open(uri, protocols) { | |
| + protocols = init(protocols); | |
| + | |
| + if (test_mode) { | |
| + websocket = {}; | |
| + } else { | |
| + if ((uri.toLowerCase().search("ws://") === 0) || | |
| + (uri.toLowerCase().search("wss://") === 0)) { | |
| + openWebSocket(uri, protocols); | |
| + } else if (uri.toLowerCase().search("tcp://") === 0) { | |
| + openChromeSocket(uri); | |
| + } | |
| + } | |
| + | |
| +} | |
| + | |
| function close() { | |
| if (websocket) { | |
| if ((websocket.readyState === WebSocket.OPEN) || | |
| @@ -366,7 +413,10 @@ function close() { | |
| websocket.close(); | |
| } | |
| websocket.onmessage = function (e) { return; }; | |
| + } else if (chrsocket) { | |
| + chrsocket.disconnect(); | |
| } | |
| + websocket = chrsocket = null; | |
| } | |
| // Override internal functions for testing | |
| diff --git a/manifest.json b/manifest.json | |
| new file mode 100644 | |
| index 0000000..b468c8a | |
| --- /dev/null | |
| +++ b/manifest.json | |
| @@ -0,0 +1,18 @@ | |
| +{ | |
| + "name": "noVNC", | |
| + "version": "0.4", | |
| + "description": "HTML5 VNC client.", | |
| + "manifest_version": 2, | |
| + "minimum_chrome_version": "23", | |
| + "app": { | |
| + "background": { | |
| + "scripts": ["include/chrome-app/launcher.js"] | |
| + } | |
| + }, | |
| + "permissions": ["app.window", | |
| + "storage", | |
| + "experimental", | |
| + {"socket": [ "tcp-connect:*:*" ] }], | |
| + "icons": { "16": "images/favicon.png", | |
| + "128": "images/screen_128x128.png" } | |
| +} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment