Browse Source

Implement "optional" field for servers.

Optional penalty timeout for unresponsive servers.
Refer to new V2 Wiki pages for Config->Scheduling and Config->Servers.
Closes #223 for trunk.
tags/0.6.0
shypike 16 years ago
parent
commit
0c77dff305
  1. 18
      main/interfaces/Default/templates/config_scheduling.tmpl
  2. 4
      main/interfaces/Default/templates/config_server.tmpl
  3. 36
      main/interfaces/Plush/templates/config_scheduling.tmpl
  4. 46
      main/interfaces/Plush/templates/config_server.tmpl
  5. 2
      main/interfaces/prototype/templates/config_scheduling.tmpl
  6. 10
      main/interfaces/prototype/templates/config_server.tmpl
  7. 2
      main/interfaces/smpl/templates/config_scheduling.tmpl
  8. 10
      main/interfaces/smpl/templates/config_server.tmpl
  9. 43
      main/sabnzbd/downloader.py
  10. 27
      main/sabnzbd/scheduler.py

18
main/interfaces/Default/templates/config_scheduling.tmpl

@ -1,6 +1,6 @@
<!--#set global $topmenu="config"#-->
<!--#set global $statpath="../.."#-->
<!--#set global $helpsubject="Configure+Scheduling"#-->
<!--#set global $helpsubject="Configure+Scheduling+V2"#-->
<!--#include $webdir + "/inc_top.tmpl"#-->
<!--#set global $submenu="scheduling"#-->
@ -41,13 +41,13 @@ Hour:<br>
<option value="6">Saturdays
<option value="7">Sundays
</select>
<br>Action:<br>
<br>Action:<br>
<select name="action">
<!--#for $action in $actions#-->
<option value="$action">$action
<!--#end for#-->
</select>
<br>Arguments:<br>
<br>Arguments:<br>
<input type="text" size="20" name="arguments" value="">
<p><input type="submit" value="Add Schedule"></p>
</fieldset>
@ -60,7 +60,7 @@ Hour:<br>
<form action="delSchedule" method="post">
<fieldset class="EntryFieldSet">
<!--#set $schednum = $schednum+1#-->
<%
<%
m, h, day, action = line.split(' ', 3)
if len(m) == 1:
m = '0%s' % m
@ -69,17 +69,17 @@ if day == "*":
elif day == "1":
day='Monday'
elif day == "2":
day='Tuesday'
day='Tuesday'
elif day == "3":
day='Wednesday'
day='Wednesday'
elif day == "4":
day='Thursday'
day='Thursday'
elif day == "5":
day='Friday'
elif day == "6":
day='Saturday'
day='Saturday'
elif day == "7":
day='Sunday'
day='Sunday'
%>
Task $schednum: <strong>$h:$m</strong> - $day - $action
<input type="hidden" name="line" value="$line">

4
main/interfaces/Default/templates/config_server.tmpl

@ -1,6 +1,6 @@
<!--#set global $topmenu="config"#-->
<!--#set global $statpath="../.."#-->
<!--#set global $helpsubject="Configure+Servers"#-->
<!--#set global $helpsubject="Configure+Servers+V2"#-->
<!--#include $webdir + "/inc_top.tmpl"#-->
<!--#set global $submenu="servers"#-->
@ -23,6 +23,7 @@
<input type="checkbox" name="ssl" value="1" <!--#if int($have_ssl) == 0 then "disabled" else ""#-->>&nbsp;SSL<br/>
<!--#end if#-->
<input type="checkbox" name="fillserver" value="1">&nbsp;Backup server<br>
<input type="checkbox" name="optional" value="1">&nbsp;Optional<br>
<input type="checkbox" name="enable" value="1" checked="1">&nbsp;Enable<br>
<p><input type="submit" value="Add Server"></p>
</fieldset>
@ -45,6 +46,7 @@
<input type="checkbox" name="ssl" value="1" <!--#if int($servers[$server]['ssl']) != 0 then "checked=1" else ""#-->/>&nbsp;SSL<br/>
<!--#end if#-->
<input type="checkbox" name="fillserver" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> />&nbsp;Backup server<br/>
<input type="checkbox" name="optional" value="1" <!--#if int($servers[$server]['optional']) != 0 then "checked=1" else ""#--> />&nbsp;Optional<br/>
<input type="checkbox" name="enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then "checked=1" else ""#--> />&nbsp;Enable<br/>
<input type="hidden" name="server" value="$server">
<p><input type="submit" value="Save Changes"></p>

