Browse Source

Improve handling of blocked servers.

- Detection improved
- Blocking reason is shown
- A de-block button is offered (implementation in smpl does not work now!)
- Prevent double server entries in Connections page

Improve implementation of API call "set_config".

De []<==>{} conversion of IPV6-IPs only for the INI file.
tags/0.6.0
shypike 16 years ago
parent
commit
ff7e09a467
  1. 6
      main/interfaces/Default/templates/connection_info.tmpl
  2. 6
      main/interfaces/Plush/templates/connection_info.tmpl
  3. 7
      main/interfaces/smpl/templates/connection_info.tmpl
  4. 5
      main/interfaces/smpl/templates/main.tmpl
  5. 8
      main/language/fr-fr.txt
  6. 10
      main/language/nl-du.txt
  7. 10
      main/language/us-en.txt
  8. 9
      main/sabnzbd/config.py
  9. 92
      main/sabnzbd/downloader.py
  10. 51
      main/sabnzbd/interface.py
  11. 6
      main/sabnzbd/scheduler.py

6
main/interfaces/Default/templates/connection_info.tmpl

@ -23,7 +23,11 @@ $T('logging'):
<ul> <ul>
<!--#for $server in $servers#--> <!--#for $server in $servers#-->
<li> <li>
$server[0]:$server[1]: $server[2]<!--#if not $server[5]#--> ($T('server-blocked'))<!--#end if#--> $server[0]:$server[1]: $server[2]
<!--#if not $server[5]#-->
<a href="./unblock_server?server=$server[0]:$server[1]&session=$session">($T('server-blocked'))</a>
&nbsp;&nbsp;$server[6]
<!--#end if#-->
<ul> <ul>
<!--#for $thrd in $server[3]#--> <!--#for $thrd in $server[3]#-->
<li>$T('thread') #$thrd[0] -&gt; $thrd[1] -&gt; $thrd[2] -&gt; $thrd[3]</li> <li>$T('thread') #$thrd[0] -&gt; $thrd[1] -&gt; $thrd[2] -&gt; $thrd[3]</li>

6
main/interfaces/Plush/templates/connection_info.tmpl

@ -17,7 +17,11 @@
<!--#if $servers#--> <!--#if $servers#-->
<!--#for $server in $servers#--> <!--#for $server in $servers#-->
<fieldset class="EntryFieldSet"> <fieldset class="EntryFieldSet">
<legend id="<!--#if int($server[4])#-->configbox_server_encrypted<!--#else#-->configbox_server_decrypted<!--#end if#-->">$server[0]:$server[1]:$server[2]<!--#if not $server[5]#--> ($T('server-blocked'))<!--#end if#--> <legend id="<!--#if int($server[4])#-->configbox_server_encrypted<!--#else#-->configbox_server_decrypted<!--#end if#-->">$server[0]:$server[1]:$server[2]
<!--#if not $server[5]#-->
<a href="./unblock_server?server=$server[0]:$server[1]&session=$session">($T('server-blocked'))</a>
&nbsp;&nbsp;$server[6]
<!--#end if#-->
</legend> </legend>
<small><!--#if $server[3]#--><ol class="numbered_list"> <small><!--#if $server[3]#--><ol class="numbered_list">
<!--#for $thrd in $server[3]#--> <!--#for $thrd in $server[3]#-->

7
main/interfaces/smpl/templates/connection_info.tmpl

@ -15,7 +15,12 @@ $T('logging'):
<!--#for $server in $servers#--> <!--#for $server in $servers#-->
<li> <li>
$server[0]:$server[1]: $server[2] <!--#if int($server[4])#--><img src="static/images/nuvola/kgpg.png" /><!--#end if#--> $server[0]:$server[1]: $server[2] <!--#if int($server[4])#--><img src="static/images/nuvola/kgpg.png" /><!--#end if#-->
<!--#if not $server[5]#--> ($T('server-blocked'))<!--#end if#--> <!--#if not $server[5]#-->
<!--#set $srv_id= "unblock_server('" + $server[0] + "','" + str($server[1]) + "');"#-->
<a class="config" onClick="$srv_id">
($T('server-blocked'))</a>
&nbsp;&nbsp;$server[6]
<!--#end if#-->
<ul> <ul>
<!--#for $thrd in $server[3]#--> <!--#for $thrd in $server[3]#-->

