예제 #1
0
def get_download_url(conf, fileid):
    """the api to download just redirects to the real url to download

    :conf: configuration object
    :fileid: fileid to download
    :returns: the download url

    """
    LOG.debug(
        'trying to dereference download url for file id: %s',
        str(fileid))
    try:
        conn = httplib.HTTPSConnection('api.put.io')
        url = API_URL + \
            '/files/%s/download?oauth_token=' + conf.get('oauthtoken')
        url = url % fileid
        conn.request("GET", url, None, {'User-Agent': USER_AGENT})
        response = conn.getresponse()
        if response.status == 302:
            return response.getheader('Location')
        else:
            LOG.error(
                'putio api returned status %d for download: %s',
                response.status, url)
            return None
    except (httplib.HTTPException, IOError, OSError):
        LOG.error(
            'error dereferencing download url for file id: %s',
            str(fileid), exc_info=True)
        return None
예제 #2
0
def make_api_request(conf, resource, params, compress=True):
    """makes an http call to put.io api

    :conf: configuration object
    :resource: the REST resource in the api
    :params: a dictionary of url parameters key-val
    :returns: raw response from http response or None if failed

    """
    params['oauth_token'] = conf.get('oauthtoken')
    url = API_URL + resource + '?' + urlencode(params)
    LOG.debug('making http request: %s', url)
    req = urllib2.Request(url)
    req.add_header('User-Agent', USER_AGENT)
    req.add_header('Accept', 'application/json')
    if compress:
        req.add_header('Accept-Encoding', 'gzip;q=1.0,deflate;q=0.5,*;q=0')
    try:
        response = urllib2.urlopen(req)
        if response.getcode() == 200:
            content = response.read()
            try:
                if compress:
                    try:
                        inflated = gzip.GzipFile(
                            fileobj=StringIO.StringIO(content))

                        return json.loads(inflated.read())
                    except IOError:
                        LOG.error(
                            'request failed due to IO error, content',
                            exc_info=True)

                        return json.loads(content)
                else:
                    return json.loads(content)
            except ValueError:
                LOG.error(
                    'cant parse api response: %s',
                    content,
                    exc_info=True)

                return None
        elif response.getcode() == 302:
            LOG.debug('got redirect: %s', str(response.info()))
            return response.info()
        else:
            LOG.error('request failed %s status: %s', url, response.getcode())

    except urllib2.HTTPError as exc:
        LOG.error(
            'request failed %s status: %s message: %s',
            url,
            exc.code,
            exc.reason)

    return None
예제 #3
0
def start_download(filesize, download_url, targetfile, conf):
    """downloads the file"""
    suspend_until_can_store_file(filesize, targetfile)
    bps = conf.get('bytes_per_second')
    connections = conf.get('conn_per_downloads')

    print '\nStarting download :%s' % download_url
    LOG.info('starting download :%s into %s', download_url, targetfile)
    cmd = 'axel -o %s -n %d -a -s %d %s' % (targetfile, connections, bps,
                                            download_url)
    LOG.debug('running axel: %s', cmd)
    axel = subprocess.Popen([
        'axel', '-o', targetfile, '-a', '-s',
        str(bps), '-n',
        str(connections), download_url
    ])

    currsize = os.path.getsize(targetfile) if os.path.exists(targetfile) else 0
    pollinterval = 5
    time.sleep(pollinterval)
    remaining_attempts = 3
    while axel.poll() is None:
        time.sleep(pollinterval)
        progress = os.path.getsize(targetfile) - currsize
        currsize = currsize + progress
        if progress == 0:
            LOG.warn('seems like axel isnt effective in the last %d seconds',
                     pollinterval)
            if remaining_attempts == 0:
                LOG.error('axel seems totally stuck, aborting')
                axel.kill()
                return

            remaining_attempts = remaining_attempts - 1
            pollinterval = pollinterval * 2

    returncode = axel.poll()
    if returncode != 0:
        print '\n[E] Download %s failed!' % download_url
        LOG.error('download %s failed with code: %d', download_url, returncode)
        return

    if os.path.exists(targetfile):
        if os.path.getsize(targetfile) != filesize:
            LOG.info('detected partial download %s due to file size',
                     targetfile)
            try:
                os.remove(targetfile)
            except (OSError, IOError):
                print '\n[E] Cant remove bad download %s' % targetfile
                LOG.error('cant remove bad download %s',
                          targetfile,
                          exc_info=True)