36
main/interfaces/Plush/templates/config_scheduling.tmpl

@ -1,11 +1,11 @@
<!--#set global $pane="Scheduling"#-->
<!--#set global $help_uri="Configure+Scheduling"#-->
<!--#set global $help_uri="Configure+Scheduling+V2"#-->
<!--#include $webdir + "/config_inc_header.tmpl"#-->
<div class="EntryBlock">
<form action="addSchedule" method="post">
<fieldset class="EntryFieldSet">
<legend id="configbox_add_schedule">Add&nbsp;Schedule</legend>
<%import time
t = time.localtime()
@ -29,7 +29,7 @@ else:
<!--#end for#-->
</select>
</td></tr>
<tr><td align=right>
<div class="sucker">Frequency:</div>
</td><td>
@ -44,7 +44,7 @@ else:
<option value="7">Sundays</option>
</select>
</td></tr>
<tr><td align=right>
<div class="sucker">Action:</div>
</td><td>
@ -54,26 +54,26 @@ else:
<!--#end for#-->
</select>
</td></tr>
<tr><td align=right>
<div class="sucker">Arguments:</div>
</td><td>
<input type="text" size="20" name="arguments" value=""/>
</td></tr>
<tr><td>
</td><td>
<br/><input type="submit" value="Add"/>
</td></tr>
</table>
</fieldset>
</form>
</div>
<!--#if $schedlines#-->
<div class="EntryBlock">
<fieldset class="EntryFieldSet">
@ -82,7 +82,7 @@ else:
<!--#set $schednum = 0#-->
<!--#for $line in $schedlines#-->
<!--#set $schednum = $schednum+1#-->
<%
<%
m, h, day, action = line.split(' ', 3)
if len(m) == 1:
m = '0%s' % m
@ -91,17 +91,17 @@ if day == "*":
elif day == "1":
day='Monday'
elif day == "2":
day='Tuesday'
day='Tuesday'
elif day == "3":
day='Wednesday'
day='Wednesday'
elif day == "4":
day='Thursday'
day='Thursday'
elif day == "5":
day='Friday'
elif day == "6":
day='Saturday'
day='Saturday'
elif day == "7":
day='Sunday'
day='Sunday'
%>
<form action="delSchedule" method="post">
<input type="hidden" name="line" value="$line"/>
@ -112,7 +112,7 @@ elif day == "7":
<td>$action</td>
</tr>
</form>
<!--#end for#-->
</table>
</fieldset>

46
main/interfaces/Plush/templates/config_server.tmpl

