# 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 of the License, 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # Copyright 2006 Dan Williams and Red Hat, Inc. import threading import URLopener import time FT_RESULT_SUCCESS = 'success' FT_RESULT_FAILED = 'failed' FT_RESULT_CANCELED = 'canceled' class FileTransfer(threading.Thread): def __init__(self, certs=None): self._callback = None self._cb_data = None self._cancel = False self._tries = 5 self._opener = None if certs: if type(certs) is not type({}): raise ValueError("Certs must be a dict of certificate paths.") self._certs = certs self._opener = URLopener.PlgURLopener(self._certs, 20) threading.Thread.__init__(self) def set_tries(self, tries): if tries <= 0: raise ValueError("Tries must be larger than 0") self._tries = tries def set_callback(self, callback, cb_data): self._callback = callback self._cb_data = cb_data def cancel(self): self._cancel = True def _action(self, data=None): # Should be implemented by subclasses return (False, "_action should be implemented by subclass") def _process_one_transfer(self, data=None): """Retries a transfer for a specified number of times before failing.""" status = FT_RESULT_FAILED result = msg = filed_msg = None for attempt in range(1, self._tries + 1): try: (result, msg) = self._action(data) except ValueError, exc: result = None failed_msg = str(exc) if result: status = FT_RESULT_SUCCESS break if self._cancel: status = FT_RESULT_CANCELED break time.sleep(5) failed_msg = "Transfer timed out." if status == FT_RESULT_FAILED: msg = failed_msg return (status, msg) def run(self): (status, msg) = self._process_one_transfer() if self._callback: self._callback(status, self._cb_data, msg)