#2912: Improvements to GlibURLDownloader API
This commit is contained in:
parent
8c113d5561
commit
e83b98a8f6
1
NEWS
1
NEWS
@ -1,3 +1,4 @@
|
|||||||
|
* #2912: Improvements to GlibURLDownloader API (dcbw)
|
||||||
* #2299: Really fix buddy properties coming through as arrays of bytes (dcbw)
|
* #2299: Really fix buddy properties coming through as arrays of bytes (dcbw)
|
||||||
|
|
||||||
Snapshot b24a28a77d
|
Snapshot b24a28a77d
|
||||||
|
@ -176,6 +176,8 @@ class GlibURLDownloader(gobject.GObject):
|
|||||||
'finished': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
'finished': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||||
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
|
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])),
|
||||||
'error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
'error': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||||
|
([gobject.TYPE_PYOBJECT])),
|
||||||
|
'progress': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||||
([gobject.TYPE_PYOBJECT]))
|
([gobject.TYPE_PYOBJECT]))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,16 +191,23 @@ class GlibURLDownloader(gobject.GObject):
|
|||||||
self._srcid = 0
|
self._srcid = 0
|
||||||
self._fname = None
|
self._fname = None
|
||||||
self._outf = None
|
self._outf = None
|
||||||
|
self._written = 0
|
||||||
gobject.GObject.__init__(self)
|
gobject.GObject.__init__(self)
|
||||||
|
|
||||||
def start(self, destfile=None):
|
def start(self, destfile=None, destfd=None):
|
||||||
self._info = urllib.urlopen(self._url)
|
self._info = urllib.urlopen(self._url)
|
||||||
self._outf = None
|
self._outf = None
|
||||||
self._fname = None
|
self._fname = None
|
||||||
|
if destfd and not destfile:
|
||||||
|
raise ValueError("Must provide destination file too when specifying file descriptor")
|
||||||
if destfile:
|
if destfile:
|
||||||
self._suggested_fname = os.path.basename(destfile)
|
self._suggested_fname = os.path.basename(destfile)
|
||||||
self._fname = os.path.abspath(os.path.expanduser(destfile))
|
self._fname = os.path.abspath(os.path.expanduser(destfile))
|
||||||
self._outf = os.open(self._fname, os.O_RDWR | os.O_TRUNC | os.O_CREAT, 0644)
|
if destfd:
|
||||||
|
# Use the user-supplied destination file descriptor
|
||||||
|
self._outf = destfd
|
||||||
|
else:
|
||||||
|
self._outf = os.open(self._fname, os.O_RDWR | os.O_TRUNC | os.O_CREAT, 0644)
|
||||||
else:
|
else:
|
||||||
self._suggested_fname = self._get_filename_from_headers(self._info.headers)
|
self._suggested_fname = self._get_filename_from_headers(self._info.headers)
|
||||||
garbage, path = urllib.splittype(self._url)
|
garbage, path = urllib.splittype(self._url)
|
||||||
@ -213,6 +222,11 @@ class GlibURLDownloader(gobject.GObject):
|
|||||||
gobject.IO_IN | gobject.IO_ERR,
|
gobject.IO_IN | gobject.IO_ERR,
|
||||||
self._read_next_chunk)
|
self._read_next_chunk)
|
||||||
|
|
||||||
|
def cancel(self):
|
||||||
|
if self._srcid == 0:
|
||||||
|
raise RuntimeError("Download already canceled or stopped")
|
||||||
|
self.cleanup(remove=True)
|
||||||
|
|
||||||
def _get_filename_from_headers(self, headers):
|
def _get_filename_from_headers(self, headers):
|
||||||
if not headers.has_key("Content-Disposition"):
|
if not headers.has_key("Content-Disposition"):
|
||||||
return None
|
return None
|
||||||
@ -231,8 +245,7 @@ class GlibURLDownloader(gobject.GObject):
|
|||||||
|
|
||||||
def _read_next_chunk(self, source, condition):
|
def _read_next_chunk(self, source, condition):
|
||||||
if condition & gobject.IO_ERR:
|
if condition & gobject.IO_ERR:
|
||||||
self.cleanup()
|
self.cleanup(remove=True)
|
||||||
os.remove(self._fname)
|
|
||||||
self.emit("error", "Error downloading file.")
|
self.emit("error", "Error downloading file.")
|
||||||
return False
|
return False
|
||||||
elif not (condition & gobject.IO_IN):
|
elif not (condition & gobject.IO_IN):
|
||||||
@ -242,27 +255,36 @@ class GlibURLDownloader(gobject.GObject):
|
|||||||
try:
|
try:
|
||||||
data = self._info.fp.read(self.CHUNK_SIZE)
|
data = self._info.fp.read(self.CHUNK_SIZE)
|
||||||
count = os.write(self._outf, data)
|
count = os.write(self._outf, data)
|
||||||
|
self._written += len(data)
|
||||||
|
|
||||||
|
# error writing data to file?
|
||||||
|
if count < len(data):
|
||||||
|
self.cleanup(remove=True)
|
||||||
|
self.emit("error", "Error writing to download file.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.emit("progress", self._written)
|
||||||
|
|
||||||
|
# done?
|
||||||
if len(data) < self.CHUNK_SIZE:
|
if len(data) < self.CHUNK_SIZE:
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
self.emit("finished", self._fname, self._suggested_fname)
|
self.emit("finished", self._fname, self._suggested_fname)
|
||||||
return False
|
return False
|
||||||
if count < len(data):
|
|
||||||
self.cleanup()
|
|
||||||
self.emit("error", "Error writing to download file.")
|
|
||||||
return False
|
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
self.cleanup()
|
self.cleanup(remove=True)
|
||||||
self.emit("error", "Error downloading file: %s" % err)
|
self.emit("error", "Error downloading file: %s" % err)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self, remove=False):
|
||||||
if self._srcid > 0:
|
if self._srcid > 0:
|
||||||
gobject.source_remove(self._srcid)
|
gobject.source_remove(self._srcid)
|
||||||
self._srcid = 0
|
self._srcid = 0
|
||||||
del self._info
|
del self._info
|
||||||
self._info = None
|
self._info = None
|
||||||
os.close(self._outf)
|
os.close(self._outf)
|
||||||
|
if remove:
|
||||||
|
os.remove(self._fname)
|
||||||
self._outf = None
|
self._outf = None
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user