@ -1,14 +1,14 @@
<!--#set global $pane="Servers"#-->
<!--#set global $help_uri="Configure+Servers"#-->
<!--#set global $help_uri="Configure+Servers+V2"#-->
<!--#include $webdir + "/config_inc_header.tmpl"#-->
<div class="EntryBlock">
<form action="addServer" method="post">
<fieldset class="EntryFieldSet">
<legend id="configbox_add_server">Add&nbsp;Usenet&nbsp;Server</legend>
<table cellpadding=2>
<tr><td align="right"><div class="sucker">Host / IP:</div></td><td><input type="text" size="25" name="host"/></td></tr>
<tr><td align="right"><div class="sucker">Port:</div></td><td><input type="text" size="10" name="port"/></td></tr>
@ -16,13 +16,13 @@
<tr><td align="right"><div class="sucker">Username:</div></td><td><input type="text" size="25" name="username"/></td></tr>
<tr><td align="right"><div class="sucker">Password:</div></td><td><input type="password" size="25" name="password"/></td></tr>
</table>
<br/>
<table>
<tr><td align="right"><div class="sucker">#&nbsp;Connections:</div></td><td><input type="text" size="5" name="connections"/></td></tr>
<tr><td align="right"><div class="sucker">Timeout:</div></td><td><input type="text" size="5" name="timeout" value="120">&nbsp;<small>seconds</small></td></tr>
<td><td colspan="2">&nbsp;</td></tr>
<tr>
@ -37,14 +37,18 @@
<td align="right"><input type="checkbox" name="fillserver" id="fillserver" value="1"/></td>
<td><label for="fillserver"><strong>Backup&nbsp;Server</strong></label></td>
</tr>
<tr>
<td align="right"><input type="checkbox" name="optional" id="optional" value="1"/></td>
<td><label for="optional"><strong>Optional</strong></label></td>
</tr>
<tr><td></td><td><br/><input type="submit" value="Add"/></td></tr>
</table>
</fieldset>
</form>
<!--#set $slist = $servers.keys()#-->
<!--#$slist.sort()#-->
<!--#set $cur = 0#-->
@ -52,9 +56,9 @@
<!--#set $cur = $cur + 1#-->
<form action="saveServer" method="post">
<fieldset class="EntryFieldSet">
<legend id="<!--#if int($servers[$server]['ssl']) != 0 and int($have_ssl) == 1#-->configbox_server_encrypted<!--#else#-->configbox_server_decrypted<!--#end if#-->">$server</legend>
<table cellpadding=2>
<tr><td align="right"><div class="sucker">Host / IP:</div></td><td><input type="text" size="25" name="host" value="$servers[$server]['host']"/></td></tr>
<tr><td align="right"><div class="sucker">Port:</div></td><td><input type="text" size="10" name="port" value="$servers[$server]['port']"/></td></tr>
@ -62,9 +66,9 @@
<tr><td align="right"><div class="sucker">Username:</div></td><td><input type="text" size="25" name="username" value="$servers[$server]['username']"/></td></tr>
<tr><td align="right"><div class="sucker">Password:</div></td><td><input type="password" size="25" name="password" value="$servers[$server]['password']"/></td></tr>
</table>
<br/>
<table>
<tr>
<td align="right"><div class="sucker">#&nbsp;Connections:</div></td>
@ -87,19 +91,23 @@
<td align="right"><input type="checkbox" name="fillserver" id="fillserver$cur" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> /></td>
<td><label for="fillserver$cur"><strong>Backup&nbsp;Server</strong></label></td>
</tr>
<tr>
<td align="right"><input type="checkbox" name="optional" id="optional$cur" value="1" <!--#if int($servers[$server]['optional']) != 0 then "checked=1" else ""#--> /></td>
<td><label for="optional$cur"><strong>Optional&nbsp;Server</strong></label></td>
</tr>
<tr><td></td><td>
<br/><input type="hidden" name="server" value="$server"/>
<input type="submit" value="Save"/>
<input type="button" value="X"/>
</td></tr>
</table>
</fieldset>
</form>
<!--#end for#-->
</div>
<!--#include $webdir + "/config_inc_footer.tmpl"#-->

2
main/interfaces/prototype/templates/config_scheduling.tmpl

@ -1,5 +1,5 @@
<div id="formPanel">
<a href="${helpuri}Configure+Scheduling" id="help">Help</a><h3>Scheduling configuration</h3>
<a href="${helpuri}Configure+Scheduling+V2" id="help">Help</a><h3>Scheduling configuration</h3>
<br class="clear" />
<div class="EntryBlock">
<form class="cmxform" id="schedule">

10
main/interfaces/prototype/templates/config_server.tmpl

@ -1,5 +1,5 @@
<div id="formPanel">
<a href="${helpuri}Configure+Servers" id="help">Help</a><h3>Server configuration</h3>
<a href="${helpuri}Configure+Servers+V2" id="help">Help</a><h3>Server configuration</h3>
<div class="EntryBlock">
<br class="clear"/>
<!--#set $slist = $servers.keys()#-->
@ -32,6 +32,10 @@
<input class="radio" type="checkbox" name="fillserver" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> /></label>
</label><br class="clear" />
<label><span class="label">Optional:</span>
<input class="radio" type="checkbox" name="optional" value="1" <!--#if int($servers[$server]['optional']) != 0 then "checked=1" else ""#--> /></label>
</label><br class="clear" />
<label><span class="label">Enable:</span>
<input class="radio" type="checkbox" name="enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then "checked=1" else ""#--> /></label>
<input type="hidden" name="server" value="$server"><br class="clear" />
@ -78,6 +82,10 @@
<input class="radio" type="checkbox" name="fillserver" value="1"></label>
<br class="clear" />
<label><span class="label">Optional:</span>
<input class="radio" type="checkbox" name="optional" value="1"></label>
<br class="clear" />
<label><span class="label">Enable:</span>
<input class="radio" type="checkbox" name="enable" value="1"></label>
<br class="clear" />

