refactor+enhance json api

This commit is contained in:
Martijn Voncken 2008-07-15 17:36:18 +00:00
parent 9b12c231da
commit 6a216c0122
4 changed files with 89 additions and 111 deletions

View File

@ -53,6 +53,25 @@ from utils import dict_cb
from lib import json from lib import json
def json_response(result, id):
print json.write({
"version":"1.1",
"result":result,
"id":id
})
def json_error(message , id , msg_number=123):
log.error("JSON-error:%s" % message)
print json.write({
"version":"1.1",
"id":id,
"error":{
"number":msg_number,
"message":message,
"error":message
}
})
class json_rpc: class json_rpc:
""" """
== Full client api == == Full client api ==
@ -60,6 +79,10 @@ class json_rpc:
* rpc-api : http://en.wikipedia.org/wiki/JSON-RPC#Version_1.0 * rpc-api : http://en.wikipedia.org/wiki/JSON-RPC#Version_1.0
* methods : http://dev.deluge-torrent.org/wiki/Development/UiClient#Remoteapi * methods : http://dev.deluge-torrent.org/wiki/Development/UiClient#Remoteapi
""" """
#extra exposed methods
json_exposed = ["update_ui","get_stats","system_listMethods"]
def GET(self): def GET(self):
print '{"error":"only POST is supported"}' print '{"error":"only POST is supported"}'
@ -67,38 +90,30 @@ class json_rpc:
def POST(self , name=None): def POST(self , name=None):
web.header("Content-Type", "application/x-json") web.header("Content-Type", "application/x-json")
ck = cookies() ck = cookies()
if not(ck.has_key("session_id") and ck["session_id"] in utils.SESSIONS):
print """{"error":{
"number":1,
"message":"not authenticated",
"error":"not authenticated"
}
}
"""
return
id = 0 id = 0
if not(ck.has_key("session_id") and ck["session_id"] in utils.SESSIONS):
return json_error("not authenticated", id)
try: try:
log.debug("json-data:") log.debug("json-data:")
log.debug(webapi.data()) log.debug(webapi.data())
json_data = json.read(webapi.data()) json_data = json.read(webapi.data())
id = json_data["id"] id = json_data["id"]
method = json_data["method"] method = json_data["method"].replace(".", "_")
params = json_data["params"] params = json_data["params"]
if method.startswith('_'): if method.startswith('_'):
raise Exception('_ methods are illegal.') raise Exception('_ methods are illegal.')
if method.startswith("system."): elif method in self.json_exposed:
result = self.exec_system_method(method, params,id) func = getattr(self, method)
elif method == ("list_torrents"): result = func(*params)
result = self.list_torrents(method, params,id)
elif method == ("get_stats"):
result = self.exec_get_stats(method, params,id)
else: else:
result = self.exec_client_method(method, params,id) result = self.exec_client_method(method, params)
log.debug("JSON-result:%s(%s)[%s] = %s" % (method, params, id, result)) #log.debug("JSON-result:%s(%s)[%s] = %s" % (method, params, id, result))
print json.write(result)
return json_response(result, id)
except Exception,e: except Exception,e:
#verbose because you don't want exeptions in the error-handler. #verbose because you don't want exeptions in the error-handler.
@ -106,42 +121,24 @@ class json_rpc:
if hasattr(e,"message"): if hasattr(e,"message"):
message = e.message message = e.message
log.debug(format_exc()) log.debug(format_exc())
log.error("JSON-error:%s:%s %s" % (e, message, id)) return json_error("%s:%s" % (e, message), id)
print json.write({
"version":"1.1",
"id":id,
"error":{
"number":123,
"message":"%s:%s %s" % (e, message, id),
"error":format_exc()
}
})
def exec_client_method(self, method, params, id): def exec_client_method(self, method, params):
if not hasattr(sclient,method): if not hasattr(sclient,method):
raise Exception('Unknown method:%s', method) raise Exception('Unknown method:%s', method)
#Call: #Call:
func = getattr(sclient, method) func = getattr(sclient, method)
result = func(*params) return func(*params)
return { #
"version":"1.1", #Extra exposed methods:
"result":result, #
"id":id def system_listMethods(self):
} "system.list_methods() see json/xmlrpc docs"
return sclient.list_methods() + self.json_exposed
def exec_system_method(self, method, params, id): def get_stats(self):
if method == "system.listMethods":
methods = sclient.list_methods()
return {
"version":"1.1",
"result":methods + ["get_stats"],
"id":id
}
raise Exception('Unknown method:%s', method)
def exec_get_stats(self, method, params, id):
stats = {} stats = {}
aclient.get_download_rate(dict_cb('download_rate',stats)) aclient.get_download_rate(dict_cb('download_rate',stats))
@ -157,81 +154,45 @@ class json_rpc:
aclient.force_call(block=True) aclient.force_call(block=True)
return { return stats
"version":"1.1",
"result":stats,
"id":id
}
def update_ui(self, keys ,filter_dict , cache_id = None ):
def list_torrents(self,params,id):
""" """
== torrent_list ==
Composite call. Composite call.
Goal : limit the number of ajax calls Goal : limit the number of ajax calls
filter is only effective if the label plugin is enabled.
filter is only effective if the organize plugin is enabled.
label is redirected to the tracker column, there will be a label feature in the future.
cache_id = future feature, not effective yet. cache_id = future feature, not effective yet.
=== input === === input ===
{{{ {{{
{ keys: see get_torrent_status
keys: [<like get_torrent_status>], filter_dict: see label_get_filtered_ids
filter: { cache_id: # todo
/*ommitted keys are ignored*/
"keyword":string
"label":string,
"state":string
} ,
cache_id: int
} }
}}} }}}
=== output === === output ===
{{{ {{{
{ {
torrents: "torrents": see get_torrent_status
[ {"id":string,"name":string, ..}, ..] "filters": see label_get_filters
states: "stats": see get_stats
[('string',int), ..] "cache_id":int # todo
trackers:
[('string',int), ..]
stats:
[upload_rate, download_rate, nu_connections, num_dht_nodes]
}
cache_id:int
} }
}}} }}}
""" """
"""filter = params["filter"] if 'Label' in sclient.get_enabled_plugins():
keys = params["keys"]
cache_id = params["cache_id"]
organize_filters = {}
if 'Organize' in proxy.get_enabled_plugins():
filter_dict = {} filter_dict = {}
torrent_ids = sclient.label_get_filtered_ids(filter_dict)
for filter_name in ["state","tracker","keyword"]: filters = sclient.label_filter_items()
value = get(filter,filter_name)
if value and value <> "All":
filter_dict[filter_name] = value
torrent_ids = proxy.organize_get_session_state(filter_dict)
organize_filters = Storage(proxy.organize_all_filter_items())
else: else:
torrent_ids = proxy.get_session_state() torrent_ids = proxy.get_session_state()
organize_filters = {"state":[["All",-1]],"tracker":[]} organize_filters = {"state":[["All",-1]],"tracker":[]}
result = { return {
"torrents":sclient.get_torrents_status(torrent_ids, keys), "torrents":sclient.get_torrents_status(torrent_ids, keys),
"state":organize_filters["state"], "filters":filters,
"tracker":organize_filters["tracker"], "stats":self.get_stats(),
"stats":[0, 1, 2, 3], #todo "cache_id":-1
"cache_id":cache_id
} }
"""

