switch over to using twisted-web

This commit is contained in:
Damien Churchill 2009-02-08 16:56:56 +00:00
commit e96b4c4f58
5 changed files with 118 additions and 98 deletions

View file

@ -7,11 +7,14 @@ html, body {
height:100%; height:100%;
} }
.deluge-torrents td {
height: 16px;
line-height: 16px;
}
.deluge-torrents .torrent-name { .deluge-torrents .torrent-name {
padding-left: 20px; padding-left: 20px;
background-repeat: no-repeat; background-repeat: no-repeat;
height: 16px;
line-height: 16px;
} }
.deluge-torrents .deluge-torrent-progress { .deluge-torrents .deluge-torrent-progress {
@ -64,3 +67,4 @@ html, body {
.deluge-status dd.torrent_name, .deluge-status dd.tracker, .deluge-status dd.path { .deluge-status dd.torrent_name, .deluge-status dd.tracker, .deluge-status dd.path {
width: 500px; width: 500px;
}

View file

@ -3,55 +3,55 @@ Deluge.ToolBar = new Ext.Toolbar({
{ {
id: 'create', id: 'create',
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
text: 'Create', text: _('Create'),
icon: '/icons/16/create.png', icon: '/icons/16/create.png',
handler: torrentAction handler: torrentAction
},{ },{
id: 'add', id: 'add',
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
text: 'Add', text: _('Add'),
icon: '/icons/16/add.png', icon: '/icons/16/add.png',
handler: torrentAction handler: torrentAction
},{ },{
id: 'remove', id: 'remove',
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
text: 'Remove', text: _('Remove'),
icon: '/icons/16/remove.png', icon: '/icons/16/remove.png',
handler: torrentAction handler: torrentAction
},{ },{
id: 'pause', id: 'pause',
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
text: 'Pause', text: _('Pause'),
icon: '/icons/16/pause.png', icon: '/icons/16/pause.png',
handler: torrentAction handler: torrentAction
},{ },{
id: 'resume', id: 'resume',
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
text: 'Resume', text: _('Resume'),
icon: '/icons/16/start.png', icon: '/icons/16/start.png',
handler: torrentAction handler: torrentAction
},{ },{
id: 'up', id: 'up',
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
text: 'Up', text: _('Up'),
icon: '/icons/16/up.png', icon: '/icons/16/up.png',
handler: torrentAction handler: torrentAction
},{ },{
id: 'down', id: 'down',
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
text: 'Down', text: _('Down'),
icon: '/icons/16/down.png', icon: '/icons/16/down.png',
handler: torrentAction handler: torrentAction
},{ },{
id: 'preferences', id: 'preferences',
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
text: 'Preferences', text: _('Preferences'),
icon: '/icons/16/preferences.png', icon: '/icons/16/preferences.png',
handler: torrentAction handler: torrentAction
},{ },{
id: 'connectionman', id: 'connectionman',
cls: 'x-btn-text-icon', cls: 'x-btn-text-icon',
text: 'Connection Manager', text: _('Connection Manager'),
icon: '/icons/16/connection_manager.png', icon: '/icons/16/connection_manager.png',
handler: torrentAction handler: torrentAction
} }
@ -105,10 +105,11 @@ function torrentAction(item) {
} }
Deluge.SideBar = { Deluge.SideBar = {
region:'west', region: 'west',
id:'west-panel', id: 'sidebar',
title:'Sidebar', cls: 'deluge-sidebar',
split:true, title: _('Sidebar'),
split: true,
width: 200, width: 200,
minSize: 175, minSize: 175,
collapsible: true, collapsible: true,

View file

@ -37,3 +37,7 @@ Deluge.Details.Status.add({
cls: 'deluge-status', cls: 'deluge-status',
border: false border: false
}); });
Deluge.Details.update = function(torrentId) {
Deluge.Details.getActiveTab().update(torrent);
}

View file

@ -13,6 +13,12 @@ Deluge.Ui = {
bbar: Deluge.StatusBar bbar: Deluge.StatusBar
}); });
Deluge.SideBar = this.MainPanel.items.get('sidebar');
Deluge.SideBar.on('collapse', function(bar) {
//alert(JSON.encode($('sidebar').getSize()));
});
this.Viewport = new Ext.Viewport({ this.Viewport = new Ext.Viewport({
layout: 'fit', layout: 'fit',
items: [this.MainPanel] items: [this.MainPanel]

View file

@ -37,10 +37,9 @@ if sys.version_info > (2, 6):
else: else:
import simplejson as json import simplejson as json
from twisted.application import service, internet
from twisted.internet.defer import Deferred from twisted.internet.defer import Deferred
from twisted.application import service, strports from twisted.web import http, resource, server, static
from twisted.web2 import static, wsgi, resource, responsecode
from twisted.web2 import stream, http, http_headers, server, channel
from mako.template import Template as MakoTemplate from mako.template import Template as MakoTemplate
@ -60,14 +59,14 @@ class Template(MakoTemplate):
class JSONException(Exception): pass class JSONException(Exception): pass
class JSON(resource.PostableResource): class JSON(resource.Resource):
""" """
A Twisted Web2 resource that exposes a JSON-RPC interface for web clients A Twisted Web resource that exposes a JSON-RPC interface for web clients
to use. to use.
""" """
def __init__(self): def __init__(self):
resource.PostableResource.__init__(self) resource.Resource.__init__(self)
self._remote_methods = [] self._remote_methods = []
self._local_methods = { self._local_methods = {
"web.update_ui": self.update_ui, "web.update_ui": self.update_ui,
@ -76,12 +75,16 @@ class JSON(resource.PostableResource):
"web.add_torrents": self.add_torrents "web.add_torrents": self.add_torrents
} }
for entry in open(common.get_default_config_dir("auth")): for entry in open(common.get_default_config_dir("auth")):
username, password = entry.split(":") parts = entry.split(":")
if len(parts) > 1:
username, password = parts[0], parts[1]
else:
continue
if username != "localclient": if username != "localclient":
continue continue
self.local_username = username self.local_username = username
self.local_password = password self.local_password = password
print username, password
self.connect() self.connect()
def connect(self, host="localhost", username=None, password=None): def connect(self, host="localhost", username=None, password=None):
@ -159,21 +162,22 @@ class JSON(resource.PostableResource):
except Exception, e: except Exception, e:
raise JSONException(str(e)) raise JSONException(str(e))
def _on_rpc_request_finished(self, result, response): def _on_rpc_request_finished(self, result, response, request):
""" """
Sends the response of any rpc calls back to the json-rpc client. Sends the response of any rpc calls back to the json-rpc client.
""" """
response["result"] = result response["result"] = result
return self._send_response(response) return self._send_response(request, response)
def _on_rpc_request_failed(self, reason, response): def _on_rpc_request_failed(self, reason, response, request):
""" """
Handles any failures that occured while making an rpc call. Handles any failures that occured while making an rpc call.
""" """
print reason print reason
return http.Response(responsecode.INTERNAL_SERVER_ERROR) request.setResponseCode(http.INTERNAL_SERVER_ERROR)
return ""
def _on_json_request(self, result, request): def _on_json_request(self, request):
""" """
Handler to take the json data as a string and pass it on to the Handler to take the json data as a string and pass it on to the
_handle_request method for further processing. _handle_request method for further processing.
@ -181,8 +185,8 @@ class JSON(resource.PostableResource):
log.debug("json-request: %s", request.json) log.debug("json-request: %s", request.json)
response = {"result": None, "error": None, "id": None} response = {"result": None, "error": None, "id": None}
d, response["id"] = self._handle_request(request.json) d, response["id"] = self._handle_request(request.json)
d.addCallback(self._on_rpc_request_finished, response) d.addCallback(self._on_rpc_request_finished, response, request)
d.addErrback(self._on_rpc_request_failed, response) d.addErrback(self._on_rpc_request_failed, response, request)
return d return d
def _on_json_request_failed(self, reason, request): def _on_json_request_failed(self, reason, request):
@ -190,38 +194,31 @@ class JSON(resource.PostableResource):
Errback handler to return a HTTP code of 500. Errback handler to return a HTTP code of 500.
""" """
print reason print reason
return http.Response(responsecode.INTERNAL_SERVER_ERROR) request.setResponseCode(http.INTERNAL_SERVER_ERROR)
return ""
def _send_response(self, response): def _send_response(self, request, response):
response = json.dumps(response) response = json.dumps(response)
return http.Response(responsecode.OK, request.setHeader("content-type", "application/x-json")
{"content-type": http_headers.MimeType("application", "x-json")}, request.write(response)
stream=response) request.finish()
def http_POST(self, request):
"""
Handles all the POST requests made to the /json controller.
"""
request.json = ""
def handle_data(data):
request.json += data
d = stream.readStream(request.stream, handle_data)
d.addCallbacks(
self._on_json_request,
self._on_json_request_failed,
callbackArgs=(request,),
errbackArgs=(request,)
)
d.addErrback(self._on_json_request_failed, request)
return d
def render(self, request): def render(self, request):
""" """
Block all other HTTP methods. Handles all the POST requests made to the /json controller.
""" """
return http.Response(responsecode.NOT_ALLOWED)
if request.method != "POST":
request.setResponseCode(http.NOT_ALLOWED)
return ""
try:
request.content.seek(0)
request.json = request.content.read()
d = self._on_json_request(request)
return server.NOT_DONE_YET
except Exception, e:
return self._on_json_request_failed(e, request)
def update_ui(self, keys, filter_dict, cache_id=None): def update_ui(self, keys, filter_dict, cache_id=None):
@ -302,16 +299,14 @@ class JSON(resource.PostableResource):
class GetText(resource.Resource): class GetText(resource.Resource):
headers = {
"content-type": http_headers.MimeType("text", "javascript")
}
def render(self, request): def render(self, request):
request.setHeader("content-type", "text/javascript")
template = Template(filename="gettext.js") template = Template(filename="gettext.js")
return http.Response(responsecode.OK, self.headers, template.render()) return template.render()
class Upload(resource.PostableResource): class Upload(resource.Resource):
""" """
Twisted Web2 resource to handle file uploads Twisted Web resource to handle file uploads
""" """
def http_POST(self, request): def http_POST(self, request):
@ -330,72 +325,81 @@ class Upload(resource.PostableResource):
f = open(fn, upload[2].mode) f = open(fn, upload[2].mode)
shutil.copyfileobj(upload[2], f) shutil.copyfileobj(upload[2], f)
filenames.append(fn) filenames.append(fn)
return http.Response(responsecode.OK, stream="\n".join(filenames)) return http.Response(http.OK, stream="\n".join(filenames))
def render(self, request): def render(self, request):
""" """
Block all other HTTP methods. Block all other HTTP methods.
""" """
return http.Response(responsecode.NOT_ALLOWED) return http.Response(http.NOT_ALLOWED)
class Render(resource.Resource): class Render(resource.Resource):
headers = { def getChild(self, path, request):
"Content-type": http_headers.MimeType("text", "html") request.render_file = path
} return self
def locateChild(self, request, segments):
request.render_file = segments[0]
return self, ()
def render(self, request): def render(self, request):
if not hasattr(request, "render_file"): if not hasattr(request, "render_file"):
return http.Response(responsecode.INTERNAL_SERVER_ERROR) request.setResponseCode(http.INTERNAL_SERVER_ERROR)
return ""
filename = os.path.join("render", request.render_file) filename = os.path.join("render", request.render_file)
template = Template(filename=filename) template = Template(filename=filename)
return http.Response(responsecode.OK, self.headers, template.render()) request.setHeader("content-type", "text/html")
request.setResponseCode(http.OK)
return template.render()
class Tracker(resource.Resource): class Tracker(resource.Resource):
tracker_icons = TrackerIcons() tracker_icons = TrackerIcons()
def locateChild(self, request, segments): def getChild(self, path, request):
request.tracker_name = "/".join(segments) request.tracker_name = path
return self, () return self
def render(self, request): def render(self, request):
headers = {} headers = {}
filename = self.tracker_icons.get(request.tracker_name) filename = self.tracker_icons.get(request.tracker_name)
if filename: if filename:
http_headers.He request.setHeader("cache-control", "public, must-revalidate, max-age=86400")
#headers["cache-control"] = "public, must-revalidate, max-age=86400"
if filename.endswith(".ico"): if filename.endswith(".ico"):
headers["content-type"] = http_headers.MimeType("image", "x-icon") request.setHeader("content-type", "image/x-icon")
elif filename.endwith(".png"): elif filename.endwith(".png"):
headers["content-type"] = http_headers.MimeType("image", "png") request.setHeader("content-type", "image/png")
data = open(filename, "rb") data = open(filename, "rb")
return http.Response(responsecode.OK, headers, data.read()) request.setResponseCode(http.OK)
return data.read()
else: else:
return http.Response(responsecode.NOT_FOUND) request.setResponseCode(http.NOT_FOUND)
return ""
class TopLevel(resource.Resource): class TopLevel(resource.Resource):
addSlash = True addSlash = True
child_json = JSON()
child_upload = Upload() def __init__(self):
child_test = static.File("test.html") resource.Resource.__init__(self)
child_js = static.File("js") self.putChild("css", static.File("css"))
child_images = static.File("images") self.putChild("gettext.js", GetText())
child_icons = static.File("icons") self.putChild("icons", static.File("icons"))
child_css = static.File("css") self.putChild("images", static.File("images"))
child_themes = static.File("themes") self.putChild("js", static.File("js"))
child_gettext = GetText() self.putChild("json", JSON())
child_render = Render() self.putChild("upload", Upload())
child_tracker = Tracker() self.putChild("render", Render())
self.putChild("test", static.File("test.html"))
self.putChild("themes", static.File("themes"))
self.putChild("tracker", Tracker())
def getChild(self, path, request):
if path == "":
return self
else:
return resource.Resource.getChild(self, path, request)
def render(self, request): def render(self, request):
template = Template(filename="index.html") template = Template(filename="index.html")
return http.Response(responsecode.OK, stream=template.render()) request.setHeader("content-type", "text/html; charset=utf-8")
return template.render()
setupLogger(level="debug") setupLogger(level="debug")
@ -414,5 +418,6 @@ except Exception, e:
site = server.Site(TopLevel()) site = server.Site(TopLevel())
application = service.Application("DelugeWeb") application = service.Application("DelugeWeb")
s = strports.service("tcp:8112", channel.HTTPFactory(site)) sc = service.IServiceCollection(application)
s.setServiceParent(application) i = internet.TCPServer(8112, site)
i.setServiceParent(sc)