예제 #4
0
파일: start.py 프로젝트: weop/putiosync
def __create_local_dirs(root, dirtree, files_to_dirs):
    """creates the local dir tree

    :conf: configuration object
    :dirtree: the tree fetched from the putio account
    :files_to_dirs: a mapping of file data to the dir the file should
            be downloaded to
    :returns: None

    """

    todelete = os.listdir(root)

    for name, remoteitem in dirtree.iteritems():
        if name in todelete:
            todelete.remove(name)

        if remoteitem is None:
            print ('Skipping dir %s because no data for it', name)
            LOG.error('skipping dir %s because no data for it', name)
            continue

        target = os.path.join(root, name)
        if remoteitem.isdir():
            LOG.debug('inspecting dir: %s', name)
            # this is a directory
            if os.path.exists(target) and not os.path.isdir(target):
                LOG.warn(
                    "remote dir and local file conflict" +
                    "removing local file: %s",
                    target)
                os.remove(target)

            if not os.path.exists(target):
                LOG.debug('creating dir: %s', target)
                os.makedirs(target)

            if remoteitem.dirtree:
                __create_local_dirs(target, remoteitem.dirtree, files_to_dirs)
            elif os.path.exists(target):
                todelete.append(name)

        else:
            LOG.debug('inspecting file: %s', name)
            # this is a normal file
            exists = os.path.exists(target)
            if exists and os.path.getsize(target) != remoteitem.size:
                LOG.warn('file size != from whats on putio: %s', target)
                todelete.append(name)
                files_to_dirs[remoteitem] = target
            elif not exists:
                LOG.debug(
                    'file will be downloaded: %s -> %s',
                    remoteitem,
                    target)
                files_to_dirs[remoteitem] = target

    sync_utils.delete_files(root, todelete)
예제 #5
0
def __create_local_dirs(root, dirtree, files_to_dirs):
    """creates the local dir tree

    :conf: configuration object
    :dirtree: the tree fetched from the putio account
    :files_to_dirs: a mapping of file data to the dir the file should
            be downloaded to
    :returns: None

    """

    todelete = os.listdir(root)

    for name, remoteitem in dirtree.iteritems():
        if name in todelete:
            todelete.remove(name)

        if remoteitem is None:
            print('Skipping dir %s because no data for it', name)
            LOG.error('skipping dir %s because no data for it', name)
            continue

        target = os.path.join(root, name)
        if remoteitem.isdir():
            LOG.debug('inspecting dir: %s', name)
            # this is a directory
            if os.path.exists(target) and not os.path.isdir(target):
                LOG.warn(
                    "remote dir and local file conflict" +
                    "removing local file: %s", target)
                os.remove(target)

            if not os.path.exists(target):
                LOG.debug('creating dir: %s', target)
                os.makedirs(target)

            if remoteitem.dirtree:
                __create_local_dirs(target, remoteitem.dirtree, files_to_dirs)
            elif os.path.exists(target):
                todelete.append(name)

        else:
            LOG.debug('inspecting file: %s', name)
            # this is a normal file
            exists = os.path.exists(target)
            if exists and os.path.getsize(target) != remoteitem.size:
                LOG.warn('file size != from whats on putio: %s', target)
                todelete.append(name)
                files_to_dirs[remoteitem] = target
            elif not exists:
                LOG.debug('file will be downloaded: %s -> %s', remoteitem,
                          target)
                files_to_dirs[remoteitem] = target

    sync_utils.delete_files(root, todelete)
예제 #6
0
def __get_putio_files(conf, parent_id=0, tree=None, root=None):
    """fetches the file list from put.io account

    :conf: configuration object
    :parent_id: the from which to start on the account
    :returns: a dict of dicts representing the account directory tree
    """
    if not tree:
        tree = {}

    if not root:
        root = '/'

    data = putio_api.getfiles(conf, parent_id)
    putio_api.ensure_valid_oauth_token(data)
    freshtree = {}
    if data:
        LOG.debug('got data for file id: %d', parent_id)
        for remotefile in data.get('files'):
            filename = remotefile.get('name')
            filetype = remotefile.get('file_type')
            fileid = remotefile.get('id')
            filesize = remotefile.get('size')
            abspath = root + '/' + filename

            skip = False
            for exclude in EXCLUDE_LIST:
                skip = abspath == exclude or re.search(exclude, abspath)
                if skip:
                    LOG.info('skipping because exclude rule match (%s ~ %s)',
                             exclude, abspath)
                    break
            if skip:
                continue

            if filetype == PUTIO_DIR_FTP:
                cached = tree.get(filename, None)
                cached_filesize = cached.size if cached else 0
                if cached:
                    freshtree[filename] = cached

                if filesize != cached_filesize:
                    subtree = cached.dirtree if cached else {}
                    subtree = __get_putio_files(conf, fileid, subtree, abspath)
                    freshtree[filename] = RemoteItem(filename, filesize,
                                                     fileid, subtree)
                    LOG.debug('mapped directory: %s', freshtree[filename])

            else:
                filedata = RemoteItem(filename, filesize, fileid, None)
                LOG.debug('mapped file: %s', filedata)
                freshtree[filename] = filedata

        tree = freshtree

    return tree