5
main/interfaces/smpl/templates/main.tmpl

@ -711,6 +711,11 @@ function loadtitle() {
d.addErrback(handleServerError); d.addErrback(handleServerError);
} }
function unblock_server(host, port)
{
d = doSimpleXMLHttpRequest('connections/unblock_server?server='+host+':'+port+'&session='+session);
}
function getBookmarks() function getBookmarks()
{ {
d = doSimpleXMLHttpRequest('tapi?mode=newzbin&name=get_bookmarks&session='+session); d = doSimpleXMLHttpRequest('tapi?mode=newzbin&name=get_bookmarks&session='+session);

8
main/language/fr-fr.txt

@ -586,12 +586,14 @@ warn-noRead@1 Ne peut lire %s
error-except Exception ? error-except Exception ?
error-noInit@3 Echec de l'initialisation %s@%s:%s error-noInit@3 Echec de l'initialisation %s@%s:%s
error-serverFailed@4 Echec de la connexion à %s@%s:%s, message=%s error-serverFailed@4 Echec de la connexion à %s@%s:%s, message=%s
error-serverLogin@2 Echec de la connexion au serveur %s:%s error-serverLogin@1 Echec de la connexion au serveur %s
error-serverNoConn@3 Ne peut se connecter au serveur %s:%s [%s] error-serverNoConn@2 Ne peut se connecter au serveur %s [%s]
error-serverTooMany@2 Trop de connexions au serveur %s:%s error-serverTooMany@2 Trop de connexions au serveur %s:%s
warn-ignoreServer@2 Le serveur %s sera ignoré pendant %s minutes warn-ignoreServer@2 Le serveur %s sera ignoré pendant %s minutes
warn-noActiveServers Aucun serveur primaire défini, pas de téléchargement possible ! warn-noActiveServers Aucun serveur primaire défini, pas de téléchargement possible !
warn-noConnectServer@3 Impossible de se connecter au serveur %s:%s [%s] warn-noConnectServer@2 Impossible de se connecter au serveur %s [%s]
error-accountSharing Probable account sharing
error-serverCred@1 Server %s requires user/password
warn-thread@3 Thread %s@%s:%s: warn-thread@3 Thread %s@%s:%s:
error-mailAuth Echec de l'autentification au serveur de mail error-mailAuth Echec de l'autentification au serveur de mail
error-mailNoConn Echec de la connexion au serveur de mail error-mailNoConn Echec de la connexion au serveur de mail

10
main/language/nl-du.txt

@ -146,7 +146,7 @@ thread Verbinding
emailResult Test resultaat email emailResult Test resultaat email
lastWarnings Recentste meldingen lastWarnings Recentste meldingen
clearWarnings Wissen clearWarnings Wissen
server-blocked geblokkeerd server-blocked Deblokkeren
# Configuration # Configuration
configuration Instellingen configuration Instellingen
@ -582,12 +582,14 @@ warn-noRead@1 Kan %s niet lezen
error-except Exception? error-except Exception?
error-noInit@3 Kan geen verbinding maken %s@%s:%s error-noInit@3 Kan geen verbinding maken %s@%s:%s
error-serverFailed@4 Verbinding %s@%s:%s mislukt, bericht=%s error-serverFailed@4 Verbinding %s@%s:%s mislukt, bericht=%s
error-serverLogin@2 Kan niet aanmelden bij server %s:%s error-serverLogin@1 Kan niet aanmelden bij server %s
error-serverNoConn@3 Kan geen verbinding maken met server %s:%s [%s] error-serverNoConn@2 Kan geen verbinding maken met server %s [%s]
error-serverTooMany@2 Te veel verbindingen met server %s:%s error-serverTooMany@2 Te veel verbindingen met server %s:%s
warn-ignoreServer@2 Server %s wordt gedurende %s minuten genegeerd warn-ignoreServer@2 Server %s wordt gedurende %s minuten genegeerd
warn-noActiveServers Geen aktieve primaire servers, download niet mogelijk! warn-noActiveServers Geen aktieve primaire servers, download niet mogelijk!
warn-noConnectServer@3 Kan geen verbinding maken met server %s:%s [%s] warn-noConnectServer@2 Kan geen verbinding maken met server %s [%s]
error-accountSharing Mogelijk delen van account
error-serverCred@1 Server %s heeft gebruikersnaam/wachtwoord nodig
warn-thread@3 Verbinding %s@%s:%s: warn-thread@3 Verbinding %s@%s:%s:
error-mailAuth Kan niet aanmelden bij email server error-mailAuth Kan niet aanmelden bij email server
error-mailNoConn Kan geen verbinding maken met email server error-mailNoConn Kan geen verbinding maken met email server

10
main/language/us-en.txt

@ -148,7 +148,7 @@ thread Thread
emailResult Email Test Result emailResult Email Test Result
lastWarnings Lastest Warnings lastWarnings Lastest Warnings
clearWarnings clear clearWarnings clear
server-blocked blocked server-blocked Unblock
# Configuration # Configuration
configuration Configuration configuration Configuration
@ -582,12 +582,14 @@ warn-noRead@1 Cannot read %s
error-except Exception? error-except Exception?
error-noInit@3 Failed to initialize %s@%s:%s error-noInit@3 Failed to initialize %s@%s:%s
error-serverFailed@4 Connecting %s@%s:%s failed, message=%s error-serverFailed@4 Connecting %s@%s:%s failed, message=%s
error-serverLogin@2 Failed login for server %s:%s error-serverLogin@1 Failed login for server %s
error-serverNoConn@3 Cannot connect to server %s:%s [%s] error-serverNoConn@2 Cannot connect to server %s [%s]
error-serverTooMany@2 Too many connections to server %s:%s error-serverTooMany@2 Too many connections to server %s:%s
warn-ignoreServer@2 Server %s will be ignored for %s minutes warn-ignoreServer@2 Server %s will be ignored for %s minutes
warn-noActiveServers No active primary servers defined, will not download! warn-noActiveServers No active primary servers defined, will not download!
warn-noConnectServer@3 Cannot connect to server %s:%s [%s] warn-noConnectServer@2 Cannot connect to server %s [%s]
error-accountSharing Probable account sharing
error-serverCred@1 Server %s requires user/password
warn-thread@3 Thread %s@%s:%s: warn-thread@3 Thread %s@%s:%s:
error-mailAuth Failed to authenticate to mail server error-mailAuth Failed to authenticate to mail server
error-mailNoConn Failed to connect to mail server error-mailNoConn Failed to connect to mail server

9
main/sabnzbd/config.py

@ -681,12 +681,13 @@ def save_config(force=False):
except: except:
CFG[section] = {} CFG[section] = {}
for subsec in database[section]: for subsec in database[section]:
subsec_mod = subsec.replace('[', '{').replace(']','}')
try: try:
CFG[section][subsec] CFG[section][subsec_mod]
except: except:
CFG[section][subsec] = {} CFG[section][subsec_mod] = {}
items = database[section][subsec].get_dict() items = database[section][subsec].get_dict()
CFG[section][subsec] = items CFG[section][subsec_mod] = items
else: else:
for option in database[section]: for option in database[section]:
sec, kw = database[section][option].ident() sec, kw = database[section][option].ident()
@ -727,7 +728,7 @@ def define_servers():
try: try:
for server in CFG['servers']: for server in CFG['servers']:
svr = CFG['servers'][server] svr = CFG['servers'][server]
ConfigServer(server, svr) ConfigServer(server.replace('{', '[').replace('}', ']'), svr)
except KeyError: except KeyError:
pass pass

92
main/sabnzbd/downloader.py

@ -22,6 +22,7 @@ sabnzbd.downloader - download engine
import time import time
import select import select
import logging import logging
import datetime
from threading import Thread from threading import Thread
from nntplib import NNTPPermanentError from nntplib import NNTPPermanentError
@ -162,6 +163,10 @@ def delayed():
global __DOWNLOADER global __DOWNLOADER
if __DOWNLOADER: return __DOWNLOADER.delayed if __DOWNLOADER: return __DOWNLOADER.delayed
def unblock(server):
global __DOWNLOADER
if __DOWNLOADER: return __DOWNLOADER.unblock(server)
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
class Server: class Server:
@ -185,6 +190,7 @@ class Server:
self.idle_threads = [] self.idle_threads = []
self.active = True self.active = True
self.bad_cons = 0 self.bad_cons = 0
self.errormsg = ''
for i in range(threads): for i in range(threads):
self.idle_threads.append(NewsWrapper(self, i+1)) self.idle_threads.append(NewsWrapper(self, i+1))
@ -238,6 +244,7 @@ class Downloader(Thread):
self.write_fds = {} self.write_fds = {}
self.servers = [] self.servers = []
self._timers = {}
primary = False primary = False
for server in config.get_servers(): for server in config.get_servers():
@ -292,7 +299,6 @@ class Downloader(Thread):
return primary return primary
def stop(self): def stop(self):
self.shutdown = True self.shutdown = True
osx.sendGrowlMsg("SABnzbd",T('grwl-shutdown-begin-msg'),osx.NOTIFICATION['startup']) osx.sendGrowlMsg("SABnzbd",T('grwl-shutdown-begin-msg'),osx.NOTIFICATION['startup'])
@ -362,9 +368,9 @@ class Downloader(Thread):
# disable it now and send a re-enable plan to the scheduler # disable it now and send a re-enable plan to the scheduler
server.bad_cons = 0 server.bad_cons = 0
server.active = False server.active = False
self.init_server(server.id, None) server.errormsg = T('warn-ignoreServer@2') % ('', _PENALTY_TIMEOUT)
logging.warning(T('warn-ignoreServer@2'), server.id, _PENALTY_TIMEOUT) logging.warning(T('warn-ignoreServer@2'), server.id, _PENALTY_TIMEOUT)
sabnzbd.scheduler.plan_server(self.init_server, [None, server.id], _PENALTY_TIMEOUT) self.plan_server(server.id, _PENALTY_TIMEOUT)
if server.restart: if server.restart:
if not server.busy_threads: if not server.busy_threads:
@ -545,36 +551,46 @@ class Downloader(Thread):
penalty = 0 penalty = 0
msg = error.response msg = error.response
ecode = msg[:3] ecode = msg[:3]
if ecode in ('481', '482', '381') or (ecode == '502' and clues_login(msg)): logging.debug('Server login problem: %s, %s', ecode, msg)
if ((ecode in ('502', '400')) and clues_too_many(msg)) or \
(ecode == '481' and clues_too_many(msg)):
# Too many connections: remove this thread and reduce thread-setting for server
if server.active:
server.errormsg = T('error-serverTooMany@2') % ('', '')
logging.error(T('error-serverTooMany@2'), server.host, server.port)
self.__reset_nw(nw, None, warn=False, destroy=True)
server.threads -= 1
elif ecode in ('502', '481') and clues_too_many_ip(msg):
# Account sharing?
if server.active:
server.errormsg = T('error-accountSharing')
name = ' (%s:%s)' % (server.host, server.port)
logging.error(T('error-accountSharing') + name)
penalty = _PENALTY_SHARE
elif ecode in ('481', '482', '381') or (ecode == '502' and clues_login(msg)):
# Cannot login, block this server # Cannot login, block this server
if server.active: if server.active:
logging.error(T('error-serverLogin@2'), server.host, server.port) server.errormsg = T('error-serverLogin@1') % ''
logging.error(T('error-serverLogin@1'), '%s:%s' % (server.host, server.port))
block = True block = True
elif (ecode in ('502', '400')) and clues_too_many(msg):
# Too many connections: remove this thread and reduce thread-setting for server
logging.error(T('error-serverTooMany@2'), 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': elif ecode == '502':
# Cannot connect (other reasons), block this server # Cannot connect (other reasons), block this server
if server.active: if server.active:
logging.warning(T('warn-noConnectServer@3'), server.host, server.port, msg) server.errormsg = T('warn-noConnectServer@2') % ('', msg)
logging.warning(T('warn-noConnectServer@2'), '%s:%s' % (server.host, server.port), msg)
penalty = _PENALTY_502 penalty = _PENALTY_502
else: else:
# Unknown error, just keep trying # Unknown error, just keep trying
logging.error(T('error-serverNoConn@3'), server.host, server.port, msg) if server.active:
penalty = _PENALTY_UNKNOWN server.errormsg = T('error-serverNoConn@2') % ('', msg)
logging.error(T('error-serverNoConn@2'), '%s:%s' % (server.host, server.port, msg))
penalty = _PENALTY_UNKNOWN
if block or (penalty and server.optional): if block or (penalty and server.optional):
if server.active: if server.active:
server.active = False server.active = False
self.init_server(server, None)
if penalty and server.optional: if penalty and server.optional:
logging.info('Server %s ignored for %s minutes', server.id, penalty) logging.info('Server %s ignored for %s minutes', server.id, penalty)
sabnzbd.scheduler.plan_server(self.init_server, [None, server.id], penalty) self.plan_server(server.id, penalty)
self.__reset_nw(nw, None, warn=False) self.__reset_nw(nw, None, warn=False)
continue continue
except: except:
@ -610,7 +626,11 @@ class Downloader(Thread):
nw.server.port, article.article) nw.server.port, article.article)
elif code == '480': elif code == '480':
msg = 'Server %s:%s requires user/password' % (nw.server.host, nw.server.port) if server.active:
server.active = False
server.errormsg = T('error-serverCred@1') % ''
self.plan_server(server.id, 0)
msg = T('error-serverCred@1') % ('%s:%s' % (nw.server.host, nw.server.port))
self.__reset_nw(nw, msg) self.__reset_nw(nw, msg)
if done: if done:
@ -699,6 +719,38 @@ class Downloader(Thread):
logging.error(T('error-except')) logging.error(T('error-except'))
self.__reset_nw(nw, "server broke off connection") self.__reset_nw(nw, "server broke off connection")
#------------------------------------------------------------------------------
# Timed restart of servers admin.
# For each server all planned events are kept in a list.
# When the first timer of a server fires, all other existing timers
# are neutralized.
# Each server has a dictionary entry, consisting of a list of timestamps.
def plan_server(self, server_id, interval):
""" Plan the restart of a server in 'interval' minutes """
logging.debug('Set planned server resume %s in %s mins', server_id, interval)
if server_id not in self._timers:
self._timers[server_id] = []
stamp = datetime.datetime.now()
self._timers[server_id].append(stamp)
if interval:
sabnzbd.scheduler.plan_server(self.trigger_server, [server_id, stamp], interval)
def trigger_server(self, server_id, timestamp):
""" Called by scheduler, start server if timer still valid """
logging.debug('Trigger planned server resume %s', server_id)
if server_id in self._timers:
if timestamp in self._timers[server_id]:
del self._timers[server_id]
self.init_server(server_id, server_id)
def unblock(self, server_id):
if server_id in self._timers:
logging.debug('Unblock server %s', server_id)
del self._timers[server_id]
self.init_server(server_id, server_id)
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def clues_login(text): def clues_login(text):

51
main/sabnzbd/interface.py

@ -245,6 +245,7 @@ _MSG_NO_FILE = 'no file given'
_MSG_NO_PATH = 'file does not exist' _MSG_NO_PATH = 'file does not exist'
_MSG_OUTPUT_FORMAT = 'Format not supported' _MSG_OUTPUT_FORMAT = 'Format not supported'
_MSG_NO_SUCH_CONFIG = 'Config item does not exist' _MSG_NO_SUCH_CONFIG = 'Config item does not exist'
_MSG_BAD_SERVER_PARMS = 'Incorrect server settings'
def remove_callable(dic): def remove_callable(dic):
""" Remove all callable items from dictionary """ """ Remove all callable items from dictionary """
@ -483,9 +484,13 @@ class MainPage:
output = kwargs.get('output') output = kwargs.get('output')
if mode == 'set_config': if mode == 'set_config':
res = config.set_config(kwargs) if kwargs.get('section') == 'servers':
if not res: handle_server_api(output, kwargs)
return report(output, _MSG_NO_SUCH_CONFIG) else:
res = config.set_config(kwargs)
if not res:
return report(output, _MSG_NO_SUCH_CONFIG)
config.save_config()
if mode in ('get_config', 'set_config'): if mode in ('get_config', 'set_config'):
res, data = config.get_dconfig(kwargs.get('section'), kwargs.get('keyword')) res, data = config.get_dconfig(kwargs.get('section'), kwargs.get('keyword'))
@ -1766,9 +1771,7 @@ def handle_server(kwargs, root=None):
if msg: if msg:
return msg return msg
# Replace square by curly brackets to avoid clash server = '%s:%s' % (host, port)
# between INI format and IPV6 notation
server = '%s:%s' % (host.replace('[','{').replace(']','}'), port)
svr = None svr = None
old_server = kwargs.get('server') old_server = kwargs.get('server')
@ -1793,6 +1796,31 @@ def handle_server(kwargs, root=None):
raise dcRaiser(root, kwargs) raise dcRaiser(root, kwargs)
def handle_server_api(output, kwargs):
""" Special handler for API-call 'set_config'
"""
name = kwargs.get('keyword')
if not name:
name = kwargs.get('name')
if not name:
host = kwargs.get('host')
port = kwargs.get('port', '119')
if host:
name = '%s:%s' % (host, port)
else:
return False
server = config.get_config('servers', name)
if server:
server.set_dict(kwargs)
old_name = name
else:
config.ConfigServer(name, kwargs)
old_name = None
downloader.update_server(old_name, name)
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
class ConfigRss: class ConfigRss:
@ -2363,7 +2391,7 @@ class ConnectionInfo:
connected += 1 connected += 1
busy.sort() busy.sort()
header['servers'].append((server.host, server.port, connected, busy, server.ssl, server.active)) header['servers'].append((server.host, server.port, connected, busy, server.ssl, server.active, server.errormsg))
wlist = [] wlist = []
for w in sabnzbd.GUIHANDLER.content(): for w in sabnzbd.GUIHANDLER.content():
@ -2430,6 +2458,15 @@ class ConnectionInfo:
raise dcRaiser(self.__root, kwargs) raise dcRaiser(self.__root, kwargs)
@cherrypy.expose
def unblock_server(self, **kwargs):
msg = check_session(kwargs)
if msg: return msg
downloader.unblock(kwargs.get('server'))
# Short sleep so that UI shows new server status
time.sleep(1.0)
raise dcRaiser(self.__root, kwargs)
def Protected(): def Protected():
return badParameterResponse("Configuration is locked") return badParameterResponse("Configuration is locked")

6
main/sabnzbd/scheduler.py

@ -320,7 +320,7 @@ def pause_int():
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
def plan_server(action, parms, penalty): def plan_server(action, parms, interval):
""" Plan to re-activate server after "penalty" minutes """ Plan to re-activate server after "interval" minutes
""" """
__SCHED.add_single_task(action, '', penalty*60, kronos.method.sequential, parms, None) __SCHED.add_single_task(action, '', interval*60, kronos.method.sequential, parms, None)

Loading…
Cancel
Save