1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
# -*- coding: utf-8 -*-
""" TransferHandler -- class to handle uploading and downloading files
Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
"""
from PyQt4 import QtCore
from urllib import urlopen
import httplib
import urlparse
import bz2
import base64
import threading
class TransferHandler( QtCore.QObject ):
""" Manages up- and downloading files. """
sig_download_start = QtCore.SIGNAL( 'downloadStart(const QString)' )
sig_download_success = QtCore.SIGNAL( 'downloadSuccess(const QString)' )
sig_download_fail = QtCore.SIGNAL( 'downloadFail(const QString, const QString)' )
sig_download_finished = QtCore.SIGNAL( 'downloadFinished()' )
sig_upload_start = QtCore.SIGNAL( 'uploadStart(const QString)' )
sig_upload_success = QtCore.SIGNAL( 'uploadSuccess(const QString)' )
sig_upload_fail = QtCore.SIGNAL( 'uploadFail(const QString, const int, const QString, const QString)' )
sig_upload_finished = QtCore.SIGNAL( 'uploadFinished()' )
def __init__( self, username=None, password=None ):
QtCore.QObject.__init__( self )
self.downloader = None
self.uploader = None
self.mapsdir = None
self.mapsurl = None
self.username = username
self.password = password
def perform_transfers( self, map_dir, map_url, download, upload ):
""" Start the transfers listed in download and upload in seperate threads.
download and upload need to be lists of dictionaries, containing:
- mapname: the base name of the map to download, e.g. de_dust
- mapexts: list of file extensions to be downloaded, e.g. [bsp.bz2, txt, nav]
"""
self.mapsdir = map_dir
self.mapsurl = map_url
if self.downloader is None or not self.downloader.isAlive():
self.downloader = threading.Thread( target=self.perform_downloads, args=(download,) )
self.downloader.start()
if self.uploader is None or not self.uploader.isAlive():
self.uploader = threading.Thread( target=self.perform_uploads, args=(upload,) )
self.uploader.start()
def perform_downloads( self, download ):
""" The thread worker that handles downloading files.
For documentation on the download parameter, see perform_transfers.
"""
for job in download:
mapname = job['mapname']
mapexts = job['mapexts']
self.emit( TransferHandler.sig_download_start, mapname )
for cur_ext in mapexts:
if cur_ext == "bsp" and "bsp.bz2" in mapexts:
# We won't download a bsp now because a bz2'ed file exists
continue
mapfile = urlopen( "%s/%s.%s" % ( self.mapsurl, mapname, cur_ext ) ).fp.read()
if cur_ext == "bsp.bz2":
mapfile = bz2.decompress( mapfile )
cur_ext = "bsp"
mapfile_fd = open( "%s/%s.%s" % ( self.mapsdir, mapname, cur_ext ), 'wb' )
mapfile_fd.write( mapfile )
mapfile_fd.close()
self.emit( TransferHandler.sig_download_success, mapname )
self.emit( TransferHandler.sig_download_finished )
def perform_uploads( self, upload ):
""" The thread worker that handles uploading files.
For documentation on the upload parameter, see perform_transfers.
"""
for job in upload:
mapname = job['mapname']
mapexts = job['mapexts']
self.emit( TransferHandler.sig_upload_start, mapname )
bspath = "%s/%s.bsp" % ( self.mapsdir, mapname )
bspurl = "%s/%s.bsp.bz2" % ( self.mapsurl, mapname )
if not self.upload_file( mapname, bspath, bspurl ):
continue
for cur_ext in mapexts:
if cur_ext in ( "bsp", "bsp.bz2" ):
continue
filepath = "%s/%s.%s" % ( self.mapsdir, mapname, cur_ext )
fileurl = "%s/%s.%s" % ( self.mapsurl, mapname, cur_ext )
self.upload_file( mapname, filepath, fileurl )
self.emit( TransferHandler.sig_upload_success, mapname )
self.emit( TransferHandler.sig_upload_finished )
def upload_file( self, mapname, filepath, fileurl ):
""" See if the server will accept the file, and if so, upload it. """
if self.upload_file_real( mapname, filepath, fileurl, True ):
return self.upload_file_real( mapname, filepath, fileurl, False )
return False
def upload_file_real( self, mapname, filepath, fileurl, dry = False ):
""" Upload a file. """
diskfd = open( filepath, 'rb' )
try:
plaincontent = diskfd.read()
finally:
diskfd.close()
if fileurl[-3:] == 'bz2':
fd_content = bz2.compress( plaincontent )
else:
fd_content = plaincontent
parsedurl = urlparse.urlparse( fileurl )
# Send HTTP Put request
httpreq = httplib.HTTPS( parsedurl.netloc )
httpreq.putrequest( 'PUT', parsedurl.path )
httpreq.putheader( 'Accept', '*/*' )
httpreq.putheader( 'Allow', 'PUT' )
httpreq.putheader( 'Content-Type', 'application/octet-stream' )
httpreq.putheader( 'Content-Length', str( len( fd_content ) ) )
if self.username and self.password:
httpreq.putheader( 'Authorization', base64.b64encode( '%s:%s' % ( self.username, self.password ) ) )
if dry:
httpreq.putheader( 'x-dry-run', 'true' )
httpreq.endheaders()
if not dry:
print "Sending file with %s bytes (original: %d)" % ( str( len( fd_content ) ), len( plaincontent ) )
httpreq.send( fd_content )
# check reply
errcode, errmsg, _ = httpreq.getreply()
hfd = httpreq.getfile()
if hfd:
replybody = hfd.read()
else:
replybody = ""
if errcode != 201:
self.emit( TransferHandler.sig_upload_fail, mapname, errcode, errmsg, replybody )
return False
httpreq.close()
return True
|