예제 #7
0
파일: start.py 프로젝트: weop/putiosync
def __get_putio_files(conf, parent_id=0, tree=None, root=None):
    """fetches the file list from put.io account

    :conf: configuration object
    :parent_id: the from which to start on the account
    :returns: a dict of dicts representing the account directory tree
    """
    if not tree:
        tree = {}

    if not root:
        root = '/'

    data = putio_api.getfiles(conf, parent_id)
    putio_api.ensure_valid_oauth_token(data)
    freshtree = {}
    if data:
        LOG.debug('got data for file id: %d', parent_id)
        for remotefile in data.get('files'):
            filename = remotefile.get('name')
            filetype = remotefile.get('file_type')
            fileid = remotefile.get('id')
            filesize = remotefile.get('size')
            abspath = root + '/' + filename

            skip = False
            for exclude in EXCLUDE_LIST:
                skip = abspath == exclude or re.search(exclude, abspath)
                if skip:
                    LOG.info('skipping because exclude rule match (%s ~ %s)',
                             exclude, abspath)
                    break
            if skip:
                continue

            if filetype == PUTIO_DIR_FTP:
                cached = tree.get(filename, None)
                cached_filesize = cached.size if cached else 0
                if cached:
                    freshtree[filename] = cached

                if filesize != cached_filesize:
                    subtree = cached.dirtree if cached else {}
                    subtree = __get_putio_files(conf, fileid, subtree, abspath)
                    freshtree[filename] = RemoteItem(
                        filename, filesize, fileid, subtree)
                    LOG.debug('mapped directory: %s', freshtree[filename])

            else:
                filedata = RemoteItem(filename, filesize, fileid, None)
                LOG.debug('mapped file: %s', filedata)
                freshtree[filename] = filedata

        tree = freshtree

    return tree
예제 #8
0
def suspend_sync():
    """simple sleep helper"""
    sleep_seconds = 60 * 1
    LOG.debug('sleeping for %d seconds', sleep_seconds)
    time.sleep(sleep_seconds)
예제 #9
0
def suspend_sync():
    """simple sleep helper"""
    sleep_seconds = 60 * 1
    LOG.debug('sleeping for %d seconds', sleep_seconds)
    time.sleep(sleep_seconds)
예제 #10
0
def start_download(filesize, download_url, targetfile, conf):
    """downloads the file"""
    suspend_until_can_store_file(filesize, targetfile)
    bps = conf.get('bytes_per_second')
    connections = conf.get('conn_per_downloads')

    print '\nStarting download :%s' % download_url
    LOG.info('starting download :%s into %s', download_url, targetfile)
    cmd = 'axel -o %s -n %d -a -s %d %s' % (targetfile,
                                            connections,
                                            bps,
                                            download_url)
    LOG.debug('running axel: %s', cmd)
    axel = subprocess.Popen(
        ['axel',
         '-o',
         targetfile,
         '-a',
         '-s',
         str(bps),
         '-n',
         str(connections),
         download_url])

    currsize = os.path.getsize(targetfile) if os.path.exists(targetfile) else 0
    pollinterval = 5
    time.sleep(pollinterval)
    remaining_attempts = 3
    while axel.poll() is None:
        time.sleep(pollinterval)
        progress = os.path.getsize(targetfile) - currsize
        currsize = currsize + progress
        if progress == 0:
            LOG.warn('seems like axel isnt effective in the last %d seconds',
                     pollinterval)
            if remaining_attempts == 0:
                LOG.error('axel seems totally stuck, aborting')
                axel.kill()
                return

            remaining_attempts = remaining_attempts - 1
            pollinterval = pollinterval * 2

    returncode = axel.poll()
    if returncode != 0:
        print '\n[E] Download %s failed!' % download_url
        LOG.error(
            'download %s failed with code: %d',
            download_url,
            returncode)
        return

    if os.path.exists(targetfile):
        if os.path.getsize(targetfile) != filesize:
            LOG.info(
                'detected partial download %s due to file size',
                targetfile)
            try:
                os.remove(targetfile)
            except (OSError, IOError):
                print '\n[E] Cant remove bad download %s' % targetfile
                LOG.error(
                    'cant remove bad download %s',
                    targetfile,
                    exc_info=True)