diff options
Diffstat (limited to 'module')
| -rw-r--r-- | module/network/FTPBase.py | 208 | ||||
| -rw-r--r-- | module/network/HTTPChunk.py | 31 | ||||
| -rw-r--r-- | module/network/HTTPDownload.py | 22 | ||||
| -rw-r--r-- | module/plugins/hoster/Ftp.py | 5 | ||||
| -rw-r--r-- | module/plugins/hoster/ShareonlineBiz.py | 4 | ||||
| -rw-r--r-- | module/web/templates/default/package_ui.js | 1 | ||||
| -rw-r--r-- | module/web/webinterface.py | 3 | 
7 files changed, 44 insertions, 230 deletions
| diff --git a/module/network/FTPBase.py b/module/network/FTPBase.py deleted file mode 100644 index d8fc5a20d..000000000 --- a/module/network/FTPBase.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -    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 3 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 General Public License for more details. - -    You should have received a copy of the GNU General Public License -    along with this program; if not, see <http://www.gnu.org/licenses/>. -     -    @author: mkaay -""" - -from ftplib import FTP - -import socket -import socks - -from os.path import getsize -from urlparse import urlparse -from urllib2 import _parse_proxy - -from helper import * - -class FTPBase(FTP): -    sourceAddress = ('', 0) -     -    def setSourceAddress(self, host): -        self.sourceAddress = (host, 0) -     -    def connect(self, host='', port=0, timeout=30, proxies={}): -        if host != '': -            self.host = host -        if port > 0: -            self.port = port -        self.timeout = timeout -         -        proxytype = None -        proxy = None -        if "socks5" in proxies: -            proxytype = socks.PROXY_TYPE_SOCKS5 -            proxy = proxies["socks5"] -        elif "socks4" in proxies: -            proxytype = socks.PROXY_TYPE_SOCKS4 -            proxy = proxies["socks4"] -        if proxytype: -            self.sock = socks.socksocket() -            t = _parse_proxy(proxy) -            self.sock.setproxy(proxytype, addr=t[3].split(":")[0], port=int(t[3].split(":")[1]), username=t[1], password=t[2]) -        else: -            self.sock = socket.socket() -        self.sock.settimeout(self.timeout) -        self.sock.bind(self.sourceAddress) -        self.sock.connect((self.host, self.port)) -        self.af = self.sock.family -        self.file = self.sock.makefile('rb') -        self.welcome = self.getresp() -        return self.welcome - -class WrappedFTPDeferred(WrappedDeferred): -    pass - -class FTPDownload(): -    def __init__(self, url, filename, interface=None, bucket=None, proxies={}): -        self.url = url -        self.filename = filename -         -        self.bucket = bucket -        self.interface = interface -        self.proxies = proxies -         -        self.deferred = Deferred() -         -        self.finished = False -        self.size = None -         -        self.speed = 0 -         -        self.abort = False -         -        self.arrived = 0 -         -        self.startTime = None -        self.endTime = None -         -        self.speed = 0 #byte/sec -        self.speedCalcTime = None -        self.speedCalcLen = 0 -         -        self.bufferSize = 16*1024 #tune if performance is poor -         -        self.ftp = FTPBase() -        self.fh = None -     -    @threaded -    def _download(self, offset): -        remotename = self.url.split("/")[-1] -        cmd = "RETR %s" % remotename -         -        self.startTime = inttime() -        self.arrived = offset -        conn, size = self.ftp.ntransfercmd(cmd, None if offset == 0 else offset) #explicit None -        if size: -            self.size = size + offset -        while True: -            if self.abort: -                self.ftp.abort() -                break -            count = self.bufferSize -            if self.bucket: -                count = self.bucket.add(count) -                if count == 0: -                    sleep(0.01) -                    continue -             -            try: -                data = conn.recv(count) -            except: -                self.deferred.error("timeout") -             -            if self.speedCalcTime < inttime(): -                self.speed = self.speedCalcLen -                self.speedCalcTime = inttime() -                self.speedCalcLen = 0 -                try: -                    self.deferred.progress("percent", 100-int((self.size - self.arrived)/float(self.size)*100)) -                except: -                    pass -            size = len(data) -            self.speedCalcLen += size -            self.arrived += size -             -            if not data: -                break -             -            self.fh.write(data) -        self.fh.close() -        conn.close() -        self.endTime = inttime() -        if not self.abort: -            print self.ftp.voidresp() #debug -         -            self.ftp.quit() -        if self.abort: -            self.deferred.error("abort") -        elif self.size is None or self.size == self.arrived: -            self.deferred.callback() -        else: -            self.deferred.error("wrong content lenght") -     -    def download(self, resume=False): -        self.fh = open("%s.part" % self.filename, "ab" if resume else "wb") -        offset = 0 -        if resume: -            offset = getsize("%s.part" % self.filename) -         -        up = urlparse(self.url) -         -        self.ftp.connect(up.hostname, up.port if up.port else 21, proxies=self.proxies) -        self.ftp.login(up.username, up.password) -        self.ftp.cwd("/".join(up.path.split("/")[:-1])) -        self.ftp.voidcmd('TYPE I') -        self.size = self.ftp.size(self.url.split("/")[-1]) -         -        self._download(offset) -        return WrappedFTPDeferred(self, self.deferred) - -if __name__ == "__main__": -    import sys -    from Bucket import Bucket -    bucket = Bucket() -    bucket.setRate(200*1000) -    #bucket = None -     -    url = "ftp://mirror.sov.uk.goscomb.net/ubuntu-releases/maverick/ubuntu-10.10-desktop-i386.iso" -     -    finished = False -    def err(*a, **b): -        print a, b -    def callb(*a, **b): -        global finished -        finished = True -        print a, b -     -    print "starting" -     -    dwnld = FTPDownload(url, "ubuntu_ftp.iso") -    d = dwnld.download(resume=True) -    d.addCallback(callb) -    d.addErrback(err) -     -    try: -        while True: -            if not dwnld.finished: -                print dwnld.speed/1024, "kb/s", "size", dwnld.arrived, "/", dwnld.size#, int(float(dwnld.arrived)/dwnld.size*100), "%" -            if finished: -                print "- finished" -                break -            sleep(1) -    except KeyboardInterrupt: -        dwnld.abort = True -        sys.exit() diff --git a/module/network/HTTPChunk.py b/module/network/HTTPChunk.py index 440115c77..680b982d3 100644 --- a/module/network/HTTPChunk.py +++ b/module/network/HTTPChunk.py @@ -28,6 +28,7 @@ from HTTPRequest import HTTPRequest  class WrongFormat(Exception):      pass +  class ChunkInfo():      def __init__(self, name):          self.name = name @@ -115,6 +116,7 @@ class ChunkInfo():      def getChunkRange(self, index):          return self.chunks[index][1] +  class HTTPChunk(HTTPRequest):      def __init__(self, id, parent, range=None, resume=False):          self.id = id @@ -123,6 +125,7 @@ class HTTPChunk(HTTPRequest):          self.resume = resume          self.log = parent.log +        self.size = range[1] - range[0] if range else -1          self.arrived = 0          self.lastURL = self.p.referer @@ -136,11 +139,13 @@ class HTTPChunk(HTTPRequest):          self.initHandle()          self.setInterface(self.p.options["interface"], self.p.options["proxies"], self.p.options["ipv6"]) -        self.BOMChecked = False -        # check and remove byte order mark +        self.BOMChecked = False # check and remove byte order mark          self.rep = None +        self.sleep = 0.000 +        self.lastSize = 0 +      @property      def cj(self):          return self.p.cj @@ -218,11 +223,21 @@ class HTTPChunk(HTTPRequest):          if self.p.bucket:              sleep(self.p.bucket.consumed(size)) -        elif size < 5000: #@TODO nice to have: traffic sharping algr. which calculates sleep time to reduce cpu load -            #sleep if chunk size gets low, to avoid many function calls and hope chunksize gets bigger -            sleep(0.007) +        else: +            # Avoid small buffers, increasing sleep time slowly if buffer size gets smaller +            # otherwise reduce sleep time percentual (values are based on tests) +            # So in general cpu time is saved without reducing bandwith too much -        if self.range and self.arrived > (self.range[1] - self.range[0]): +            if size < self.lastSize: +                self.sleep += 0.002 +            else: +                self.sleep *= 0.7 + +            self.lastSize = size + +            sleep(self.sleep) + +        if self.range and self.arrived > self.size:              return 0 #close if we have enough data @@ -244,6 +259,10 @@ class HTTPChunk(HTTPRequest):          self.headerParsed = True +    def setRange(self, range): +        self.range = range +        self.size = range[1] - range[0] +      def close(self):          """ closes everything, unusable after this """          if self.fp: self.fp.close() diff --git a/module/network/HTTPDownload.py b/module/network/HTTPDownload.py index ac3252f68..f616b16b5 100644 --- a/module/network/HTTPDownload.py +++ b/module/network/HTTPDownload.py @@ -33,6 +33,7 @@ from module.utils import save_join  class HTTPDownload():      """ loads a url http + ftp """ +      def __init__(self, url, filename, get={}, post={}, referer=None, cj=None, bucket=None,                   options={}, progressNotify=None, disposition=False):          self.url = url @@ -69,7 +70,7 @@ class HTTPDownload():          self.lastArrived = []          self.speeds = []          self.lastSpeeds = [0, 0] -         +          self.progressNotify = progressNotify      @property @@ -93,7 +94,8 @@ class HTTPDownload():              fo = open(init, "rb+") #first chunkfile              for i in range(1, self.info.getCount()):                  #input file -                fo.seek(self.info.getChunkRange(i - 1)[1] + 1) #seek to beginning of chunk, to get rid of overlapping chunks +                fo.seek( +                    self.info.getChunkRange(i - 1)[1] + 1) #seek to beginning of chunk, to get rid of overlapping chunks                  fname = "%s.chunk%d" % (self.filename, i)                  fi = open(fname, "rb")                  buf = 32 * 1024 @@ -113,7 +115,7 @@ class HTTPDownload():          if self.nameDisposition and self.disposition:              self.filename = save_join(dirname(self.filename), self.nameDisposition) -             +          move(init, self.filename)          self.info.remove() #remove info file @@ -164,7 +166,7 @@ class HTTPDownload():          chunksCreated = False          done = False          if self.info.getCount() > 1: # This is a resume, if we were chunked originally assume still can -            self.chunkSupport=True +            self.chunkSupport = True          while 1:              #need to create chunks @@ -177,7 +179,7 @@ class HTTPDownload():                  chunks = self.info.getCount() -                init.range = self.info.getChunkRange(0) +                init.setRange(self.info.getChunkRange(0))                  for i in range(1, chunks):                      c = HTTPChunk(i, self, self.info.getChunkRange(i), resume) @@ -191,10 +193,8 @@ class HTTPDownload():                          self.log.debug("Invalid curl handle -> closed")                          c.close() -                  chunksCreated = True -              while 1:                  ret, num_handles = self.m.perform()                  if ret != pycurl.E_CALL_MULTI_PERFORM: @@ -215,7 +215,7 @@ class HTTPDownload():                      #@TODO KeyBoardInterrupts are seen as finished chunks,                      #but normally not handled to this process, only in the testcase -                     +                      chunksDone.add(curl)                  if not num_q:                      lastFinishCheck = t @@ -243,7 +243,7 @@ class HTTPDownload():              if self.abort:                  raise Abort() -            sleep(0.003) #supress busy waiting - limits dl speed to  (1 / x) * buffersize +            #sleep(0.003) #supress busy waiting - limits dl speed to  (1 / x) * buffersize              self.m.select(1)          failed = False @@ -261,11 +261,11 @@ class HTTPDownload():          if failed: raise BadHeader(failed)          self._copyChunks() -     +      def updateProgress(self):          if self.progressNotify:              self.progressNotify(self.percent) -     +      def close(self):          """ cleanup """          for chunk in self.chunks: diff --git a/module/plugins/hoster/Ftp.py b/module/plugins/hoster/Ftp.py index ca0689c62..7c2af85ed 100644 --- a/module/plugins/hoster/Ftp.py +++ b/module/plugins/hoster/Ftp.py @@ -23,15 +23,14 @@ from module.plugins.Hoster import Hoster  class Ftp(Hoster):
      __name__ = "Ftp"
 -    __version__ = "0.3"
 -    __pattern__ = r'ftp://(.*?:.*?@)?.*?/.*' # ftp://user:password@ftp.server.org/path/to/file
 +    __version__ = "0.31"
 +    __pattern__ = r'(ftps?|sftp)://(.*?:.*?@)?.*?/.*' # ftp://user:password@ftp.server.org/path/to/file
      __type__ = "hoster"
      __description__ = """A Plugin that allows you to download from an from an ftp directory"""
      __author_name__ = ("jeix", "mkaay")
      __author_mail__ = ("jeix@hasnomail.com", "mkaay@mkaay.de")
      def process(self, pyfile):
 -        self.req = pyfile.m.core.requestFactory.getRequest(self.__name__)
          pyfile.name = self.pyfile.url.rpartition('/')[2]
          self.chunkLimit = -1
 diff --git a/module/plugins/hoster/ShareonlineBiz.py b/module/plugins/hoster/ShareonlineBiz.py index afc7312f1..2a6645e86 100644 --- a/module/plugins/hoster/ShareonlineBiz.py +++ b/module/plugins/hoster/ShareonlineBiz.py @@ -101,6 +101,10 @@ class ShareonlineBiz(Hoster):              if r"Der Download ist Ihnen zu langsam" not in self.html and r"The download is too slow for you" not in self.html:                  self.fail("Plugin defect. Save dumps and report.") + +        if "Kein weiterer Download-Thread möglich!" in self.html: #TODO corresponding translation +            self.retry(wait_time=30, reason=_("Parallel download issue")) +          m = re.search("var wait=(\d+);", self.html[1])          wait_time = int(m.group(1)) if m else 30          self.setWait(wait_time) diff --git a/module/web/templates/default/package_ui.js b/module/web/templates/default/package_ui.js index 4913f1543..3aee766ac 100644 --- a/module/web/templates/default/package_ui.js +++ b/module/web/templates/default/package_ui.js @@ -315,6 +315,7 @@ var Package = new Class({              }.bind(this),              onFailure: indicateFail          }).send(); +        hide_pack();      },      restartPackage: function(event) { diff --git a/module/web/webinterface.py b/module/web/webinterface.py index d6b7f8438..f6ad35138 100644 --- a/module/web/webinterface.py +++ b/module/web/webinterface.py @@ -62,8 +62,7 @@ LOG_ROOT = config.get('log', 'log_folder')  PREFIX = config.get('webinterface', 'prefix')  if PREFIX: -    if PREFIX.endswith("/"): -        PREFIX = PREFIX[:1] +    PREFIX = PREFIX.rstrip("/")      if not PREFIX.startswith("/"):          PREFIX = "/" + PREFIX | 
