better error handling

This commit is contained in:
Ward Wouts 2002-07-03 22:18:40 +00:00
parent 0154d6292d
commit 9026140c4e
2 changed files with 89 additions and 97 deletions

View file

@ -15,6 +15,11 @@ require 'news/newsrc'
require 'tempfile' require 'tempfile'
require 'timeout' require 'timeout'
class ArticleError < RuntimeError; end
class ReconnectError < ArticleError; end
class GroupInfoError < ArticleError; end
class BodyError < ArticleError; end
class Article class Article
Debuglevel = 0 Debuglevel = 0
@ -41,25 +46,21 @@ def initialize(nntpservers, groupname, newsrc="~/.newsrc")
@connections[server]["newsrc"] = News::Newsrc.new("#{newsrc}.#{server}") @connections[server]["newsrc"] = News::Newsrc.new("#{newsrc}.#{server}")
set_skip_ids(server, @connections[server]["newsrc"].marked_articles(@group)) set_skip_ids(server, @connections[server]["newsrc"].marked_articles(@group))
rescue SocketError rescue SocketError
print "Connection to #{server} failed, removing from server list...\n" print "Connection to #{server} failed\n"
@connections.delete(server) del_server(server)
@serverlist.delete(server)
end end
} }
end end
def reconnect(server) def reconnect(server)
print "Trying to reconnect to #{server}...\n"
begin begin
@connections[server]["nntp"] = Net::NNTP.new(server) @connections[server]["nntp"] = Net::NNTP.new(server)
rescue SocketError rescue SocketError
print "Connection to #{server} failed, removing from server list...\n" print "Reconnect to #{server} failed\n"
@connections.delete(server) del_server(server)
@serverlist.delete(server) raise ReconnectError
return false
end end
print "Succesfully reconnected to #{server}\n" print "Succesfully reconnected to #{server}\n"
return true
end end
def add(messid, id, server, subject) def add(messid, id, server, subject)
@ -75,29 +76,32 @@ def add(messid, id, server, subject)
@grouped = false @grouped = false
end end
def del_server(server)
print "Removing server #{server} from list\n"
@connections.delete(server)
@serverlist.delete(server)
end
def get_articles(cachedir=false) def get_articles(cachedir=false)
for server in @connections.keys for server in @connections.keys
first, last = get_group_info(server) begin
return false if first == false first, last = get_group_info(server)
if first rescue ReconnectError, GroupInfoError
del_server(server)
next
end
if first <= last
@connections[server]["first"] = first ? first : 0 @connections[server]["first"] = first ? first : 0
@connections[server]["last"] = last ? last : 0 @connections[server]["last"] = last ? last : 0
else else
print "Error selecting @group on server #{server}, removing from server list...\n" print " First article has higher number than last article on server #{server}.\n"
@connections.delete(server) del_server(server)
@serverlist.delete(server)
end end
end end
read_cache(cachedir) read_cache(cachedir)
for server in @connections.keys for server in @connections.keys
print " reading articles from server: #{server}\n" print " reading articles from server: #{server}\n"
if @connections[server]["first"] > @connections[server]["last"] range = Set::IntSpan.new("#{@connections[server]["first"]}-#{@connections[server]["last"]}")
print " First article has higher number than last article on server #{server}.\n"
print " Skipping...\n"
next
else
range = Set::IntSpan.new("#{@connections[server]["first"]}-#{@connections[server]["last"]}")
end
rangelist = rechunk_runlist(range.diff(@connections[server]["skip_ids"]).run_list) rangelist = rechunk_runlist(range.diff(@connections[server]["skip_ids"]).run_list)
print "rangelist: #{rangelist}\n" if Debuglevel >1 print "rangelist: #{rangelist}\n" if Debuglevel >1
print "rangelist: #{rangelist.type.to_s}\n" if Debuglevel >1 print "rangelist: #{rangelist.type.to_s}\n" if Debuglevel >1
@ -105,10 +109,13 @@ def get_articles(cachedir=false)
unless rangelist == nil or rangelist =~ /^$/ unless rangelist == nil or rangelist =~ /^$/
for i in rangelist.split(',') for i in rangelist.split(',')
print "i: #{i}\n" if Debuglevel > 1 print "i: #{i}\n" if Debuglevel > 1
begin
resp, subj_lines = get_xhdr(server, i, "subject") resp, subj_lines = get_xhdr(server, i, "subject")
next unless resp
resp, messid_lines = get_xhdr(server, i, "message-id") resp, messid_lines = get_xhdr(server, i, "message-id")
next unless resp rescue TimeoutError, ReconnectError, XhdrError, GroupInfoError
print "Caught: #{$!} reading from #{server}\n"
next
end
art = {} art = {}
subj_lines.collect{|x| subj_lines.collect{|x|
@ -139,30 +146,27 @@ def get_group_info(server)
first = "" first = ""
last = "" last = ""
begin begin
if timedout > 1
print "Too many timeouts! (get_group_info)\n"
return false
end
timeout(30) do timeout(30) do
begin begin
resp, count, first, last, name = @connections[server]["nntp"].group(@group) resp, count, first, last, name = @connections[server]["nntp"].group(@group)
rescue Net::NNTP::RuntimeError rescue Net::NNTP::RuntimeError
print "Couldn't open group: #{@group}\n" print "Got error \"#{$!}\" from #{server}\n"
print "Error: #{$!}\n" raise GroupInfoError
return false
rescue Errno::EPIPE, Errno::ECONNRESET rescue Errno::EPIPE, Errno::ECONNRESET
print "Caught Errno::EPIPE reading from server #{server}\n" print "Caught Errno::EPIPE reading from server #{server}\n"
print "Error: #{$!}\n" print "Error: #{$!}\n"
retry if reconnect(server) reconnect(server)
retry
end end
end end
return first, last if resp
rescue TimeoutError rescue TimeoutError
print "Time out, reconnecting to server\n"
timedout += 1 timedout += 1
retry if reconnect(server) raise TimeoutError, "Too many timeouts! (get_group_info)\n" if timedout > 1
print "Time out, reconnecting to server...\n"
reconnect(server)
retry
end end
return false return first, last
end end
def get_xhdr(server, range, header) def get_xhdr(server, range, header)
@ -170,16 +174,12 @@ def get_xhdr(server, range, header)
resp = "" resp = ""
lines = [] lines = []
begin begin
if timedout > 1
print "Too many timeouts! (get_xhdr)\n"
return false
end
timeout(180) do timeout(180) do
begin begin
resp, lines = @connections[server]["nntp"].xhdr(header, range) resp, lines = @connections[server]["nntp"].xhdr(header, range)
unless resp.to_i >= 200 and resp.to_i < 300 unless resp.to_i >= 200 and resp.to_i < 300
print "got response #{resp} while reading group #{@group} from #{server}\n" print "got response #{resp} while reading group #{@group} from #{server}\n"
return false raise XhdrError
end end
rescue Net::NNTP::RuntimeError rescue Net::NNTP::RuntimeError
print "Caught Net::NNTP::RuntimeError reading from server #{server}\n" print "Caught Net::NNTP::RuntimeError reading from server #{server}\n"
@ -187,20 +187,19 @@ def get_xhdr(server, range, header)
rescue Errno::EPIPE, Errno::ECONNRESET rescue Errno::EPIPE, Errno::ECONNRESET
print "Caught Errno::EPIPE reading from server #{server}\n" print "Caught Errno::EPIPE reading from server #{server}\n"
print "Error: #{$!}\n" print "Error: #{$!}\n"
if reconnect(server) reconnect(server)
return false unless get_group_info(server) get_group_info(server)
retry retry
end
end end
end end
return resp, lines return resp, lines
rescue TimeoutError rescue TimeoutError
print "Time out, reconnecting to server\n" print "Time out, reconnecting to server\n"
timedout += 1 timedout += 1
if reconnect(server) raise TimeoutError, "Too many timeouts! (get_xhrd)\n" if timedout > 1
return false unless get_group_info(server) reconnect(server)
retry get_group_info(server)
end retry
end end
end end
@ -240,10 +239,6 @@ def get_body(server, message)
messid = "" messid = ""
list = [] list = []
begin begin
if timedout > 1
print "Too many timeouts! (get_body)\n"
return false
end
timeout(180) do timeout(180) do
begin begin
resp, id, messid, list = @connections[server]["nntp"].body(message) resp, id, messid, list = @connections[server]["nntp"].body(message)
@ -254,20 +249,19 @@ def get_body(server, message)
rescue Errno::EPIPE, Errno::ECONNRESET rescue Errno::EPIPE, Errno::ECONNRESET
print "Caught Errno::EPIPE reading from server #{server}\n" print "Caught Errno::EPIPE reading from server #{server}\n"
print "Error: #{$!}\n" print "Error: #{$!}\n"
if reconnect(server) reconnect(server)
return false unless get_group_info(server) get_group_info(server)
retry retry
end
end end
end end
return resp, id, messid, list return resp, id, messid, list
rescue TimeoutError rescue TimeoutError
print "Time out, reconnecting to server\n" print "Time out, reconnecting to server\n"
timedout += 1 timedout += 1
if reconnect(server) raise TimeoutError, "Too many timeouts! (get_body)\n" if timedout > 1
return false unless get_group_info(server) reconnect(server)
retry get_group_info(server)
end retry
end end
end end
@ -293,8 +287,7 @@ def get_group_body(subj)
i += 1 i += 1
retry retry
else else
print "Message-id not on another server :( Skipping...\n" raise BodyError, "Message-id not on another server\n"
return false
end end
end end
end end
@ -325,8 +318,7 @@ def get_group_body_first(subj)
i += 1 i += 1
retry retry
else else
print "Message-id not on another server :( Skipping...\n" raise BodyError, "Message-id not on another server\n"
return false
end end
end end
end end
@ -356,8 +348,7 @@ def get_group_body_rest(subj, file=nil)
i += 1 i += 1
retry retry
else else
print "Message-id not on another server :( Skipping...\n" raise BodyError, "Message-id not on another server\n"
return false
end end
end end
end end

View file

@ -224,7 +224,6 @@ def get_multi(subj, group)
return false return false
else else
body = @articles.get_group_body_first(subj) body = @articles.get_group_body_first(subj)
return false if body == false
if @articles.is_uuencoded(body) or @articles.is_yencoded(body) if @articles.is_uuencoded(body) or @articles.is_yencoded(body)
file = Tempfile.new("riptmp", @config[group]["TEMPDIR"]) file = Tempfile.new("riptmp", @config[group]["TEMPDIR"])
body.collect{|x| file.print "#{x}\n"} body.collect{|x| file.print "#{x}\n"}
@ -248,28 +247,23 @@ def get_multi(subj, group)
end end
def output_data(subject, mode, filename="", body="") def output_data(subject, mode, filename="", body="")
if mode group = @articles.get_groupname
group = @articles.get_groupname print " mode: #{mode}\n" if Debuglevel > 0
print " mode: #{mode}\n" if Debuglevel > 0 print " Filename: '#{filename}'\n" if Debuglevel > 0
print " Filename: '#{filename}'\n" if Debuglevel > 0 if @config[group].has_key?("-L") and @config[group]["-L"]
if @config[group].has_key?("-L") and @config[group]["-L"] print "longname\n" if Debuglevel > 1
print "longname\n" if Debuglevel > 1 outfile = subject
outfile = subject elsif @config[group].has_key?("-C") and @config[group]["-C"]
elsif @config[group].has_key?("-C") and @config[group]["-C"] print "combinedname\n" if Debuglevel > 1
print "combinedname\n" if Debuglevel > 1 outfile = "#{subject} [#{filename}]"
outfile = "#{subject} [#{filename}]"
else
print "shortname\n" if Debuglevel > 1
outfile = filename
end
if save_file("#{@config[group]["DATADIR"]}/#{group}", outfile, body)
@articles.group_update_newsrc(subject)
@articles.save_newsrc unless @config[group].has_key?("-T") and @config[group]["-T"]
end
else else
return false print "shortname\n" if Debuglevel > 1
outfile = filename
end
if save_file("#{@config[group]["DATADIR"]}/#{group}", outfile, body)
@articles.group_update_newsrc(subject)
@articles.save_newsrc unless @config[group].has_key?("-T") and @config[group]["-T"]
end end
return true
end end
def check_ext(filename, mode) def check_ext(filename, mode)
@ -303,10 +297,13 @@ end
for group in @config.keys.sort for group in @config.keys.sort
print "Getting articles for #{group}\n" print "Getting articles for #{group}\n"
@articles = Article.new(@config[group]["NNTPSERVER"], group, @config[group]["NEWSRCNAME"]) @articles = Article.new(@config[group]["NNTPSERVER"], group, @config[group]["NEWSRCNAME"])
if @articles.get_articles(@config[group]["CACHEDIR"]) == false # begin
@articles.quit @articles.get_articles(@config[group]["CACHEDIR"])
next # rescue Article::
end # print "Caught something: #{$!}\n"
# @articles.quit
# next
# end
unless FileTest.directory?("#{@config[group]["DATADIR"]}/#{group}") or unless FileTest.directory?("#{@config[group]["DATADIR"]}/#{group}") or
Dir.mkdir("#{@config[group]["DATADIR"]}/#{group}", @config[group]["PERMISSION"].oct) Dir.mkdir("#{@config[group]["DATADIR"]}/#{group}", @config[group]["PERMISSION"].oct)
@ -319,12 +316,16 @@ for group in @config.keys.sort
i =~ /#{@config[group]["-I"]}/ i =~ /#{@config[group]["-I"]}/
print "Match: #{i}\n" if Debuglevel > 0 print "Match: #{i}\n" if Debuglevel > 0
if @articles.group_is_complete(i) if @articles.group_is_complete(i)
if @articles.group_is_singlepart(i) begin
mode, filename, body = get_single(i) if @articles.group_is_singlepart(i)
elsif @articles.group_is_multipart(i) mode, filename, body = get_single(i)
mode, filename, body = get_multi(i, group) elsif @articles.group_is_multipart(i)
mode, filename, body = get_multi(i, group)
end
output_data(i, mode, filename, body) if mode != false
rescue Article::BodyError
next
end end
output_data(i, mode, filename, body)
else else
print " Not complete: #{i}\n" print " Not complete: #{i}\n"
end end