예제 #1
0
    def get(self, path: str):
        """Retrieve a file under a given path."""
        internal_path = validate_path(path)

        parent = Path('/')
        entry = None
        for part in internal_path.parts:
            entry = mongo.db.index.find_one({
                'name': part,
                'parent': str(parent)
            })
            if entry is None:
                abort(404)
            parent /= part

        if entry is None or entry['is_directory'] or not entry['servers']:
            abort(404)

        server = choose_server(among=entry['servers'])

        file = requests.get(f'http://{server}/file/{internal_path}')
        if not file.ok:
            abort(400, 'File download failed.')

        response = current_app.make_response(file.content)
        response.headers.set('Content-Type',
                             mimetypes.guess_type(internal_path.name)[0])
        return response
예제 #2
0
    def delete(self, path):
        """Delete a file under a given path."""
        internal_path = validate_path(path)

        parent = Path('/')
        entry = None
        for part in internal_path.parts:
            entry = mongo.db.index.find_one({
                'name': part,
                'parent': str(parent)
            })
            if entry is None:
                abort(404)
            parent /= part

        if entry['is_directory']:
            abort(404)

        for server in entry['servers']:
            response = requests.delete(f'http://{server}/file/{internal_path}')
            mongo.db.servers.replace_one(
                {'_id': server},
                {
                    '_id': server,
                    'free_space': int(response.text)
                },
            )

        mongo.db.index.delete_one(entry)

        return jsonify(get_min_free_space())
예제 #3
0
    def put(self, path):
        """Update a file under a given path."""
        if 'file' not in request.files:
            abort(400, 'No file attached.')
        file = request.files['file']

        internal_path = validate_path(path)

        *parents, name = internal_path.parts
        parent = Path('/')
        entry = None
        for part in parents:
            entry = mongo.db.index.find_one({
                'name': part,
                'parent': str(parent)
            })
            if entry is None:
                mongo.db.index.insert_one({
                    'name': part,
                    'parent': str(parent),
                    'is_directory': True
                })
            parent /= part

        entry = mongo.db.index.find_one({'name': name, 'parent': str(parent)})
        if entry is not None:
            abort(400, 'A file with this name already exists.')

        ok_servers = []
        for server in mongo.db.servers.find():
            response = requests.post(
                f'http://{server["_id"]}/file/{internal_path}',
                files={'file': file.stream})
            if not response.ok:
                continue

            server['free_space'] = int(response.text)
            mongo.db.servers.replace_one({'_id': server['_id']}, server)
            ok_servers.append(server['_id'])

        mongo.db.index.replace_one({
            'name': name,
        }, {
            'name': name,
            'parent': str(parent),
            'is_directory': False,
            'size': get_file_size(file),
            'last_modified': int(time.time()),
            'servers': ok_servers,
        },
                                   upsert=True)

        return jsonify(get_min_free_space())
예제 #4
0
    def get(self, path: str):
        """Retrieve the listing of a given directory."""
        internal_path = validate_path(path)

        parent = Path('/')
        entry = {'name': '.', 'is_directory': True}
        for part in internal_path.parts:
            entry = mongo.db.index.find_one({
                'name': part,
                'parent': str(parent)
            })
            if entry is None:
                abort(404)
            parent /= part

        if not entry['is_directory']:
            abort(404)

        children = mongo.db.index.find({'parent': str(parent)})
        listing = []
        for child in children:
            if child['is_directory']:
                listing.append({
                    'name':
                    child['name'],
                    'path':
                    str(Path('/') / internal_path / child['name']) + '/',
                    'is_directory':
                    True,
                })
            else:
                listing.append({
                    'name':
                    child['name'],
                    'path':
                    str(Path('/') / internal_path / child['name']),
                    'is_directory':
                    False,
                    'size':
                    child['size'],
                    'replicas':
                    len(child['servers']),
                })

        return jsonify(listing)
예제 #5
0
    def delete(self, path: str):
        """Delete a directory."""
        internal_path = validate_path(path)

        parent = Path('/')
        entry = None
        for part in internal_path.parts:
            entry = mongo.db.index.find_one({
                'name': part,
                'parent': str(parent)
            })
            if entry is None:
                return NO_PAYLOAD
            parent /= part

        if not entry['is_directory']:
            abort(400, 'The path points to a file.')

        alright = str(parent).replace("/", "\\/")
        children = mongo.db.index.find({'parent': {'$regex': f'^{alright}.*'}})
        for child in children:
            if not child['is_directory']:
                for server in child['servers']:
                    response = requests.delete(
                        f'http://{server}/file{child["parent"]}/{child["name"]}'
                    )
                    mongo.db.servers.replace_one(
                        {'_id': server},
                        {
                            '_id': server,
                            'free_space': int(response.text)
                        },
                    )

            mongo.db.index.delete_one(child)

        mongo.db.index.delete_one(entry)

        return NO_PAYLOAD
예제 #6
0
    def post(self, path: str):
        """Create a directory."""
        internal_path = validate_path(path)

        parent = Path('/')
        entry = None
        for part in internal_path.parts:
            entry = mongo.db.index.find_one({
                'name': part,
                'parent': str(parent)
            })
            if entry is None:
                entry = {
                    'name': part,
                    'parent': str(parent),
                    'is_directory': True
                }
                mongo.db.index.insert_one(entry)
            parent /= part

        if not entry['is_directory']:
            abort(400, 'A file with this name already exists.')

        return NO_PAYLOAD
예제 #7
0
def copy(path: str):
    """Copy the file to the specified location."""
    src_internal_path = validate_path(path)
    dst_internal_path = validate_path(request.json["destination"].lstrip('/'))

    src_parent = Path('/')
    src_entry = None
    for part in src_internal_path.parts:
        src_entry = mongo.db.index.find_one({
            'name': part,
            'parent': str(src_parent)
        })
        if src_entry is None:
            abort(404)
        src_parent /= part

    if src_entry is None or src_entry[
            'is_directory'] or not src_entry['servers']:
        abort(404)

    *dst_parents, dst_name = dst_internal_path.parts
    dst_parent = Path('/')
    dst_entry = None
    for part in dst_parents:
        dst_entry = mongo.db.index.find_one({
            'name': part,
            'parent': str(dst_parent)
        })
        if dst_entry is None:
            mongo.db.index.insert_one({
                'name': part,
                'parent': str(dst_parent),
                'is_directory': True
            })
        dst_parent /= part

    dst_entry = mongo.db.index.find_one({
        'name': dst_name,
        'parent': str(dst_parent)
    })
    if dst_entry is not None:
        abort(400, 'A file with this name already exists.')

    server = choose_server(among=src_entry['servers'])

    file = requests.get(f'http://{server}/file/{src_internal_path}')
    if not file.ok:
        abort(400, 'Copying failed.')

    ok_servers = []
    for server in mongo.db.servers.find():
        response = requests.post(
            f'http://{server["_id"]}/file/{str(dst_internal_path)}',
            files={'file': io.BytesIO(file.content)})
        if not response.ok:
            continue

        server['free_space'] = int(response.text)
        mongo.db.servers.replace_one({'_id': server['_id']}, server)
        ok_servers.append(server['_id'])

    mongo.db.index.insert_one({
        'name': dst_name,
        'parent': str(dst_parent),
        'is_directory': False,
        'size': len(file.content),
        'last_modified': int(time.time()),
        'servers': ok_servers,
    })

    return jsonify(get_min_free_space())