sync webui plugin with rev48

This commit is contained in:
Marcos Pinto 2007-09-29 06:39:06 +00:00
parent 9a050065a9
commit 53e65e9554
19 changed files with 238 additions and 100 deletions

View File

@ -33,18 +33,24 @@
plugin_name = "Web User interface" plugin_name = "Web User interface"
plugin_author = "Martijn Voncken" plugin_author = "Martijn Voncken"
plugin_version = "rev." plugin_version = "rev."
plugin_description = """A Web based User Interface (and dbus-ipc) plugin_description = "A Web based User Interface\n"
beta test version, disclaimer, etc..
"""
import deluge.common, deluge.pref import deluge.common
import deluge.pref
from deluge.dialogs import show_popup_warning
from dbus_interface import DbusManager 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
import random
random.seed()
plugin_version += open(os.path.join(os.path.dirname(__file__),'revno')).read() plugin_version += open(os.path.join(os.path.dirname(__file__),'revno')).read()
plugin_description += (
open(os.path.join(os.path.dirname(__file__),'version')).read())
def deluge_init(deluge_path): def deluge_init(deluge_path):
global path global path
@ -72,19 +78,24 @@ class plugin_WebUi:
if not self.config.get('port'): #ugly way to detect new config file. if not self.config.get('port'): #ugly way to detect new config file.
#set default values: #set default values:
self.config.set("port", 8112) self.config.set("port", 8112)
self.config.set("user", "deluge")
self.config.set("pwd", "deluge")
#future->use deluge-core setting for download_dir (if it is set) #future->use deluge-core setting for download_dir (if it is set)
self.config.set("download_dir", os.path.expanduser("~/")) self.config.set("download_dir", os.path.expanduser("~/"))
self.config.set("torrent_dir", os.path.expanduser("~/")) self.config.set("torrent_dir", os.path.expanduser("~/"))
self.config.set("button_style", 2)
self.config.set("auto_refresh", False) self.config.set("auto_refresh", False)
self.config.set("auto_refresh_secs", 4) self.config.set("auto_refresh_secs", 4)
self.config.set("template", "deluge") self.config.set("template", "deluge")
self.config.save(self.config_file) self.config.save(self.config_file)
if not self.config.get("pwd_salt"):
self.config.set("pwd_salt", "invalid")
self.config.set("pwd_md5", "invalid")
self.dbusManager = DbusManager(deluge_core, deluge_interface self.dbusManager = DbusManager(deluge_core, deluge_interface
, self.config, self.config_file) , self.config, self.config_file)
print dir(self.dbusManager)
self.start_server() self.start_server()
def unload(self): def unload(self):
@ -135,9 +146,11 @@ class ConfigDialog(gtk.Dialog):
if os.path.isdir(os.path.join(template_path, dirname))] if os.path.isdir(os.path.join(template_path, dirname))]
self.port = self.add_widget(_('Port Number'), gtk.SpinButton()) self.port = self.add_widget(_('Port Number'), gtk.SpinButton())
self.user = self.add_widget(_('User'), gtk.Entry()) self.pwd1 = self.add_widget(_('New Password'), gtk.Entry())
self.pwd = self.add_widget(_('Password'), gtk.Entry()) self.pwd2 = self.add_widget(_('New Password(confirm)'), gtk.Entry())
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'),
gtk.combo_box_new_text())
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'),
@ -147,16 +160,24 @@ class ConfigDialog(gtk.Dialog):
self.torrent_dir.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) self.torrent_dir.set_action(gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
self.port.set_range(80, 65536) self.port.set_range(80, 65536)
self.port.set_increments(1, 10) self.port.set_increments(1, 10)
self.pwd1.set_visibility(False)
self.pwd2.set_visibility(False)
for item in self.templates: for item in self.templates:
self.template.append_text(item) self.template.append_text(item)
self.button_style
if not self.config.get("template") in self.templates: if not self.config.get("template") in self.templates:
self.config.set("template","deluge") self.config.set("template","deluge")
self.user.set_text(self.config.get("user")) for item in [_('Text and image'), _('Image Only'), _('Text Only')]:
self.pwd.set_text(self.config.get("pwd")) self.button_style.append_text(item)
if not self.config.get("button_style"):
self.config.set("button_style", 2)
self.port.set_value(int(self.config.get("port"))) self.port.set_value(int(self.config.get("port")))
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.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.vbox.pack_start(self.vb, True, True, 0) self.vbox.pack_start(self.vb, True, True, 0)
@ -177,11 +198,21 @@ class ConfigDialog(gtk.Dialog):
self.add_buttons(dgtk.STOCK_CLOSE, dgtk.RESPONSE_CLOSE) self.add_buttons(dgtk.STOCK_CLOSE, dgtk.RESPONSE_CLOSE)
def save_config(self): def save_config(self):
print 'save config' if self.pwd1.get_text() > '':
self.config.set("user", self.user.get_text()) if self.pwd1.get_text() <> self.pwd2.get_text():
self.config.set("pwd", self.pwd.get_text()) show_popup_warning(self,_("Confirmed Password <> New Password\n"
+ "Password was not changed"))
else:
salt = str(random.getrandbits(500))
m = md5()
m.update(salt)
m.update(unicode(self.pwd1.get_text()))
self.config.set("pwd_salt", salt)
self.config.set("pwd_md5", m.digest())
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("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.save(self.plugin.config_file) self.config.save(self.plugin.config_file)

View File

@ -0,0 +1 @@
curl -F torrent=@./test1.torrent -F pwd=deluge http://localhost:8112/remote/torrent/add

View File

@ -39,6 +39,7 @@ 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()
@ -182,7 +183,7 @@ class DbusManager(dbus.service.Object):
not in 0.6 not in 0.6
""" """
retval = self.config.get(str(key)) retval = self.config.get(str(key))
print 'get webui config:', str(key), retval #print 'get webui config:', str(key), retval
if retval == None: if retval == None:
retval = False #dbus does not accept None :( retval = False #dbus does not accept None :(
@ -195,10 +196,18 @@ class DbusManager(dbus.service.Object):
return data from wevbui config. return data from wevbui config.
not in 0.6 not in 0.6
""" """
print 'set webui config:', str(key), pythonize(value) #print 'set webui config:', str(key), pythonize(value)
self.config.set(str(key), pythonize(value)) self.config.set(str(key), pythonize(value))
self.config.save(self.config_file) 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.....

View File

@ -50,7 +50,7 @@ from webpy022 import template
import dbus import dbus
import gettext, os, platform, locale import gettext, os, platform, locale, traceback
import random import random
import base64 import base64
from operator import attrgetter from operator import attrgetter
@ -105,7 +105,7 @@ def deluge_page_noauth(func):
web.header("Content-Type", "text/html; charset=utf-8") web.header("Content-Type", "text/html; charset=utf-8")
web.header("Cache-Control", "no-cache, must-revalidate") web.header("Cache-Control", "no-cache, must-revalidate")
res = func(self, name) res = func(self, name)
print res print unicode(res)
return deco return deco
def check_session(func): def check_session(func):
@ -139,6 +139,17 @@ def error_page(error):
web.header("Cache-Control", "no-cache, must-revalidate") web.header("Cache-Control", "no-cache, must-revalidate")
print render.error(error) 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 #/framework
#utils: #utils:
@ -191,7 +202,7 @@ def template_crop(text, end):
return text[0:end - 3] + '...' return text[0:end - 3] + '...'
return text return text
def sort_head(id,name): def template_sort_head(id,name):
#got tired of doing these complex things inside templetor.. #got tired of doing these complex things inside templetor..
vars = web.input(sort=None, order=None) vars = web.input(sort=None, order=None)
active_up = False active_up = False
@ -210,18 +221,23 @@ def sort_head(id,name):
render = template.render('templates/%s/' % proxy.get_webui_config('template')) render = template.render('templates/%s/' % proxy.get_webui_config('template'))
template.Template.globals['crop'] = template_crop template.Template.globals.update({
template.Template.globals['fspeed'] = common.fspeed 'sort_head': template_sort_head,
template.Template.globals['fsize'] = common.fsize 'crop': template_crop,
template.Template.globals['sorted'] = sorted '_': _ , #gettext/translations
template.Template.globals['_'] = _ #gettext/translations 'str': str, #because % in templetor is broken.
template.Template.globals['deluge_web_version'] = ('rev.' 'sorted': sorted,
+ open(os.path.join(os.path.dirname(__file__),'revno')).read()) 'get_config': proxy.get_webui_config,
template.Template.globals['render'] = render #for easy resuse of templates 'self_url': web.changequery,
template.Template.globals['sort_head'] = sort_head 'fspeed': common.fspeed,
template.Template.globals['get_config'] = proxy.get_webui_config 'fsize': common.fsize,
template.Template.globals['self_url'] = web.changequery '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())
})
#/template-defs #/template-defs
#routing: #routing:
@ -237,9 +253,12 @@ urls = (
"/refresh/set(.*)", "refresh_set", "/refresh/set(.*)", "refresh_set",
"/refresh/(.*)", "refresh", "/refresh/(.*)", "refresh",
"/home(.*)", "home", "/home(.*)", "home",
"/about(.*)", "about",
#default-pages #default-pages
"/", "login", "/", "login",
"", "login" "", "login",
#remote-api:
"/remote/torrent/add(.*)", "remote_torrent_add"
) )
#/routing #/routing
@ -248,20 +267,20 @@ urls = (
class login: class login:
@deluge_page_noauth @deluge_page_noauth
def GET(self, name): def GET(self, name):
return render.login() vars = web.input(error = None)
return render.login(vars.error)
def POST(self, name): def POST(self, name):
vars = web.input(var = None, pwd = None) vars = web.input(pwd = None)
if (vars.user == proxy.get_webui_config('user') if proxy.check_pwd(vars.pwd):
and vars.pwd == proxy.get_webui_config('pwd')):
#start new session #start new session
session_id = str(random.random()) session_id = str(random.random())
SESSIONS[session_id] = {"user":vars.user} SESSIONS[session_id] = {"not":"used"}
setcookie("session_id", session_id) setcookie("session_id", session_id)
do_redirect() do_redirect()
else: else:
error_page(_("Username or Password is invalid.")) seeother('/login?error=1')
class home: class home:
@check_session @check_session
@ -332,6 +351,23 @@ class torrent_add:
else: else:
error_page(_("no data.")) error_page(_("no data."))
class remote_torrent_add:
"""
For use in remote scripts etc.
POST user and file
Example : curl -F torrent=@./test1.torrent -F pwd=deluge http://localhost:8112/remote/torrent/add"
"""
@remote
def POST(self, name):
vars = web.input(pwd = None, torrent = {})
if not proxy.check_pwd(vars.pwd):
return 'error:wrong password'
data_b64 = base64.b64encode(vars.torrent.file.read())
proxy.add_torrent_filecontent(vars.torrent.filename,data_b64)
return 'ok'
class torrent_delete: class torrent_delete:
@deluge_page @deluge_page
def GET(self, torrent_id): def GET(self, torrent_id):
@ -383,6 +419,12 @@ class refresh_set:
else: else:
error_page(_('refresh must be > 0')) error_page(_('refresh must be > 0'))
class about:
@deluge_page_noauth
def GET(self, name):
return render.about()
#/pages #/pages
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1 +1 @@
40 48

View File

@ -31,6 +31,15 @@ button.deluge_button {
color: #000; color: #000;
} }
div.error {
background-color:#FFFFFF;
color:#AA0000;
font-weight:bold;
-moz-border-radius:10px;
width:200px;
margin-bottom:20px;
padding:10px;
}
/* Hides from IE-mac \*/ * html .clearfix {height: 1%;} .clearfix {display: block;} /* End hide from IE-mac */ /* Hides from IE-mac \*/ * html .clearfix {height: 1%;} .clearfix {display: block;} /* End hide from IE-mac */

View File

@ -0,0 +1,39 @@
$:render.header(_('About'))
<div class="panel" style="text-align:left">
<h2>Version</h2>
<pre>$version </pre>
<h2>Links</h2>
<ul>
<li><a href="http://deluge-torrent.org">Deluge</a></li>
<li><a href="http://forum.deluge-torrent.org/viewtopic.php?f=9&t=425">
WebUi forum Thread</a>
</li>
<li><a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GPL v2
</a></li>
</ul>
<h2>Authors</h2>
<ul>
<h3>WebUi</h3>
<ul>
<li>Martijn Voncken</li>
</ul>
<h3>Template</h3>
<ul>
<li>Martijn Voncken</li>
<li>somedude</li>
</ul>
<h3>Deluge</h3>
<ul>
<li>Zach Tibbitts</li>
<li>Alon Zakai</li>
<li>Alon Zakai</li>
<li>Marcos Pinto</li>
<li>Andrew Resch</li>
<li>Alex Dedul</li>
</ul>
</ul>
*and all other authors/helpers/contributors I forgot to mention.
</div>
$:render.footer()

View File

@ -1,6 +1,6 @@
$def with (error_msg) $def with (error_msg)
$:header(_('Error')) $:render.header(_('Error'))
<pre class="error"> <pre class="error">
$error_msg $error_msg
</pre> </pre>
$:footer() $:render.footer()

View File

@ -1,15 +1,13 @@
$def with (title) $def with (title)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html> <html>
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Deluge:$title</title> <title>Deluge:$title</title>
<link rel="icon" href="/static/images/deluge_icon.gif" type="image/gif" /> <link rel="icon" href="/static/images/deluge_icon.gif" type="image/gif" />
<link rel="shortcut icon" href="/static/images/deluge_icon.gif" type="image/gif" /> <link rel="shortcut icon" href="/static/images/deluge_icon.gif" type="image/gif" />
<link rel="stylesheet" type="text/css" href="/static/simple_site_style.css" /> <link rel="stylesheet" type="text/css" href="/static/simple_site_style.css" />
</head> </head>
<body> <body>
<div id="page"> <div id="page">

View File

@ -54,5 +54,4 @@ $:render.part_button('POST', '/resume_all', _('Resume all'), 'tango/media-playba
$:render.part_refresh() $:render.part_refresh()
$:render.footer() $:render.footer()

View File

@ -1,13 +1,13 @@
$def with (error)
$:render.header(_('Login')) $:render.header(_('Login'))
<div class="panel"> <div class="panel">
$if error > 0:
<div class="error">$_("Password is invalid,try again")</div>
<form method="POST" id="loginform" action='/login'> <form method="POST" id="loginform" action='/login'>
<div id="loginpanel"> <div id="loginpanel">
<div class="form_row"> <div class="form_row">
<span class="form_label">$_('User')</span> <span class="form_label">$_('Password')</span>
<input type="text" name="user" id="user" class="form_input">
</div>
<div class="form_row">
<span class="form_label">$_('Pass')</span>
<input type="password" name="pwd" id="pwd" class="form_input"> <input type="password" name="pwd" id="pwd" class="form_input">
</div> </div>
<div class="form_row"> <div class="form_row">
@ -15,6 +15,9 @@ $:render.header(_('Login'))
<input type="submit" name="submit" <input type="submit" name="submit"
id="submit" value="Submit" class="form_input"> id="submit" value="Submit" class="form_input">
</div> </div>
<br />
<a href="/about">$_('About')</a>
</div> </div>
</form> </form>
</div> </div>

View File

@ -3,11 +3,20 @@ $def with (method, url, title, image='')
<form method="$method" action="$url" class="deluge_button"> <form method="$method" action="$url" class="deluge_button">
<button type="submit" class="deluge_button"> <button type="submit" class="deluge_button">
<input type="hidden" name="redir" value="$self_url()"> <input type="hidden" name="redir" value="$self_url()">
$if image: $if (button_style == 0):
<image src="/static/images/$image" class="button"/> $title
$else: $if image:
<!--no image--> <image src="/static/images/$image" class="button" alt="$title"/>
$title
$if (button_style == 1):
$if image:
<image src="/static/images/$image" class="button" alt="$title"/>
$else:
$title
$if (button_style == 2):
$title
</button> </button>
</form> </form>
</div> </div>

View File

@ -1,5 +1,5 @@
<div class="panel"> <div id='refresh_panel'>
<div id='refresh'> <div class="panel" >
$_('Auto refresh:') $_('Auto refresh:')
$if get_config('auto_refresh'): $if get_config('auto_refresh'):
($(get_config('refresh')) $_('seconds')) &nbsp; ($(get_config('refresh')) $_('seconds')) &nbsp;

View File

@ -3,7 +3,7 @@ $:render.header(_('Set Timeout'))
<form action="/refresh/set" method="POST"> <form action="/refresh/set" method="POST">
$_('Refresh page every:') $_('Refresh page every:')
<input type="text" name="refresh" value="$get_config('refresh')" size="3"> <input type="text" name="refresh" value="$get_config('refresh')" size="3">
$_('Seconds') $_('seconds')
<input type="submit" value="$_('Set')"> <input type="submit" value="$_('Set')">
</form> </form>
</div> </div>

View File

@ -80,17 +80,7 @@ class="deluge_button">
name="$torrent.action" value="$torrent.id"> name="$torrent.action" value="$torrent.id">
</form> </form>
<div class="deluge_button"> $:render.part_button('GET', '/torrent/delete/' + str(torrent.id), _('Remove'), 'tango/user-trash.png')
<form method="GET" action="/torrent/delete/$torrent.id" class="deluge_button">
<button type="submit" class="deluge_button">
<image src="/static/images/tango/user-trash.png" /> $_('Delete')
</button>
</form>
</div>
</form>
<br> <br>
[<a onclick="javascript:toggle_dump()">$_('Debug:Data Dump')</a>] [<a onclick="javascript:toggle_dump()">$_('Debug:Data Dump')</a>]

View File

@ -10,16 +10,21 @@ Or use scite and my config: http://mvoncken.sohosted.com/deluge/SciTEUser.proper
template language: http://webpy.org/templetor template language: http://webpy.org/templetor
Exposed methods and variables (c&p from deluge_webserver): Exposed methods and variables (c&p from deluge_webserver):
'sort_head': template_sort_head,
template.Template.globals['crop'] = template_crop 'crop': template_crop,
template.Template.globals['fspeed'] = common.fspeed '_': _ , #gettext/translations
template.Template.globals['fsize'] = common.fsize 'str': str, #because % in templetor is broken.
template.Template.globals['sorted'] = sorted 'sorted': sorted,
template.Template.globals['_'] = _ #gettext/translations 'get_config': proxy.get_webui_config,
template.Template.globals['deluge_web_version'] = '0.3alfa' 'self_url': web.changequery,
template.Template.globals['render'] = render #for easy resuse of templates 'fspeed': common.fspeed,
template.Template.globals['sort_head'] = sort_head 'fsize': common.fsize,
template.Template.globals['get_config'] = proxy.get_webui_config '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())
I will update this file if there is interest in making templates. I will update this file if there is interest in making templates.

View File

@ -1,5 +1 @@
revision-id: mvoncken@gmail.com-20070923193628-omqar5yaxatdmfu0 48
date: 2007-09-23 21:36:28 +0200
build-date: 2007-09-23 21:54:09 +0200
revno: 30
branch-nick: WebUi

View File

@ -1,6 +1,10 @@
Commented out some code to enable a relative redirect. 1:Commented out some code to enable a relative redirect.
This is not according to HTTP/1.1 Spec This is not according to HTTP/1.1 Spec
But many deluge users will want to route the webui through firewalls/routers or use apache redirects. But many deluge users will want to route the webui through firewalls/routers or use apache redirects.
2:Disabled logging in the builtin http-server.

View File

@ -6,11 +6,11 @@ import net
def runbasic(func, server_address=("0.0.0.0", 8080)): def runbasic(func, server_address=("0.0.0.0", 8080)):
""" """
Runs a simple HTTP server hosting WSGI app `func`. The directory `static/` Runs a simple HTTP server hosting WSGI app `func`. The directory `static/`
is hosted statically. is hosted statically.
Based on [WsgiServer][ws] from [Colin Stewart][cs]. Based on [WsgiServer][ws] from [Colin Stewart][cs].
[ws]: http://www.owlfish.com/software/wsgiutils/documentation/wsgi-server-api.html [ws]: http://www.owlfish.com/software/wsgiutils/documentation/wsgi-server-api.html
[cs]: http://www.owlfish.com/ [cs]: http://www.owlfish.com/
""" """
@ -62,17 +62,17 @@ def runbasic(func, server_address=("0.0.0.0", 8080)):
try: try:
try: try:
for data in result: for data in result:
if data: if data:
self.wsgi_write_data(data) self.wsgi_write_data(data)
finally: finally:
if hasattr(result, 'close'): if hasattr(result, 'close'):
result.close() result.close()
except socket.error, socket_err: except socket.error, socket_err:
# Catch common network errors and suppress them # Catch common network errors and suppress them
if (socket_err.args[0] in \ if (socket_err.args[0] in \
(errno.ECONNABORTED, errno.EPIPE)): (errno.ECONNABORTED, errno.EPIPE)):
return return
except socket.timeout, socket_timeout: except socket.timeout, socket_timeout:
return return
except: except:
print >> web.debug, traceback.format_exc(), print >> web.debug, traceback.format_exc(),
@ -92,7 +92,7 @@ def runbasic(func, server_address=("0.0.0.0", 8080)):
else: else:
self.run_wsgi_app() self.run_wsgi_app()
def wsgi_start_response(self, response_status, response_headers, def wsgi_start_response(self, response_status, response_headers,
exc_info=None): exc_info=None):
if (self.wsgi_sent_headers): if (self.wsgi_sent_headers):
raise Exception \ raise Exception \
@ -117,8 +117,8 @@ def runbasic(func, server_address=("0.0.0.0", 8080)):
class WSGIServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): class WSGIServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
def __init__(self, func, server_address): def __init__(self, func, server_address):
BaseHTTPServer.HTTPServer.__init__(self, BaseHTTPServer.HTTPServer.__init__(self,
server_address, server_address,
WSGIHandler) WSGIHandler)
self.app = func self.app = func
self.serverShuttingDown = 0 self.serverShuttingDown = 0
@ -128,7 +128,7 @@ def runbasic(func, server_address=("0.0.0.0", 8080)):
def runsimple(func, server_address=("0.0.0.0", 8080)): def runsimple(func, server_address=("0.0.0.0", 8080)):
""" """
Runs [CherryPy][cp] WSGI server hosting WSGI app `func`. Runs [CherryPy][cp] WSGI server hosting WSGI app `func`.
The directory `static/` is hosted statically. The directory `static/` is hosted statically.
[cp]: http://www.cherrypy.org [cp]: http://www.cherrypy.org
@ -180,7 +180,7 @@ def runsimple(func, server_address=("0.0.0.0", 8080)):
else: else:
value = self.wfile.getvalue() value = self.wfile.getvalue()
yield value yield value
class WSGIWrapper(BaseHTTPRequestHandler): class WSGIWrapper(BaseHTTPRequestHandler):
"""WSGI wrapper for logging the status and serving static files.""" """WSGI wrapper for logging the status and serving static files."""
def __init__(self, app): def __init__(self, app):
@ -200,20 +200,23 @@ def runsimple(func, server_address=("0.0.0.0", 8080)):
return self.app(environ, xstart_response) return self.app(environ, xstart_response)
def log(self, status, environ): def log(self, status, environ):
#mvoncken,no logging..
return
outfile = environ.get('wsgi.errors', web.debug) outfile = environ.get('wsgi.errors', web.debug)
req = environ.get('PATH_INFO', '_') req = environ.get('PATH_INFO', '_')
protocol = environ.get('ACTUAL_SERVER_PROTOCOL', '-') protocol = environ.get('ACTUAL_SERVER_PROTOCOL', '-')
method = environ.get('REQUEST_METHOD', '-') method = environ.get('REQUEST_METHOD', '-')
host = "%s:%s" % (environ.get('REMOTE_ADDR','-'), host = "%s:%s" % (environ.get('REMOTE_ADDR','-'),
environ.get('REMOTE_PORT','-')) environ.get('REMOTE_PORT','-'))
#@@ It is really bad to extend from #@@ It is really bad to extend from
#@@ BaseHTTPRequestHandler just for this method #@@ BaseHTTPRequestHandler just for this method
time = self.log_date_time_string() time = self.log_date_time_string()
print >> outfile, self.format % (host, time, protocol, print >> outfile, self.format % (host, time, protocol,
method, req, status) method, req, status)
func = WSGIWrapper(func) func = WSGIWrapper(func)
server = CherryPyWSGIServer(server_address, func, server_name="localhost") server = CherryPyWSGIServer(server_address, func, server_name="localhost")