1 /*
  2 Script: Deluge.Client.js
  3     A JSON-RPC proxy built on top of ext-core.
  4 
  5 Copyright:
  6     (C) Damien Churchill 2009 <damoxc@gmail.com>
  7     This program is free software; you can redistribute it and/or modify
  8     it under the terms of the GNU General Public License as published by
  9     the Free Software Foundation; either version 3, or (at your option)
 10     any later version.
 11 
 12     This program is distributed in the hope that it will be useful,
 13     but WITHOUT ANY WARRANTY; without even the implied warranty of
 14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15     GNU General Public License for more details.
 16 
 17     You should have received a copy of the GNU General Public License
 18     along with this program.  If not, write to:
 19         The Free Software Foundation, Inc.,
 20         51 Franklin Street, Fifth Floor
 21         Boston, MA  02110-1301, USA.
 22 
 23     In addition, as a special exception, the copyright holders give
 24     permission to link the code of portions of this program with the OpenSSL
 25     library.
 26     You must obey the GNU General Public License in all respects for all of
 27     the code used other than OpenSSL. If you modify file(s) with this
 28     exception, you may extend this exception to your version of the file(s),
 29     but you are not obligated to do so. If you do not wish to do so, delete
 30     this exception statement from your version. If you delete this exception
 31     statement from all source files in the program, then also delete it here.
 32 
 33 */
 34 
 35 Ext.namespace('Ext.ux.util');
 36 (function() {
 37     Ext.ux.util.RpcClient = Ext.extend(Ext.util.Observable, {
 38 
 39         _components: [],
 40         
 41         _methods: [],
 42         
 43         _requests: {},
 44         
 45         _url: null,
 46         
 47         _optionKeys: ['scope', 'success', 'failure'],
 48         
 49         constructor: function(config) {
 50             Ext.ux.util.RpcClient.superclass.constructor.call(this, config);
 51             this._url = config.url || null;
 52             this._id = 0;
 53             
 54             this.addEvents(
 55                 // raw events
 56                 /**
 57                  * @event connected
 58                  * Fires when the client has retrieved the list of methods from the server.
 59                  * @param {Ext.ux.util.RpcClient} this
 60                  */
 61                  'connected'
 62             );
 63             this.reloadMethods();
 64         },
 65         
 66         reloadMethods: function() {
 67             Ext.each(this._components, function(component) {
 68                 delete this[component];
 69             }, this);
 70             this._execute('system.listMethods', {
 71                 success: this._setMethods,
 72                 scope: this
 73             });
 74         },
 75     
 76         _execute: function(method, options) {
 77             options = options || {};
 78             options.params = options.params || [];
 79             options.id = this._id;
 80             
 81             var request = Ext.encode({
 82                 method: method,
 83                 params: options.params,
 84                 id: options.id
 85             });
 86             this._id++;
 87             
 88             return Ext.Ajax.request({
 89                 url: this._url,
 90                 method: 'POST',
 91                 success: this._onSuccess,
 92                 failure: this._onFailure,
 93                 scope: this,
 94                 jsonData: request,
 95                 options: options
 96             });
 97         },
 98         
 99         _onFailure: function(response, requestOptions) {
100             var options = requestOptions.options;
101             errorObj = {
102                 id: options.id,
103                 result: null,
104                 error: 'HTTP: ' + response.status + ' ' + response.statusText
105             }            
106             if (Ext.type(options.failure) != 'function') return;
107             if (options.scope) {
108                 options.failure.call(options.scope, errorObj, response, requestOptions);
109             } else {
110                 options.failure(errorObj, response, requestOptions);
111             }
112         },
113         
114         _onSuccess: function(response, requestOptions) {
115             var responseObj = Ext.decode(response.responseText);
116             var options = requestOptions.options;
117             if (responseObj.error) {
118                 if (Ext.type(options.failure) != 'function') return;
119                 if (options.scope) {
120                     options.failure.call(options.scope, responseObj, response, requestOptions);
121                 } else {
122                     options.failure(responseObj, response, requestOptions);
123                 }
124             } else {
125                 if (Ext.type(options.success) != 'function') return;
126                 if (options.scope) {
127                     options.success.call(options.scope, responseObj.result, responseObj, response, requestOptions);
128                 } else {
129                     options.success(responseObj.result, responseObj, response, requestOptions);
130                 }
131             }
132         },
133         
134         _parseArgs: function(args) {
135             var params = [];
136             Ext.each(args, function(arg) {
137                 params.push(arg);
138             });
139             
140             var options = params[params.length - 1];
141             if (Ext.type(options) == 'object') {
142                 var keys = Ext.keys(options), isOption = false;
143                 
144                 Ext.each(this._optionKeys, function(key) {
145                     if (keys.indexOf(key) > -1) isOption = true;
146                 });
147                 
148                 if (isOption) {
149                     params.remove(options)
150                 } else {
151                     options = {}
152                 }
153             } else {
154                 options = {}
155             }
156             options.params = params;
157             return options;
158         },
159     
160         _setMethods: function(methods) {
161             var components = {}, self = this;
162             
163             Ext.each(methods, function(method) {
164                 var parts = method.split('.');
165                 var component = components[parts[0]] || {};
166                 
167                 var fn = function() {
168                     var options = self._parseArgs(arguments);
169                     return self._execute(method, options);
170                 }
171                 component[parts[1]] = fn;
172                 components[parts[0]] = component;
173             });
174             
175             for (var name in components) {
176                 self[name] = components[name];
177             }
178             
179             this._components = Ext.keys(components);
180             this.fireEvent('connected', this);
181         }
182     });
183 })();
184