2
main/interfaces/smpl/templates/config_scheduling.tmpl

@ -1,4 +1,4 @@
<a href="${helpuri}Configure+Scheduling" id="help">Help</a><h3>Scheduling configuration</h3>
<a href="${helpuri}Configure+Scheduling+V2" id="help">Help</a><h3>Scheduling configuration</h3>
<div class="EntryBlock">
<form class="cmxform" id="schedule">
<fieldset class="EntryFieldSet">

10
main/interfaces/smpl/templates/config_server.tmpl

@ -1,5 +1,5 @@
<a href="${helpuri}Configure+Servers" id="help">Help</a><h3>Server configuration</h3>
<a href="${helpuri}Configure+Servers+V2" id="help">Help</a><h3>Server configuration</h3>
<div class="EntryBlock">
<!--#set $slist = $servers.keys()#-->
<!--#$slist.sort()#-->
@ -30,6 +30,10 @@
<input class="radio" type="checkbox" name="fillserver" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> /></label>
</label><br class="clear" />
<label><span class="label">Optional:</span>
<input class="radio" type="checkbox" name="optional" value="1" <!--#if int($servers[$server]['optional']) != 0 then "checked=1" else ""#--> /></label>
</label><br class="clear" />
<label><span class="label">Enable:</span>
<input class="radio" type="checkbox" name="enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then "checked=1" else ""#--> /></label>
<br class="clear" />
@ -77,6 +81,10 @@
<input class="radio" type="checkbox" name="fillserver" value="1"></label>
<br class="clear" />
<label><span class="label">Optional:</span>
<input class="radio" type="checkbox" name="optional" value="1"></label>
<br class="clear" />
<label><span class="label">Enable:</span>
<input class="radio" type="checkbox" name="enable" value="1" checked="1"></label>
<br class="clear" />

43
main/sabnzbd/downloader.py

@ -34,9 +34,17 @@ from sabnzbd.constants import *
import sabnzbd.config as config
import sabnzbd.cfg as cfg
import sabnzbd.bpsmeter as bpsmeter
import sabnzbd.scheduler
import sabnzbd.nzbqueue
#------------------------------------------------------------------------------
# Timeout penalty in minutes for each cause
_PENALTY_UNKNOWN = 3
_PENALTY_502 = 5
_PENALTY_TIMEOUT = 10
_PENALTY_SHARE = 15
#------------------------------------------------------------------------------
# Wrapper functions
__DOWNLOADER = None # Global pointer to post-proc instance
@ -175,6 +183,7 @@ class Server:
self.busy_threads = []
self.idle_threads = []
self.active = True
self.bad_cons = 0
for i in range(threads):
self.idle_threads.append(NewsWrapper(self, i+1))
@ -241,6 +250,7 @@ class Downloader(Thread):
""" Setup or re-setup single server
When oldserver is defined and in use, delay startup.
Return True when newserver is primary
Note that the server names are "host:port" strings!
"""
primary = False
@ -342,6 +352,13 @@ class Downloader(Thread):
self.__reset_nw(nw, "", warn=False)
else:
self.__reset_nw(nw, "timed out")
server.bad_cons += 1
if server.optional and server.active and (server.bad_cons/server.threads) > 3:
server.bad_cons = 0
server.active = False
self.init_server(server.id, None)
logging.warning('Server %s will be ignored for %s minutes', server.id, _PENALTY_TIMEOUT)
sabnzbd.scheduler.plan_server(self.init_server, [None, server.id], _PENALTY_TIMEOUT)
if server.restart:
if not server.busy_threads:
@ -519,6 +536,7 @@ class Downloader(Thread):
except NNTPPermanentError, error:
# Handle login problems
block = False
penalty = 0
msg = error.response
ecode = msg[:3]
if ecode in ('481', '482', '381') or (ecode == '502' and clues_login(msg)):
@ -531,19 +549,26 @@ class Downloader(Thread):
logging.error('Too many connections to server %s:%s', server.host, server.port)
self.__reset_nw(nw, None, warn=False, destroy=True)
server.threads -= 1
elif (ecode == '502') and clues_too_many_ip(msg):
# Account sharing?
logging.info("Probable account sharing")
penalty = _PENALTY_SHARE
elif ecode == '502':
# Cannot connect (other reasons), block this server
if server.active:
logging.error('Cannot connect to server %s:%s [%s]', server.host, server.port, msg)
block = True
logging.warning('Cannot connect to server %s:%s [%s]', server.host, server.port, msg)
penalty = _PENALTY_502
else:
# Unknown error, just keep trying
# In the future we will give this server a penalty timeout
logging.error('Cannot connect to server %s:%s [%s]', server.host, server.port, msg)
if block:
penalty = _PENALTY_UNKNOWN
if block or (penalty and server.optional):
if server.active:
server.active = False
self.init_server(server, None)
if penalty and server.optional:
logging.info('Server %s ignored for %s minutes', server.id, penalty)
sabnzbd.scheduler.plan_server(self.init_server, [None, server.id], penalty)
self.__reset_nw(nw, None, warn=False)
continue
except:
@ -688,3 +713,13 @@ def clues_too_many(text):
if text.find(clue) >= 0:
return True
return False
def clues_too_many_ip(text):
""" Check for any "account sharing" clues in the response code
"""
text = text.lower()
for clue in ('simultaneous ip'):
if text.find(clue) >= 0:
return True
return False

