diff --git a/deluge/ui/web/auth.py b/deluge/ui/web/auth.py index 5cd345e2c..0675d9d9d 100644 --- a/deluge/ui/web/auth.py +++ b/deluge/ui/web/auth.py @@ -136,7 +136,7 @@ class Auth(JSONComponent): checksum = str(make_checksum(session_id)) request.addCookie('_session_id', session_id + checksum, - path=request.base+"json", expires=expires_str) + path=request.base, expires=expires_str) log.debug("Creating session for %s", login) config = component.get("DelugeWeb").config @@ -233,7 +233,7 @@ class Auth(JSONComponent): _session_id = request.getCookie("_session_id") request.addCookie('_session_id', _session_id, - path=request.base+"json", expires=expires_str) + path=request.base, expires=expires_str) if method: if not hasattr(method, "_json_export"): diff --git a/deluge/ui/web/js/deluge-all/data/PeerRecord.js b/deluge/ui/web/js/deluge-all/data/PeerRecord.js index 4d2312c24..f5bf6b3de 100644 --- a/deluge/ui/web/js/deluge-all/data/PeerRecord.js +++ b/deluge/ui/web/js/deluge-all/data/PeerRecord.js @@ -1,5 +1,5 @@ /*! - * Deluge.data.PeerRecord.js + * Deluge.data.Peer.js * * Copyright (c) Damien Churchill 2009-2011 * diff --git a/deluge/ui/web/js/deluge-all/details/PeersTab.js b/deluge/ui/web/js/deluge-all/details/PeersTab.js index d0980dd40..4c1f24393 100644 --- a/deluge/ui/web/js/deluge-all/details/PeersTab.js +++ b/deluge/ui/web/js/deluge-all/details/PeersTab.js @@ -30,131 +30,93 @@ * statement from all source files in the program, then also delete it here. */ -(function() { - function flagRenderer(value) { - if (!value.replace(' ', '').replace(' ', '')){ - return ''; +Ext.define('Deluge.details.PeersTab', { + extend: 'Ext.grid.Panel', + title: _('Peers'), + cls: 'x-deluge-peers', + viewConfig: { + loadMask: false, + }, + invalidateScrollerOnRefresh: false, + + store: { + model: 'Deluge.data.Peer', + proxy: { + type: 'ajax', + url: 'peers/', + reader: { + type: 'json', + root: 'peers' + } } - return String.format('', value); - } - function peerAddressRenderer(value, p, record) { - var seed = (record.data['seed'] == 1024) ? 'x-deluge-seed' : 'x-deluge-peer'; - if (peer_ip.length > 2) { - var port = peer_ip.pop(); - var ip = peer_ip.join(":"); - value = "[" + ip + "]:" + port; + }, + + columns: [{ + text: ' ', + dataIndex: 'country', + width: 30, + sortable: true, + renderer: function(v) { + if (!v.replace(' ', '').replace(' ', '')) { + return ''; + } + return Ext.String.format('', v); } - return String.format('
{1}
', seed, value); - } - function peerProgressRenderer(value) { - var progress = (value * 100).toFixed(0); - return Deluge.progressBar(progress, this.width - 8, progress + '%'); - } - - Ext.define('Deluge.details.PeersTab', { - extend: 'Ext.grid.Panel', - title: _('Peers'), - cls: 'x-deluge-peers', - - store: Ext.create('Ext.data.Store', { - model: 'Deluge.data.Peer' - }), - - columns: [{ - header: ' ', - width: 30, - sortable: true, - renderer: flagRenderer, - dataIndex: 'country' - }, { - header: 'Address', - width: 125, - sortable: true, - renderer: peerAddressRenderer, - dataIndex: 'ip' - }, { - header: 'Client', - width: 125, - sortable: true, - renderer: function(v) { return fplain(v) }, - dataIndex: 'client' - }, { - header: 'Progress', - width: 150, - sortable: true, - renderer: peerProgressRenderer, - dataIndex: 'progress' - }, { - header: 'Down Speed', - width: 100, - sortable: true, - renderer: function(v) { return fspeed(v) }, - dataIndex: 'down_speed' - }, { - header: 'Up Speed', - width: 100, - sortable: true, - renderer: function(v) { return fspeed(v) }, - dataIndex: 'up_speed' - }], - - stripeRows: true, - deferredRender: false, - autoScroll: true, - - // fast way to figure out if we have a peer already. - peers: {}, - - clear: function() { - this.getStore().removeAll(); - this.peers = {}; - }, - - update: function(torrentId) { - deluge.client.web.get_torrent_status(torrentId, Deluge.Keys.Peers, { - success: this.onRequestComplete, - scope: this - }); - }, - - onRequestComplete: function(torrent, options) { - if (!torrent) return; - - var store = this.getStore(); - var newPeers = []; - var addresses = {}; - - // Go through the peers updating and creating peer records - Ext.each(torrent.peers, function(peer) { - if (this.peers[peer.ip]) { - var record = store.getById(peer.ip); - record.beginEdit(); - for (var k in peer) { - if (record.get(k) != peer[k]) { - record.set(k, peer[k]); - } - } - record.endEdit(); - } else { - this.peers[peer.ip] = 1; - newPeers.push(new Deluge.data.Peer(peer, peer.ip)); - } - addresses[peer.ip] = 1; - }, this); - store.add(newPeers); - - // Remove any peers that shouldn't be left in the store - store.each(function(record) { - if (!addresses[record.id]) { - store.remove(record); - delete this.peers[record.id]; - } - }, this); - store.commitChanges(); - - var sortState = store.getSortState(); - if (!sortState) return; - store.sort(sortState.field, sortState.direction); + }, { + text: 'Address', + dataIndex: 'ip', + width: 125, + sortable: true, + renderer: function(v, p, r) { + var cls = (r.data['seed'] == 1024) ? 'x-deluge-seed': 'x-deluge-peer'; + return Ext.String.format('
{1}
', cls, v); } - }); -})(); + }, { + text: 'Client', + dataIndex: 'client', + width: 125, + sortable: true, + renderer: function(v) { return fplain(v) } + }, { + text: 'Progress', + dataIndex: 'progress', + width: 150, + sortable: true, + renderer: function(v) { + var progress = (v * 100).toFixed(0); + return Deluge.progressBar(progress, this.width - 8, progress + '%'); + } + }, { + text: 'Down Speed', + dataIndex: 'down_speed', + width: 100, + sortable: true, + renderer: function(v) { return fspeed(v) } + }, { + text: 'Up Speed', + dataIndex: 'up_speed', + width: 100, + sortable: true, + renderer: function(v) { return fspeed(v) } + }], + + autoScroll: true, + deferredRender: false, + stripeRows: true, + + clear: function() { + this.getStore().removeAll(); + }, + + update: function(torrentId) { + var store = this.getStore(), + view = this.getView(); + + if (torrentId != this.torrentId) { + store.removeAll(); + store.getProxy().url = 'peers/' + torrentId; + this.torrentId = torrentId; + } + store.load(); + } +}); diff --git a/deluge/ui/web/server.py b/deluge/ui/web/server.py index c9bc2a786..b775d9860 100644 --- a/deluge/ui/web/server.py +++ b/deluge/ui/web/server.py @@ -34,6 +34,7 @@ # import os +import json import time import shutil import urllib @@ -52,7 +53,7 @@ from deluge import common, component, configmanager from deluge.core.rpcserver import check_ssl_keys from deluge.ui import common as uicommon from deluge.ui.tracker_icons import TrackerIcons -from deluge.ui.web.auth import Auth +from deluge.ui.web.auth import Auth, AuthError, AUTH_LEVEL_DEFAULT from deluge.ui.web.common import Template, compress from deluge.ui.web.json_api import JSON, WebApi from deluge.ui.web.pluginmanager import PluginManager @@ -86,6 +87,8 @@ CONFIG_DEFAULTS = { "cert": "ssl/daemon.cert" } +PEERS_KEYS = ["peers"] + UI_CONFIG_KEYS = ( "theme", "sidebar_show_zero", "sidebar_multiple_filters", "show_session_speed", "base", "first_login" @@ -198,6 +201,46 @@ class Tracker(resource.Resource): d.addCallback(self.on_got_icon, request) return server.NOT_DONE_YET +class TorrentResource(resource.Resource): + """ + Base class for exposing parts of a torrent's information + as a REST-ish interface. + """ + + def getChild(self, path, request): + request.torrent_id = path + return self + + def send_response(self, response, request): + request.setHeader("content-type", "text/plain") + request.write(compress(json.dumps(response), request)) + request.finish() + +class Peers(TorrentResource): + """ + Returns a list of the peers that a torrent currently has in JSON format. + """ + + def on_got_peers(self, torrent, request): + peers = torrent["peers"] + self.send_response({ + "peers": peers, + "total": len(peers) + }, request) + + def render(self, request): + try: + component.get("Auth").check_request(request, + level=AUTH_LEVEL_DEFAULT) + except AuthError: + request.setResponseCode(http.FORBIDDEN) + return '

Forbidden

' + + component.get("SessionProxy" + ).get_torrent_status(request.torrent_id, PEERS_KEYS + ).addCallback(self.on_got_peers, request) + return server.NOT_DONE_YET + class Flag(resource.Resource): def getChild(self, path, request): request.country = path @@ -466,6 +509,9 @@ class TopLevel(resource.Resource): self.putChild("resources", static.File(rpath("resources"))) self.putChild("tracker", Tracker()) + # Torrent REST resources + self.putChild("peers", Peers()) + theme = component.get("DelugeWeb").config["theme"] if not os.path.isfile(rpath("themes", "css", "xtheme-%s.css" % theme)): theme = CONFIG_DEFAULTS.get("theme")