mirror of
https://github.com/codex-storage/deluge.git
synced 2025-02-28 19:10:35 +00:00
revert last webui
This commit is contained in:
parent
3211dc9019
commit
b2ae9f1db1
@ -36,13 +36,12 @@ plugin_description = "A Web based User Interface\n"
|
|||||||
import deluge.common
|
import deluge.common
|
||||||
import deluge.pref
|
import deluge.pref
|
||||||
from deluge.dialogs import show_popup_warning
|
from deluge.dialogs import show_popup_warning
|
||||||
from dbus_interface import get_dbus_manager
|
from dbus_interface import DbusManager
|
||||||
|
|
||||||
import gtk
|
import gtk
|
||||||
import os
|
import os
|
||||||
from subprocess import Popen
|
from subprocess import Popen
|
||||||
from md5 import md5
|
from md5 import md5
|
||||||
from threading import Thread
|
|
||||||
import random
|
import random
|
||||||
random.seed()
|
random.seed()
|
||||||
|
|
||||||
@ -50,6 +49,10 @@ plugin_version += open(os.path.join(os.path.dirname(__file__),'revno')).read()
|
|||||||
plugin_description += (
|
plugin_description += (
|
||||||
open(os.path.join(os.path.dirname(__file__),'version')).read())
|
open(os.path.join(os.path.dirname(__file__),'version')).read())
|
||||||
|
|
||||||
|
#not found a way to stop a dbus manager.
|
||||||
|
#global so it does not get started twice.
|
||||||
|
dbus_manager = None
|
||||||
|
|
||||||
def deluge_init(deluge_path):
|
def deluge_init(deluge_path):
|
||||||
global path
|
global path
|
||||||
path = deluge_path
|
path = deluge_path
|
||||||
@ -58,27 +61,15 @@ def enable(core, interface):
|
|||||||
global path
|
global path
|
||||||
return plugin_WebUi(path, core, interface)
|
return plugin_WebUi(path, core, interface)
|
||||||
|
|
||||||
class WebServerThread(Thread):
|
class plugin_WebUi:
|
||||||
|
|
||||||
def run(self):
|
|
||||||
#must be imported after plugin-load because of dbus:
|
|
||||||
import webserver_common
|
|
||||||
reload(webserver_common) #HACK!!!
|
|
||||||
from deluge_webserver import WebServer #only import in threaded mode
|
|
||||||
self.web_server = WebServer()
|
|
||||||
self.web_server.start()
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
print 'WebUi : Stop threaded server'
|
|
||||||
self.web_server.stop()
|
|
||||||
|
|
||||||
class plugin_WebUi(object):
|
|
||||||
def __init__(self, path, deluge_core, deluge_interface):
|
def __init__(self, path, deluge_core, deluge_interface):
|
||||||
|
global dbus_manager
|
||||||
self.path = path
|
self.path = path
|
||||||
self.core = deluge_core
|
self.core = deluge_core
|
||||||
self.interface = deluge_interface
|
self.interface = deluge_interface
|
||||||
self.proc = None
|
self.proc = None
|
||||||
self.web_server_thread = None
|
|
||||||
|
|
||||||
|
|
||||||
self.config_file = deluge.common.CONFIG_DIR + "/webui.conf"
|
self.config_file = deluge.common.CONFIG_DIR + "/webui.conf"
|
||||||
self.config = deluge.pref.Preferences(self.config_file, False)
|
self.config = deluge.pref.Preferences(self.config_file, False)
|
||||||
@ -107,17 +98,19 @@ class plugin_WebUi(object):
|
|||||||
if self.config.get("cache_templates") == None:
|
if self.config.get("cache_templates") == None:
|
||||||
self.config.set("cache_templates", True)
|
self.config.set("cache_templates", True)
|
||||||
|
|
||||||
if self.config.get("run_in_thread") == None:
|
|
||||||
self.config.set("run_in_thread", True)
|
|
||||||
|
|
||||||
self.dbus_manager = get_dbus_manager(deluge_core, deluge_interface,
|
if not dbus_manager:
|
||||||
self.config, self.config_file)
|
self.dbusManager = DbusManager(deluge_core, deluge_interface
|
||||||
|
, self.config, self.config_file)
|
||||||
|
|
||||||
|
self.dbus_manager = dbus_manager
|
||||||
|
|
||||||
self.start_server()
|
self.start_server()
|
||||||
|
|
||||||
def unload(self):
|
def unload(self):
|
||||||
print 'WebUI:unload..'
|
print 'WebUI:unload..'
|
||||||
self.kill_server()
|
self.kill_server()
|
||||||
|
#self.dbusManager.
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
pass
|
pass
|
||||||
@ -131,30 +124,18 @@ class plugin_WebUi(object):
|
|||||||
|
|
||||||
def start_server(self):
|
def start_server(self):
|
||||||
self.kill_server()
|
self.kill_server()
|
||||||
|
print 'start Webui..'
|
||||||
if self.config.get("run_in_thread"):
|
path = os.path.dirname(__file__)
|
||||||
print 'start Webui(in thread)..'
|
server_bin = path + '/run_webserver'
|
||||||
self.web_server_thread = WebServerThread()
|
port = str(self.config.get('port'))
|
||||||
self.web_server_thread.start()
|
self.proc = Popen((server_bin, port),cwd=path)
|
||||||
else:
|
|
||||||
print 'start Webui(in process)..'
|
|
||||||
path = os.path.dirname(__file__)
|
|
||||||
server_bin = path + '/run_webserver'
|
|
||||||
port = str(self.config.get('port'))
|
|
||||||
self.proc = Popen((server_bin, port),cwd=path)
|
|
||||||
|
|
||||||
def kill_server(self):
|
def kill_server(self):
|
||||||
if self.web_server_thread:
|
|
||||||
self.web_server_thread.stop()
|
|
||||||
if self.proc:
|
if self.proc:
|
||||||
print "webserver: kill %i" % self.proc.pid
|
print "webserver: kill %i"%self.proc.pid
|
||||||
os.system("kill %i" % self.proc.pid)
|
os.system("kill %i"%self.proc.pid)
|
||||||
self.proc = None
|
self.proc = None
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
self.kill_server()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigDialog(gtk.Dialog):
|
class ConfigDialog(gtk.Dialog):
|
||||||
"""
|
"""
|
||||||
@ -179,15 +160,12 @@ class ConfigDialog(gtk.Dialog):
|
|||||||
self.template = self.add_widget(_('Template'), gtk.combo_box_new_text())
|
self.template = self.add_widget(_('Template'), gtk.combo_box_new_text())
|
||||||
self.button_style = self.add_widget(_('Button Style'),
|
self.button_style = self.add_widget(_('Button Style'),
|
||||||
gtk.combo_box_new_text())
|
gtk.combo_box_new_text())
|
||||||
|
self.cache_templates = self.add_widget(_('Cache Templates'),
|
||||||
|
gtk.CheckButton())
|
||||||
self.download_dir = self.add_widget(_('Download Directory'),
|
self.download_dir = self.add_widget(_('Download Directory'),
|
||||||
gtk.FileChooserButton(_('Download Directory')))
|
gtk.FileChooserButton(_('Download Directory')))
|
||||||
self.torrent_dir = self.add_widget(_('Torrent Directory'),
|
self.torrent_dir = self.add_widget(_('Torrent Directory'),
|
||||||
gtk.FileChooserButton(_('Torrent Directory')))
|
gtk.FileChooserButton(_('Torrent Directory')))
|
||||||
self.cache_templates = self.add_widget(_('Cache Templates'),
|
|
||||||
gtk.CheckButton())
|
|
||||||
self.run_in_thread = self.add_widget(_('Run in thread'),
|
|
||||||
gtk.CheckButton())
|
|
||||||
|
|
||||||
|
|
||||||
self.download_dir.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
self.download_dir.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
||||||
self.torrent_dir.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
self.torrent_dir.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
||||||
@ -211,13 +189,10 @@ class ConfigDialog(gtk.Dialog):
|
|||||||
self.template.set_active(
|
self.template.set_active(
|
||||||
self.templates.index(self.config.get("template")))
|
self.templates.index(self.config.get("template")))
|
||||||
self.button_style.set_active(self.config.get("button_style"))
|
self.button_style.set_active(self.config.get("button_style"))
|
||||||
|
self.cache_templates.set_active(self.config.get("cache_templates"))
|
||||||
|
|
||||||
self.torrent_dir.set_filename(self.config.get("torrent_dir"))
|
self.torrent_dir.set_filename(self.config.get("torrent_dir"))
|
||||||
self.download_dir.set_filename(self.config.get("download_dir"))
|
self.download_dir.set_filename(self.config.get("download_dir"))
|
||||||
|
|
||||||
self.run_in_thread.set_active(self.config.get("run_in_thread"))
|
|
||||||
self.cache_templates.set_active(self.config.get("cache_templates"))
|
|
||||||
|
|
||||||
self.vbox.pack_start(self.vb, True, True, 0)
|
self.vbox.pack_start(self.vb, True, True, 0)
|
||||||
self.vb.show_all()
|
self.vb.show_all()
|
||||||
|
|
||||||
@ -251,9 +226,17 @@ class ConfigDialog(gtk.Dialog):
|
|||||||
self.config.set("port", int(self.port.get_value()))
|
self.config.set("port", int(self.port.get_value()))
|
||||||
self.config.set("template", self.template.get_active_text())
|
self.config.set("template", self.template.get_active_text())
|
||||||
self.config.set("button_style", self.button_style.get_active())
|
self.config.set("button_style", self.button_style.get_active())
|
||||||
|
self.config.set("cache_templates", self.cache_templates.get_active())
|
||||||
self.config.set("torrent_dir", self.torrent_dir.get_filename())
|
self.config.set("torrent_dir", self.torrent_dir.get_filename())
|
||||||
self.config.set("download_dir",self.download_dir.get_filename())
|
self.config.set("download_dir",self.download_dir.get_filename())
|
||||||
self.config.set("cache_templates", self.cache_templates.get_active())
|
|
||||||
self.config.set("run_in_thread", self.run_in_thread.get_active())
|
|
||||||
self.config.save(self.plugin.config_file)
|
self.config.save(self.plugin.config_file)
|
||||||
self.plugin.start_server() #restarts server
|
self.plugin.start_server() #restarts server
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,25 +32,20 @@
|
|||||||
# this exception statement from your version. If you delete this exception
|
# this exception statement from your version. If you delete this exception
|
||||||
# statement from all source files in the program, then also delete it here.
|
# statement from all source files in the program, then also delete it here.
|
||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import gtk
|
import gtk
|
||||||
import dbus
|
import dbus
|
||||||
import deluge.common as common
|
import deluge.common as common
|
||||||
from dbus_pythonize import pythonize
|
from dbus_pythonize import pythonize
|
||||||
import base64
|
import base64
|
||||||
|
from md5 import md5
|
||||||
import random
|
import random
|
||||||
random.seed()
|
random.seed()
|
||||||
|
|
||||||
dbus_interface="org.deluge_torrent.dbusplugin"
|
dbus_interface="org.deluge_torrent.dbusplugin"
|
||||||
dbus_service="/org/deluge_torrent/DelugeDbusPlugin"
|
dbus_service="/org/deluge_torrent/DelugeDbusPlugin"
|
||||||
|
|
||||||
dbus_manager = None
|
|
||||||
def get_dbus_manager(*args):
|
|
||||||
#another way to make a singleton.
|
|
||||||
global dbus_manager
|
|
||||||
if not dbus_manager:
|
|
||||||
dbus_manager = DbusManager(*args)
|
|
||||||
return dbus_manager
|
|
||||||
|
|
||||||
class DbusManager(dbus.service.Object):
|
class DbusManager(dbus.service.Object):
|
||||||
def __init__(self, core, interface,config,config_file):
|
def __init__(self, core, interface,config,config_file):
|
||||||
@ -94,7 +89,7 @@ class DbusManager(dbus.service.Object):
|
|||||||
"name": state["name"],
|
"name": state["name"],
|
||||||
"total_size": state["total_size"],
|
"total_size": state["total_size"],
|
||||||
"num_pieces": state["num_pieces"],
|
"num_pieces": state["num_pieces"],
|
||||||
"state": state['state'],
|
#"state": int(status.state), #?
|
||||||
"paused": self.core.is_user_paused(torrent_id),
|
"paused": self.core.is_user_paused(torrent_id),
|
||||||
"progress": int(state["progress"] * 100),
|
"progress": int(state["progress"] * 100),
|
||||||
"next_announce": state["next_announce"],
|
"next_announce": state["next_announce"],
|
||||||
@ -108,6 +103,7 @@ class DbusManager(dbus.service.Object):
|
|||||||
"eta": common.estimate_eta(state),
|
"eta": common.estimate_eta(state),
|
||||||
"ratio": self.interface.manager.calc_ratio(torrent_id,state),
|
"ratio": self.interface.manager.calc_ratio(torrent_id,state),
|
||||||
#non 0.6 values follow here:
|
#non 0.6 values follow here:
|
||||||
|
"message": self.interface.get_message_from_state(state),
|
||||||
"tracker_status": state.get("tracker_status","?"),
|
"tracker_status": state.get("tracker_status","?"),
|
||||||
"uploaded_memory": torrent.uploaded_memory,
|
"uploaded_memory": torrent.uploaded_memory,
|
||||||
}
|
}
|
||||||
@ -179,6 +175,39 @@ class DbusManager(dbus.service.Object):
|
|||||||
self._add_torrent(filename)
|
self._add_torrent(filename)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@dbus.service.method(dbus_interface=dbus_interface,
|
||||||
|
in_signature="s",out_signature="v")
|
||||||
|
def get_webui_config(self,key):
|
||||||
|
"""
|
||||||
|
return data from wevbui config.
|
||||||
|
not in 0.6
|
||||||
|
"""
|
||||||
|
retval = self.config.get(str(key))
|
||||||
|
#print 'get webui config:', str(key), retval
|
||||||
|
if retval == None:
|
||||||
|
retval = False #dbus does not accept None :(
|
||||||
|
|
||||||
|
return retval
|
||||||
|
|
||||||
|
@dbus.service.method(dbus_interface=dbus_interface,
|
||||||
|
in_signature="sv",out_signature="")
|
||||||
|
def set_webui_config(self, key, value):
|
||||||
|
"""
|
||||||
|
return data from wevbui config.
|
||||||
|
not in 0.6
|
||||||
|
"""
|
||||||
|
#print 'set webui config:', str(key), pythonize(value)
|
||||||
|
self.config.set(str(key), pythonize(value))
|
||||||
|
self.config.save(self.config_file)
|
||||||
|
|
||||||
|
@dbus.service.method(dbus_interface=dbus_interface,
|
||||||
|
in_signature="s",out_signature="b")
|
||||||
|
def check_pwd(self, pwd):
|
||||||
|
m = md5()
|
||||||
|
m.update(self.config.get('pwd_salt'))
|
||||||
|
m.update(pwd)
|
||||||
|
return (m.digest() == self.config.get('pwd_md5'))
|
||||||
|
|
||||||
#internal
|
#internal
|
||||||
def _add_torrent(self, filename):
|
def _add_torrent(self, filename):
|
||||||
#dbus types break pickle, again.....
|
#dbus types break pickle, again.....
|
||||||
|
@ -31,33 +31,149 @@
|
|||||||
# this exception statement from your version. If you delete this exception
|
# this exception statement from your version. If you delete this exception
|
||||||
# statement from all source files in the program, then also delete it here.
|
# statement from all source files in the program, then also delete it here.
|
||||||
|
|
||||||
|
"""
|
||||||
from webserver_common import proxy, config ,TORRENT_KEYS, STATE_MESSAGES
|
Todo's before stable:
|
||||||
from webserver_framework import *
|
-__init__:kill->restart is not waiting for kill to be finished.
|
||||||
|
--later/features:---
|
||||||
|
-alternating rows?
|
||||||
|
-set prio
|
||||||
|
-clear finished?
|
||||||
|
-torrent files.
|
||||||
|
"""
|
||||||
import webpy022 as web
|
import webpy022 as web
|
||||||
from webpy022.http import seeother, url
|
|
||||||
from webpy022.webapi import setcookie
|
|
||||||
from webpy022.utils import Storage
|
|
||||||
|
|
||||||
from md5 import md5
|
from webpy022.webapi import cookies, setcookie
|
||||||
from deluge.common import fsize
|
from webpy022.http import seeother, url
|
||||||
|
from webpy022.utils import Storage
|
||||||
|
from webpy022.net import urlquote
|
||||||
|
from webpy022 import template, changequery as self_url
|
||||||
|
|
||||||
|
import dbus
|
||||||
|
|
||||||
|
import gettext, os, platform, locale, traceback
|
||||||
|
import random
|
||||||
|
import base64
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
|
from deluge import common
|
||||||
|
from deluge.common import INSTALL_PREFIX
|
||||||
|
|
||||||
|
|
||||||
|
#init:
|
||||||
|
APP = 'deluge'
|
||||||
|
DIR = os.path.join(INSTALL_PREFIX, 'share', 'locale')
|
||||||
|
if platform.system() != "Windows":
|
||||||
|
locale.setlocale(locale.LC_MESSAGES, '')
|
||||||
|
locale.bindtextdomain(APP, DIR)
|
||||||
|
locale.textdomain(APP)
|
||||||
|
else:
|
||||||
|
locale.setlocale(locale.LC_ALL, '')
|
||||||
|
gettext.bindtextdomain(APP, DIR)
|
||||||
|
gettext.textdomain(APP)
|
||||||
|
gettext.install(APP, DIR)
|
||||||
|
|
||||||
|
random.seed()
|
||||||
|
bus = dbus.SessionBus()
|
||||||
|
proxy = bus.get_object("org.deluge_torrent.dbusplugin"
|
||||||
|
, "/org/deluge_torrent/DelugeDbusPlugin")
|
||||||
|
|
||||||
|
web.webapi.internalerror = web.debugerror
|
||||||
|
|
||||||
|
render = template.render('templates/%s/' % proxy.get_webui_config('template')
|
||||||
|
,cache=proxy.get_webui_config('cache_templates'))
|
||||||
|
#/init
|
||||||
|
|
||||||
|
#framework:
|
||||||
|
|
||||||
|
SESSIONS = {}
|
||||||
|
|
||||||
|
def do_redirect():
|
||||||
|
"""for redirects after a POST"""
|
||||||
|
vars = web.input(redir = None)
|
||||||
|
ck = cookies()
|
||||||
|
|
||||||
|
if vars.redir:
|
||||||
|
seeother(vars.redir)
|
||||||
|
elif ("order" in ck and "sort" in ck):
|
||||||
|
seeother(url("/index", sort=ck['sort'], order=ck['order']))
|
||||||
|
else:
|
||||||
|
seeother(url("/index"))
|
||||||
|
|
||||||
|
def deluge_page_noauth(func):
|
||||||
|
"""
|
||||||
|
add http headers
|
||||||
|
print result of func
|
||||||
|
"""
|
||||||
|
def deco(self, name=None):
|
||||||
|
web.header("Content-Type", "text/html; charset=utf-8")
|
||||||
|
web.header("Cache-Control", "no-cache, must-revalidate")
|
||||||
|
res = func(self, name)
|
||||||
|
print res
|
||||||
|
return deco
|
||||||
|
|
||||||
|
def check_session(func):
|
||||||
|
"""
|
||||||
|
a decorator
|
||||||
|
return func if session is valid, else redirect to login page.
|
||||||
|
"""
|
||||||
|
def deco(self, name):
|
||||||
|
vars = web.input(redir_after_login=None)
|
||||||
|
|
||||||
|
ck = cookies()
|
||||||
|
if ck.has_key("session_id") and ck["session_id"] in SESSIONS:
|
||||||
|
return func(self, name) #ok, continue..
|
||||||
|
elif vars.redir_after_login:
|
||||||
|
seeother("/login?redir=" + urlquote(self_url()))
|
||||||
|
else:
|
||||||
|
seeother("/login") #do not continue, and redirect to login page
|
||||||
|
return deco
|
||||||
|
|
||||||
|
def deluge_page(func):
|
||||||
|
return check_session(deluge_page_noauth(func))
|
||||||
|
|
||||||
|
def auto_refreshed(func):
|
||||||
|
"decorator:adds a refresh header"
|
||||||
|
def deco(self, name):
|
||||||
|
if proxy.get_webui_config('auto_refresh'):
|
||||||
|
web.header("Refresh", "%i ; url=%s" %
|
||||||
|
(proxy.get_webui_config('auto_refresh_secs'),self_url()))
|
||||||
|
return func(self, name)
|
||||||
|
return deco
|
||||||
|
|
||||||
|
def error_page(error):
|
||||||
|
web.header("Content-Type", "text/html; charset=utf-8")
|
||||||
|
web.header("Cache-Control", "no-cache, must-revalidate")
|
||||||
|
print render.error(error)
|
||||||
|
|
||||||
|
def remote(func):
|
||||||
|
"decorator for remote api's"
|
||||||
|
def deco(self, name):
|
||||||
|
try:
|
||||||
|
print func(self, name)
|
||||||
|
except Exception, e:
|
||||||
|
print 'error:' + e.message
|
||||||
|
print '-'*20
|
||||||
|
print traceback.format_exc()
|
||||||
|
return deco
|
||||||
|
|
||||||
|
#/framework
|
||||||
|
|
||||||
#utils:
|
#utils:
|
||||||
def check_pwd(pwd):
|
torrent_keys = ['distributed_copies', 'download_payload_rate',
|
||||||
m = md5()
|
'download_rate', 'eta', 'is_seed', 'message', 'name', 'next_announce',
|
||||||
m.update(config.get('pwd_salt'))
|
'num_files', 'num_peers', 'num_pieces', 'num_seeds', 'paused',
|
||||||
m.update(pwd)
|
'piece_length','progress', 'ratio', 'total_done', 'total_download',
|
||||||
return (m.digest() == config.get('pwd_md5'))
|
'total_payload_download', 'total_payload_upload', 'total_peers',
|
||||||
|
'total_seeds', 'total_size', 'total_upload', 'total_wanted',
|
||||||
|
'tracker_status', 'upload_payload_rate', 'upload_rate',
|
||||||
|
'uploaded_memory','tracker']
|
||||||
|
|
||||||
def get_torrent_status(torrent_id):
|
def get_torrent_status(torrent_id):
|
||||||
"""
|
"""
|
||||||
helper method.
|
helper method.
|
||||||
enhance proxy.get_torrent_status with some extra data
|
enhance proxy.get_torrent_status with some extra data
|
||||||
"""
|
"""
|
||||||
status = proxy.get_torrent_status(torrent_id,TORRENT_KEYS)
|
status = proxy.get_torrent_status(torrent_id,torrent_keys)
|
||||||
status["id"] = torrent_id
|
status["id"] = torrent_id
|
||||||
|
|
||||||
#for naming the status-images
|
#for naming the status-images
|
||||||
@ -73,26 +189,61 @@ def get_torrent_status(torrent_id):
|
|||||||
else:
|
else:
|
||||||
status["action"] = "stop"
|
status["action"] = "stop"
|
||||||
|
|
||||||
|
|
||||||
if status["paused"]:
|
|
||||||
status["message"] = _("Paused %s%%") % status['progress']
|
|
||||||
else:
|
|
||||||
status["message"] = "%s %i%%" % (STATE_MESSAGES[status["state"]]
|
|
||||||
, status['progress'])
|
|
||||||
|
|
||||||
#add some pre-calculated values
|
#add some pre-calculated values
|
||||||
status.update({
|
status.update({
|
||||||
"calc_total_downloaded" : (fsize(status["total_done"])
|
"calc_total_downloaded" : (common.fsize(status["total_done"])
|
||||||
+ " (" + fsize(status["total_download"]) + ")"),
|
+ " (" + common.fsize(status["total_download"]) + ")"),
|
||||||
"calc_total_uploaded": (fsize(status['uploaded_memory']
|
"calc_total_uploaded": (common.fsize(status['uploaded_memory']
|
||||||
+ status["total_payload_upload"]) + " ("
|
+ status["total_payload_upload"]) + " ("
|
||||||
+ fsize(status["total_upload"]) + ")"),
|
+ common.fsize(status["total_upload"]) + ")"),
|
||||||
})
|
})
|
||||||
|
|
||||||
return Storage(status) #Storage for easy templating.
|
return Storage(status) #Storage for easy templating.
|
||||||
|
|
||||||
#/utils
|
#/utils
|
||||||
|
|
||||||
|
#template-defs:
|
||||||
|
def template_crop(text, end):
|
||||||
|
if len(text) > end:
|
||||||
|
return text[0:end - 3] + '...'
|
||||||
|
return text
|
||||||
|
|
||||||
|
def template_sort_head(id,name):
|
||||||
|
#got tired of doing these complex things inside templetor..
|
||||||
|
vars = web.input(sort=None, order=None)
|
||||||
|
active_up = False
|
||||||
|
active_down = False
|
||||||
|
order = 'down'
|
||||||
|
|
||||||
|
if vars.sort == id:
|
||||||
|
if vars.order == 'down':
|
||||||
|
order = 'up'
|
||||||
|
active_down = True
|
||||||
|
else:
|
||||||
|
active_up = True
|
||||||
|
|
||||||
|
return render.sort_column_head(id, name, order, active_up, active_down)
|
||||||
|
|
||||||
|
template.Template.globals.update({
|
||||||
|
'sort_head': template_sort_head,
|
||||||
|
'crop': template_crop,
|
||||||
|
'_': _ , #gettext/translations
|
||||||
|
'str': str, #because % in templetor is broken.
|
||||||
|
'sorted': sorted,
|
||||||
|
'get_config': proxy.get_webui_config,
|
||||||
|
'self_url': self_url,
|
||||||
|
'fspeed': common.fspeed,
|
||||||
|
'fsize': common.fsize,
|
||||||
|
'render': render, #for easy resuse of templates
|
||||||
|
'button_style': (proxy.get_webui_config('button_style')),
|
||||||
|
'rev': ('rev.' +
|
||||||
|
open(os.path.join(os.path.dirname(__file__),'revno')).read()),
|
||||||
|
'version': (
|
||||||
|
open(os.path.join(os.path.dirname(__file__),'version')).read()),
|
||||||
|
'get': lambda (var): getattr(web.input(**{var:None}),var) # unreadable :-(
|
||||||
|
})
|
||||||
|
#/template-defs
|
||||||
|
|
||||||
#routing:
|
#routing:
|
||||||
urls = (
|
urls = (
|
||||||
"/login(.*)", "login",
|
"/login(.*)", "login",
|
||||||
@ -126,12 +277,14 @@ class login:
|
|||||||
def POST(self, name):
|
def POST(self, name):
|
||||||
vars = web.input(pwd = None ,redir = None)
|
vars = web.input(pwd = None ,redir = None)
|
||||||
|
|
||||||
if check_pwd(vars.pwd):
|
if proxy.check_pwd(vars.pwd):
|
||||||
#start new session
|
#start new session
|
||||||
start_session()
|
session_id = str(random.random())
|
||||||
|
SESSIONS[session_id] = {"not":"used"}
|
||||||
|
setcookie("session_id", session_id)
|
||||||
do_redirect()
|
do_redirect()
|
||||||
elif vars.redir:
|
elif vars.redir:
|
||||||
seeother(url('/login',error=1,redir=vars.redir))
|
seeother('/login?error=1&redir=' + urlquote(vars.redir))
|
||||||
else:
|
else:
|
||||||
seeother('/login?error=1')
|
seeother('/login?error=1')
|
||||||
|
|
||||||
@ -207,12 +360,13 @@ class remote_torrent_add:
|
|||||||
"""
|
"""
|
||||||
For use in remote scripts etc.
|
For use in remote scripts etc.
|
||||||
POST pwd and torrent
|
POST pwd and torrent
|
||||||
|
Example : curl -F torrent=@./test1.torrent -F pwd=deluge http://localhost:8112/remote/torrent/add"
|
||||||
"""
|
"""
|
||||||
@remote
|
@remote
|
||||||
def POST(self, name):
|
def POST(self, name):
|
||||||
vars = web.input(pwd = None, torrent = {})
|
vars = web.input(pwd = None, torrent = {})
|
||||||
|
|
||||||
if not check_pwd(vars.pwd):
|
if not proxy.check_pwd(vars.pwd):
|
||||||
return 'error:wrong password'
|
return 'error:wrong password'
|
||||||
|
|
||||||
data_b64 = base64.b64encode(vars.torrent.file.read())
|
data_b64 = base64.b64encode(vars.torrent.file.read())
|
||||||
@ -250,8 +404,8 @@ class resume_all:
|
|||||||
class refresh:
|
class refresh:
|
||||||
@check_session
|
@check_session
|
||||||
def POST(self, name):
|
def POST(self, name):
|
||||||
auto_refresh = {'off':'0', 'on':'1'}[name]
|
auto_refresh = {'off':False, 'on':True}[name]
|
||||||
setcookie('auto_refresh',auto_refresh)
|
proxy.set_webui_config('auto_refresh', auto_refresh)
|
||||||
do_redirect()
|
do_redirect()
|
||||||
|
|
||||||
class refresh_set:
|
class refresh_set:
|
||||||
@ -264,8 +418,8 @@ class refresh_set:
|
|||||||
vars = web.input(refresh = 0)
|
vars = web.input(refresh = 0)
|
||||||
refresh = int(vars.refresh)
|
refresh = int(vars.refresh)
|
||||||
if refresh > 0:
|
if refresh > 0:
|
||||||
setcookie('auto_refresh','1')
|
proxy.set_webui_config('refresh', refresh)
|
||||||
setcookie('auto_refresh_secs', str(refresh))
|
proxy.set_webui_config('auto_refresh', True)
|
||||||
do_redirect()
|
do_redirect()
|
||||||
else:
|
else:
|
||||||
error_page(_('refresh must be > 0'))
|
error_page(_('refresh must be > 0'))
|
||||||
@ -275,19 +429,10 @@ class about:
|
|||||||
def GET(self, name):
|
def GET(self, name):
|
||||||
return render.about()
|
return render.about()
|
||||||
|
|
||||||
|
|
||||||
#/pages
|
#/pages
|
||||||
|
|
||||||
|
|
||||||
def WebServer():
|
|
||||||
return create_webserver(urls, globals())
|
|
||||||
|
|
||||||
def run():
|
|
||||||
server = WebServer()
|
|
||||||
try:
|
|
||||||
server.start()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
server.stop()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run()
|
web.run(urls, globals())
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Copyright (C) Martijn Voncken 2007 <mvoncken@gmail.com>
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, write to:
|
|
||||||
# The Free Software Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
#
|
|
||||||
# In addition, as a special exception, the copyright holders give
|
|
||||||
# permission to link the code of portions of this program with the OpenSSL
|
|
||||||
# library.
|
|
||||||
# You must obey the GNU General Public License in all respects for all of
|
|
||||||
# the code used other than OpenSSL. If you modify file(s) with this
|
|
||||||
# exception, you may extend this exception to your version of the file(s),
|
|
||||||
# but you are not obligated to do so. If you do not wish to do so, delete
|
|
||||||
# this exception statement from your version. If you delete this exception
|
|
||||||
# statement from all source files in the program, then also delete it here.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import deluge
|
|
||||||
from deluge.common import INSTALL_PREFIX
|
|
||||||
import random
|
|
||||||
import pickle
|
|
||||||
random.seed()
|
|
||||||
|
|
||||||
config_file = deluge.common.CONFIG_DIR + "/webui.conf"
|
|
||||||
#config = deluge.pref.Preferences(config_file, False)
|
|
||||||
config = pickle.load(open(config_file))
|
|
||||||
|
|
||||||
if config.get('run_in_thread'):
|
|
||||||
#do not use dbus ipc for threads!
|
|
||||||
from dbus_interface import get_dbus_manager
|
|
||||||
proxy = get_dbus_manager()
|
|
||||||
else:
|
|
||||||
import dbus
|
|
||||||
bus = dbus.SessionBus()
|
|
||||||
proxy = bus.get_object("org.deluge_torrent.dbusplugin"
|
|
||||||
, "/org/deluge_torrent/DelugeDbusPlugin")
|
|
||||||
|
|
||||||
REVNO = open(os.path.join(os.path.dirname(__file__),'revno')).read()
|
|
||||||
VERSION = open(os.path.join(os.path.dirname(__file__),'version')).read()
|
|
||||||
|
|
||||||
TORRENT_KEYS = ['distributed_copies', 'download_payload_rate',
|
|
||||||
'download_rate', 'eta', 'is_seed', 'name', 'next_announce',
|
|
||||||
'num_files', 'num_peers', 'num_pieces', 'num_seeds', 'paused',
|
|
||||||
'piece_length','progress', 'ratio', 'total_done', 'total_download',
|
|
||||||
'total_payload_download', 'total_payload_upload', 'total_peers',
|
|
||||||
'total_seeds', 'total_size', 'total_upload', 'total_wanted',
|
|
||||||
'tracker_status', 'upload_payload_rate', 'upload_rate',
|
|
||||||
'uploaded_memory','tracker','state']
|
|
||||||
|
|
||||||
STATE_MESSAGES = (_("Queued"),
|
|
||||||
_("Checking"),
|
|
||||||
_("Connecting"),
|
|
||||||
_("Downloading Metadata"),
|
|
||||||
_("Downloading"),
|
|
||||||
_("Finished"),
|
|
||||||
_("Seeding"),
|
|
||||||
_("Allocating"))
|
|
@ -1,302 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# webserver_framework.py
|
|
||||||
#
|
|
||||||
# Copyright (C) Martijn Voncken 2007 <mvoncken@gmail.com>
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, write to:
|
|
||||||
# The Free Software Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor
|
|
||||||
# Boston, MA 02110-1301, USA.
|
|
||||||
#
|
|
||||||
# In addition, as a special exception, the copyright holders give
|
|
||||||
# permission to link the code of portions of this program with the OpenSSL
|
|
||||||
# library.
|
|
||||||
# You must obey the GNU General Public License in all respects for all of
|
|
||||||
# the code used other than OpenSSL. If you modify file(s) with this
|
|
||||||
# exception, you may extend this exception to your version of the file(s),
|
|
||||||
# but you are not obligated to do so. If you do not wish to do so, delete
|
|
||||||
# this exception statement from your version. If you delete this exception
|
|
||||||
# statement from all source files in the program, then also delete it here.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Todo's before stable:
|
|
||||||
-__init__:kill->restart is not waiting for kill to be finished.
|
|
||||||
--later/features:---
|
|
||||||
-alternating rows?
|
|
||||||
-set prio
|
|
||||||
-clear finished?
|
|
||||||
-torrent files.
|
|
||||||
"""
|
|
||||||
import webpy022 as web
|
|
||||||
|
|
||||||
from webpy022.webapi import cookies, setcookie
|
|
||||||
from webpy022.http import seeother, url
|
|
||||||
from webpy022 import template, changequery as self_url
|
|
||||||
|
|
||||||
import traceback
|
|
||||||
import random
|
|
||||||
from operator import attrgetter
|
|
||||||
|
|
||||||
from deluge import common
|
|
||||||
from webserver_common import proxy, config , REVNO, VERSION
|
|
||||||
|
|
||||||
#init:
|
|
||||||
web.webapi.internalerror = web.debugerror
|
|
||||||
render = template.render('templates/%s/' % config.get('template'),
|
|
||||||
cache=config.get('cache_templates'))
|
|
||||||
|
|
||||||
#/init
|
|
||||||
|
|
||||||
#methods:
|
|
||||||
SESSIONS = [] #dumb sessions.
|
|
||||||
def start_session():
|
|
||||||
session_id = str(random.random())
|
|
||||||
SESSIONS.append(session_id)
|
|
||||||
setcookie("session_id", session_id)
|
|
||||||
|
|
||||||
def do_redirect():
|
|
||||||
"""for redirects after a POST"""
|
|
||||||
vars = web.input(redir = None)
|
|
||||||
ck = cookies()
|
|
||||||
|
|
||||||
if vars.redir:
|
|
||||||
seeother(vars.redir)
|
|
||||||
elif ("order" in ck and "sort" in ck):
|
|
||||||
seeother(url("/index", sort=ck['sort'], order=ck['order']))
|
|
||||||
else:
|
|
||||||
seeother(url("/index"))
|
|
||||||
|
|
||||||
def error_page(error):
|
|
||||||
web.header("Content-Type", "text/html; charset=utf-8")
|
|
||||||
web.header("Cache-Control", "no-cache, must-revalidate")
|
|
||||||
print render.error(error)
|
|
||||||
|
|
||||||
def getcookie(key, default=None):
|
|
||||||
ck = cookies()
|
|
||||||
return str(ck.get(key, default))
|
|
||||||
|
|
||||||
#deco's:
|
|
||||||
def deluge_page_noauth(func):
|
|
||||||
"""
|
|
||||||
add http headers
|
|
||||||
print result of func
|
|
||||||
"""
|
|
||||||
def deco(self, name=None):
|
|
||||||
web.header("Content-Type", "text/html; charset=utf-8")
|
|
||||||
web.header("Cache-Control", "no-cache, must-revalidate")
|
|
||||||
res = func(self, name)
|
|
||||||
print res
|
|
||||||
return deco
|
|
||||||
|
|
||||||
def check_session(func):
|
|
||||||
"""
|
|
||||||
a decorator
|
|
||||||
return func if session is valid, else redirect to login page.
|
|
||||||
"""
|
|
||||||
def deco(self, name):
|
|
||||||
vars = web.input(redir_after_login=None)
|
|
||||||
|
|
||||||
ck = cookies()
|
|
||||||
if ck.has_key("session_id") and ck["session_id"] in SESSIONS:
|
|
||||||
return func(self, name) #ok, continue..
|
|
||||||
elif vars.redir_after_login:
|
|
||||||
seeother(url("/login",redir=self_url()))
|
|
||||||
else:
|
|
||||||
seeother("/login") #do not continue, and redirect to login page
|
|
||||||
return deco
|
|
||||||
|
|
||||||
def deluge_page(func):
|
|
||||||
return check_session(deluge_page_noauth(func))
|
|
||||||
|
|
||||||
#combi-deco's:
|
|
||||||
def auto_refreshed(func):
|
|
||||||
"decorator:adds a refresh header"
|
|
||||||
def deco(self, name):
|
|
||||||
if getcookie('auto_refresh') == '1':
|
|
||||||
web.header("Refresh", "%i ; url=%s" %
|
|
||||||
(int(getcookie('auto_refresh_secs',10)),self_url()))
|
|
||||||
return func(self, name)
|
|
||||||
return deco
|
|
||||||
|
|
||||||
def remote(func):
|
|
||||||
"decorator for remote api's"
|
|
||||||
def deco(self, name):
|
|
||||||
try:
|
|
||||||
print func(self, name)
|
|
||||||
except Exception, e:
|
|
||||||
print 'error:' + e.message
|
|
||||||
print '-'*20
|
|
||||||
print traceback.format_exc()
|
|
||||||
return deco
|
|
||||||
|
|
||||||
#template-defs:
|
|
||||||
def template_crop(text, end):
|
|
||||||
if len(text) > end:
|
|
||||||
return text[0:end - 3] + '...'
|
|
||||||
return text
|
|
||||||
|
|
||||||
def template_sort_head(id,name):
|
|
||||||
#got tired of doing these complex things inside templetor..
|
|
||||||
vars = web.input(sort=None, order=None)
|
|
||||||
active_up = False
|
|
||||||
active_down = False
|
|
||||||
order = 'down'
|
|
||||||
|
|
||||||
if vars.sort == id:
|
|
||||||
if vars.order == 'down':
|
|
||||||
order = 'up'
|
|
||||||
active_down = True
|
|
||||||
else:
|
|
||||||
active_up = True
|
|
||||||
|
|
||||||
return render.sort_column_head(id, name, order, active_up, active_down)
|
|
||||||
|
|
||||||
template.Template.globals.update({
|
|
||||||
'sort_head': template_sort_head,
|
|
||||||
'crop': template_crop,
|
|
||||||
'_': _ , #gettext/translations
|
|
||||||
'str': str, #because % in templetor is broken.
|
|
||||||
'sorted': sorted,
|
|
||||||
'get_config': config.get,
|
|
||||||
'self_url': self_url,
|
|
||||||
'fspeed': common.fspeed,
|
|
||||||
'fsize': common.fsize,
|
|
||||||
'render': render, #for easy resuse of templates
|
|
||||||
'button_style': (config.get('button_style')),
|
|
||||||
'rev': 'rev.%s' % (REVNO, ),
|
|
||||||
'version': VERSION,
|
|
||||||
'get': lambda (var): getattr(web.input(**{var:None}),var) # unreadable :-(
|
|
||||||
})
|
|
||||||
#/template-defs
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
|
||||||
#Some copy and paste from web.py
|
|
||||||
#mostly caused by /static
|
|
||||||
#TODO : FIX THIS.
|
|
||||||
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
|
||||||
from BaseHTTPServer import BaseHTTPRequestHandler
|
|
||||||
from webpy022.request import webpyfunc
|
|
||||||
from webpy022 import webapi
|
|
||||||
import os
|
|
||||||
|
|
||||||
class StaticApp(SimpleHTTPRequestHandler):
|
|
||||||
"""WSGI application for serving static files."""
|
|
||||||
def __init__(self, environ, start_response):
|
|
||||||
self.headers = []
|
|
||||||
self.environ = environ
|
|
||||||
self.start_response = start_response
|
|
||||||
|
|
||||||
def send_response(self, status, msg=""):
|
|
||||||
self.status = str(status) + " " + msg
|
|
||||||
|
|
||||||
def send_header(self, name, value):
|
|
||||||
self.headers.append((name, value))
|
|
||||||
|
|
||||||
def end_headers(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def log_message(*a): pass
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
environ = self.environ
|
|
||||||
|
|
||||||
self.path = environ.get('PATH_INFO', '')
|
|
||||||
self.client_address = environ.get('REMOTE_ADDR','-'), \
|
|
||||||
environ.get('REMOTE_PORT','-')
|
|
||||||
self.command = environ.get('REQUEST_METHOD', '-')
|
|
||||||
|
|
||||||
from cStringIO import StringIO
|
|
||||||
self.wfile = StringIO() # for capturing error
|
|
||||||
|
|
||||||
f = self.send_head()
|
|
||||||
self.start_response(self.status, self.headers)
|
|
||||||
|
|
||||||
if f:
|
|
||||||
block_size = 16 * 1024
|
|
||||||
while True:
|
|
||||||
buf = f.read(block_size)
|
|
||||||
if not buf:
|
|
||||||
break
|
|
||||||
yield buf
|
|
||||||
f.close()
|
|
||||||
else:
|
|
||||||
value = self.wfile.getvalue()
|
|
||||||
yield value
|
|
||||||
|
|
||||||
class WSGIWrapper(BaseHTTPRequestHandler):
|
|
||||||
"""WSGI wrapper for logging the status and serving static files."""
|
|
||||||
def __init__(self, app):
|
|
||||||
self.app = app
|
|
||||||
self.format = '%s - - [%s] "%s %s %s" - %s'
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
|
||||||
def xstart_response(status, response_headers, *args):
|
|
||||||
write = start_response(status, response_headers, *args)
|
|
||||||
self.log(status, environ)
|
|
||||||
return write
|
|
||||||
|
|
||||||
path = environ.get('PATH_INFO', '')
|
|
||||||
if path.startswith('/static/'):
|
|
||||||
return StaticApp(environ, xstart_response)
|
|
||||||
else:
|
|
||||||
return self.app(environ, xstart_response)
|
|
||||||
|
|
||||||
def log(self, status, environ):
|
|
||||||
#mvoncken,no logging..
|
|
||||||
return
|
|
||||||
|
|
||||||
outfile = environ.get('wsgi.errors', web.debug)
|
|
||||||
req = environ.get('PATH_INFO', '_')
|
|
||||||
protocol = environ.get('ACTUAL_SERVER_PROTOCOL', '-')
|
|
||||||
method = environ.get('REQUEST_METHOD', '-')
|
|
||||||
host = "%s:%s" % (environ.get('REMOTE_ADDR','-'),
|
|
||||||
environ.get('REMOTE_PORT','-'))
|
|
||||||
|
|
||||||
#@@ It is really bad to extend from
|
|
||||||
#@@ BaseHTTPRequestHandler just for this method
|
|
||||||
time = self.log_date_time_string()
|
|
||||||
|
|
||||||
print >> outfile, self.format % (host, time, protocol,
|
|
||||||
method, req, status)
|
|
||||||
|
|
||||||
def create_webserver(urls,methods):
|
|
||||||
from webpy022.wsgiserver import CherryPyWSGIServer
|
|
||||||
from BaseHTTPServer import BaseHTTPRequestHandler
|
|
||||||
|
|
||||||
|
|
||||||
os.chdir(os.path.dirname(__file__)) #HACK for /static..
|
|
||||||
|
|
||||||
func = webapi.wsgifunc(webpyfunc(urls,methods, False))
|
|
||||||
server_address=("0.0.0.0",config.get('port'))
|
|
||||||
|
|
||||||
func = WSGIWrapper(func)
|
|
||||||
server = CherryPyWSGIServer(server_address, func, server_name="localhost")
|
|
||||||
|
|
||||||
|
|
||||||
print "(created) http://%s:%d/" % server_address
|
|
||||||
|
|
||||||
return server
|
|
||||||
|
|
||||||
#------
|
|
||||||
__all__ = ['deluge_page_noauth', 'deluge_page', 'remote',
|
|
||||||
'auto_refreshed', 'check_session',
|
|
||||||
'do_redirect', 'error_page', 'render', 'start_session','getcookie'
|
|
||||||
,'create_webserver']
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user