27
main/sabnzbd/scheduler.py

@ -28,7 +28,7 @@ import time
import sabnzbd.utils.kronos as kronos
import sabnzbd.rss as rss
import sabnzbd.newzbin as newzbin
import sabnzbd.downloader as downloader
import sabnzbd.downloader
import sabnzbd.misc
import sabnzbd.config as config
import sabnzbd.cfg as cfg
@ -80,7 +80,7 @@ def init():
action = scheduled_resume
arguments = []
elif action_name == 'pause':
action = downloader.pause_downloader
action = sabnzbd.downloader.pause_downloader
arguments = []
elif action_name == 'shutdown':
action = sabnzbd.shutdown_program
@ -89,7 +89,7 @@ def init():
action = sabnzbd.restart_program
arguments = []
elif action_name == 'speedlimit' and arguments != []:
action = downloader.limit_speed
action = sabnzbd.downloader.limit_speed
elif action_name == 'enable_server' and arguments != []:
action = sabnzbd.enable_server
elif action_name == 'disable_server' and arguments != []:
@ -155,7 +155,7 @@ def restart(force=False):
SCHEDULE_GUARD_FLAG = False
stop()
analyse(downloader.paused())
analyse(sabnzbd.downloader.paused())
init()
start()
@ -255,9 +255,9 @@ def analyse(was_paused=False):
logging.warning('Schedule for non-existing server %s', value)
if not was_paused:
downloader.set_paused(paused)
sabnzbd.downloader.set_paused(paused)
if speedlimit:
downloader.limit_speed(speedlimit)
sabnzbd.downloader.limit_speed(speedlimit)
for serv in servers:
try:
config.get_config('servers', serv).enable.set(servers[serv])
@ -276,7 +276,7 @@ def scheduled_resume():
"""
global __PAUSE_END
if __PAUSE_END == None:
downloader.resume_downloader()
sabnzbd.downloader.resume_downloader()
def __oneshot_resume(when):
@ -287,7 +287,7 @@ def __oneshot_resume(when):
if __PAUSE_END != None and (when > __PAUSE_END-5) and (when < __PAUSE_END+55):
__PAUSE_END = None
logging.debug('Resume after pause-interval')
downloader.resume_downloader()
sabnzbd.downloader.resume_downloader()
else:
logging.debug('Ignoring cancelled resume')
@ -300,10 +300,10 @@ def plan_resume(interval):
__PAUSE_END = time.time() + (interval * 60)
logging.debug('Schedule resume at %s', __PAUSE_END)
__SCHED.add_single_task(__oneshot_resume, '', interval*60, kronos.method.sequential, [__PAUSE_END], None)
downloader.pause_downloader()
sabnzbd.downloader.pause_downloader()
else:
__PAUSE_END = None
downloader.resume_downloader()
sabnzbd.downloader.resume_downloader()
def pause_int():
@ -316,3 +316,10 @@ def pause_int():
min = int(val / 60L)
sec = int(val - min*60)
return "%d:%02d" % (min, sec)
#------------------------------------------------------------------------------
def plan_server(action, parms, penalty):
""" Plan to re-activate server after "penalty" minutes
"""
__SCHED.add_single_task(action, '', penalty*60, kronos.method.sequential, parms, None)

Loading…
Cancel
Save