View File

@ -407,6 +407,8 @@ route("/template_style.css", template_style)
class pixmaps: class pixmaps:
"use the deluge-images. located in data/pixmaps" "use the deluge-images. located in data/pixmaps"
def GET(self, name): def GET(self, name):
if name.startswith("flags") and not name.endswith('.png'):
name = name + ".png"
if not name.endswith('.png'): if not name.endswith('.png'):
if name == 'paused': if name == 'paused':
name = 'inactive' name = 'inactive'

View File

@ -64,7 +64,7 @@ function update_torrent(torrent) {
function get_stats() { function get_stats() {
service.get_stats({params:[], service.get_stats({params:[],
onSuccess:function(stats){ onSuccess:function(stats){
alert(stats.download_rate); alert(service.__toJSON(stats));
}, },
onException:function(errorObj){ onException:function(errorObj){
alert("Error: " + errorObj); alert("Error: " + errorObj);
@ -74,19 +74,32 @@ function get_stats() {
function update_ui() {
service.update_ui({params:[ ["name","state","label","tracker_host"],{"state":"Seeding"} ],
onSuccess:function(data){
alert(service.__toJSON(data));
},
onException:function(errorObj){
alert("Error: " + errorObj);
}
});
};
</script> </script>
<h1>sclient:</h1>
<button onclick="get_session_state()">get_session_state()</button> <button onclick="get_session_state()">get_session_state()</button>
<button onclick="list_torrents()">List torrents</button> <button onclick="list_torrents()">List torrents using get_session_state() + get_torrents_status()</button> <br>
<h1>json extra:</h1>
<button onclick="get_stats()">get_stats()</button> <button onclick="get_stats()">get_stats()</button>
<button onclick="update_ui()">update_ui() filter on "Seeding"</button>
<div id="torrent_list"> <div id="torrent_list">
</div> </div>

View File

@ -5,20 +5,21 @@ $def with (torrent)
$altrow(True) $altrow(True)
<tr class="head"> <tr class="head">
<th>$_("Ip")</th> <th>&nbsp; <!--country-flag--></th>
<th>$_("Up Speed")</th> <th>$_("Address")</th>
<th>$_("Down Speed")</th> <th>$_("Down Speed")</th>
<th>$_("Country")</th> <th>$_("Up Speed")</th>
<th>$_("Client")</th> <th>$_("Client")</th>
<th>$_("Progress")</th> <!--<th>$_("Progress")</th>-->
</tr> </tr>
$for peer in torrent.peers: $for peer in torrent.peers:
<tr class="tab_$altrow()" > <tr class="tab_$altrow()" >
<td><img src="$base/pixmaps/flags/$(peer['country'].lower())" /></td>
<td>$peer['ip']</td> <td>$peer['ip']</td>
<td>$fspeed(peer['up_speed'])</td>
<td>$fspeed(peer['down_speed'])</td> <td>$fspeed(peer['down_speed'])</td>
<td>$peer['country']</td> <td>$fspeed(peer['up_speed'])</td>
<td>$peer['client']</td> <td>$peer['client']</td>
<!--not in gtk-ui anymore, broken?
<td class="progress_bar"> <td class="progress_bar">
$if peer.get('progress'): $if peer.get('progress'):
<div class="progress_bar_outer"> <div class="progress_bar_outer">
@ -31,6 +32,7 @@ $for peer in torrent.peers:
? % ? %
</div> </div>
</td> </td>
-->
</tr> </tr>
</table> </table>
</form> </form>