From a5ebd19ec2a542d3fa5592cc667124564a8e77fb Mon Sep 17 00:00:00 2001 From: Hamza Zia Date: Wed, 5 Sep 2012 22:53:09 +0800 Subject: [PATCH] connection handling refactored all the way all the refactored connection handling code resides in the connection.js file, its a lot more rebost although still might have bugs --- index.html | 2 + js/connection.js | 153 +++++++++++++++++++++++++++++++++++++++++++++++ js/manager.js | 0 js/script.js | 132 ++-------------------------------------- js/utils.js | 18 ++++++ 5 files changed, 178 insertions(+), 127 deletions(-) create mode 100644 js/connection.js create mode 100644 js/manager.js create mode 100644 js/utils.js diff --git a/index.html b/index.html index 8b7a61b..4e9f5c9 100755 --- a/index.html +++ b/index.html @@ -22,6 +22,8 @@ + + diff --git a/js/connection.js b/js/connection.js new file mode 100644 index 0000000..08a5196 --- /dev/null +++ b/js/connection.js @@ -0,0 +1,153 @@ +var JsonRPC = function(conf) { + if (!this instanceof JsonRPC) + return new JsonRPC(); + this.avgTimeout = 1000; + this.serverConf = conf; +}; +JsonRPC.prototype = { + encode: function(obj) { + return base64.btoa(JSON.stringify(obj)); + }, + ariaRequest: function(url, multicall, funcName, params, success, error) { + var startTime = new Date(); + $.ajax({ + url: url, + timeout: 1000, + data: { + jsonrpc: 2.0, + id: 'webui', + method: funcName.search(/\./g) == -1 ? 'aria2.' + funcName : funcName, + params: params.length ? this.encode(params) : undefined + }, + success: function(data) { + this.avgTimeout = 3 * (new Date() - startTime); + return success(data) + }, + error: error, + dataType: 'jsonp', + jsonp: 'jsoncallback' + }); + }, + invoke: function(opts) { + var rpc = this; + rpc.ariaRequest( + 'http://' + rpc.serverConf.host + ':' + rpc.serverConf.port + '/jsonrpc', + opts.multicall, + opts.func, + opts.params, + opts.success, + function() { + // check if authentication details are given, if yes then use a hack to support + // http authentication otherwise emit error + if (!rpc.serverConf.user.length) { + console.log("no user name and still error!!!"); + return opts.error(); + } + + var authUrl = 'http://' + + rpc.serverConf.user + ":" + + rpc.serverConf.pass + "@" + + rpc.serverConf.host + ':' + + rpc.serverConf.port + '/jsonrpc'; + + // hack is to basically inject an image with same uri as the aria2 rpc url, + // most browsers will then cache the authentication details and we dont have + // to give them next time we make a request + var img = $('').attr("src", authUrl); + $('body').append(img); + img.remove(); + + // timeout to let the image load and then make a request, + setTimeout(function() { + rpc.ariaRequest( + authUrl, + opts.multicall, + opts.params, + opts.success, + opts.error + ); + }, rpc.avgTimeout); + } + ); + } +}; + +var SocketRPC = function(conf) { + if (!this instanceof SocketRPC) + return new SocketRPC(); + + var rpc = this; + rpc.serverConf = conf; + rpc.initialized = false; + rpc.handles = []; + rpc.sock = new WebSocket('ws://' + conf.host + ':' + conf.port + '/jsonrpc'); + rpc.sock.onopen = function() { + rpc.initialized = true; + }; + rpc.sock.onclose = rpc.sock.onerror = function() { + _.each(handles, function(h) { h.error() }); + rpc.handles = []; + }; + rpc.sock.onmessage = function(message) { + var data = JSON.parse(message.data); + for (var i = rpc.handles.length; i--; ) { + if (rpc.handles[i].id === data.id) { + if (data.error) + rpc.handles[i].error(); + else + rpc.handles[i].success(data); + rpc.handles.splice(i, 1); + return; + } + } + }; +} +SocketRPC.prototype = { + invoke: function(opts) { + var data = { + jsonrpc: 2.0, + id: 'webui_' + utils.randStr(), + method: opts.func.search(/\./g) == -1 ? 'aria2.' + opts.func : opts.func, + params: opts.params.length ? opts.params : undefined + }; + + this.handles.push({ + success: opts.success, + error: opts.error, + id: data.id + }); + this.sock.send(JSON.stringify(data)); + }, +}; +var AriaConnection = function(conf) { + var conf = conf || { + host: 'localhost', + port: 6800, + user: '', + pass: '' + }; + var jRPC = new JsonRPC(conf); + if (typeof WebSocket != "undefined") { + var sockRPC = new SocketRPC(conf); + } + + return { + conf: conf, + invoke: function(opts) { + opts = utils.mixin(opts, { + success: function() {}, + error: function() {}, + params: [], + func: '' + }); + var err = opts.error; + opts.error = function() { throw "cant run error!!!" }; + if (!sockRPC || !sockRPC.initialized || true) + return jRPC.invoke(opts); + else + return sockRPC.invoke(opts); + } + }; +} + + diff --git a/js/manager.js b/js/manager.js new file mode 100644 index 0000000..e69de29 diff --git a/js/script.js b/js/script.js index d8a3f40..a6cd53d 100755 --- a/js/script.js +++ b/js/script.js @@ -15,10 +15,6 @@ var modals = { new_metalink_modal: undefined, download_settings_modal: undefined }; -var web_sock = undefined; -var web_sock_queue = []; -var web_sock_id = 0; -var web_sock_support = typeof WebSocket != "undefined" ? 1 : 0; var clear_dialogs = function() { for(var i in modals) { modals[i].modal('hide'); @@ -31,6 +27,7 @@ var server_conf = { pass: "" }; +var ariaConnection = new AriaConnection(server_conf); var set_conf_cookie = function() { setCookie('aria2_server_conf', JSON.stringify(server_conf), 30 * 12); } @@ -56,131 +53,15 @@ var update_server_conf = function() { if(port.length !== 0) { server_conf.port = port; } - web_sock = undefined; set_conf_cookie(); + ariaConnection = new AriaConnection(server_conf); clear_dialogs(); update_ui(); }; -function param_encode(param) { - if(param) { - param = base64.btoa(JSON.stringify(param)); - } - return param; -} - -var web_sock_error = function() { - for(var i = 0; i < web_sock_queue.length; i++) { - web_sock_queue[i].error(); - web_sock_queue.splice(i, 1); - } -} -var web_sock_message = function(message) { - var data = JSON.parse(message.data); - for(var i = 0; i < web_sock_queue.length; i++) { - if(web_sock_queue[i].id === data.id) { - if(data.error) { - if(web_sock_queue[i].error) - web_sock_queue[i].error(); - } - else { - web_sock_queue[i].success(data); - } - web_sock_queue.splice(i, 1); - } - } -} -var web_sock_send = function(conf, multicall) { - var id = 'webui_' + (web_sock_id++).toString(); - var data = { - jsonrpc: 2.0, - id: id, - method: multicall? conf.func:'aria2.' + conf.func, - params: conf.params - }; - web_sock_queue.push({ - success: conf.success, - error: conf.error, - id: id - }); - web_sock.send(JSON.stringify(data)); -} -var web_sock_init = function() { - if(!web_sock) { - var sock = new WebSocket('ws://' + server_conf.host + ':' + server_conf.port + '/jsonrpc'); - sock.onopen = function() { - console.log('websocket connected!!!'); - web_sock = sock; - }; - sock.onclose = function() { - web_sock_error(); - web_sock = undefined; - }; - sock.onerror = web_sock_error; - sock.onmessage = web_sock_message; - } -} - -var jsonp_syscall = function(conf, multicall) { - $.ajax({ - url: 'http://' + server_conf.host + ':' + server_conf.port + '/jsonrpc', - timeout: 1000, - data: { - jsonrpc: 2.0, - id: 'webui', - method: multicall? conf.func:'aria2.' + conf.func, - params: param_encode(conf.params) - }, - success: conf.success, - error: function() { - if(server_conf.user.length) { - var url = 'http://' + - server_conf.user + ":" + - server_conf.pass + "@" + - server_conf.host + ':' + - server_conf.port + '/jsonrpc'; - - /* hack for http authentication */ - var img = $('').attr("src", url); - $('body').append(img); - img.remove(); - - setTimeout(function() { - $.ajax({ - url: url, - timeout: 1000, - data: { - jsonrpc: 2.0, - id: 'webui', - method: multicall? conf.func:'aria2.' + conf.func, - params: param_encode(conf.params) - }, - success: conf.success, - error: conf.error, - dataType: 'jsonp', - jsonp: 'jsoncallback' - }); - }, 1000); - } - else if(conf.error) { - conf.error(); - } - }, - dataType: 'jsonp', - jsonp: 'jsoncallback' - }); -} -var aria_syscall = function(conf, multicall) { - if(!web_sock_support || server_conf.user.length || server_conf.pass.length) { - jsonp_syscall(conf, multicall); - } - else if(web_sock) { - web_sock_send(conf, multicall); - } - else { - web_sock_init(); - jsonp_syscall(conf, multicall); - } +var aria_syscall = function(conf, multicall, old) { + conf.multicall = multicall; + ariaConnection.invoke(conf); } var update_ui = function() { updateDownloads(); @@ -207,9 +88,6 @@ $(function() { modals.new_torrent_modal = $('#new_torrent').modal(modal_conf); modals.new_metalink_modal = $('#new_metalink').modal(modal_conf); - if(web_sock_support) - web_sock_init(); - update_ui(); globalGraphData = { downSpeed: [], diff --git a/js/utils.js b/js/utils.js new file mode 100644 index 0000000..622b858 --- /dev/null +++ b/js/utils.js @@ -0,0 +1,18 @@ +var utils = { + randStr: function() { + var str = []; + var hexDigits = "0123456789abcdef"; + for (var i = 0; i < 36; i++) { + str[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); + } + return str.join(""); + }, + mixin: function(fromObj, toObj) { + for (var key in toObj) { + if (toObj.hasOwnProperty(key) && fromObj[key]) { + toObj[key] = fromObj[key]; + } + } + return toObj; + } +};