Пример #1
0
def execute_function(
    function_name: str,
    args: List[str],
    loop: asyncio.AbstractEventLoop,
) -> None:
    """
    Runs a function with the given args

    :param function_name: string name of the function to run
    :param args: arguments for the function to run
    """
    # TODO: add real drop/metadata request commands that interface
    #  with the filesystem
    # TODO: handle exceptions for real
    # for functions that create or destroy the init directory
    if function_name == "node_init":
        node_init.initialize_node(*args)
    elif function_name == "node_force_init":
        node_init.force_initialize_node(*args)
    elif function_name == "delete_node":
        node_init.delete_node_directory(*args)

    # drop functions
    elif function_name == "drop_init":
        drop_init.initialize_drop(args[0])

    elif function_name == "make_new_version":
        drop_id = crypto_util.b64decode(args[0].encode())
        task = asyncio.run_coroutine_threadsafe(
            drop_util.make_new_version(drop_id),
            loop,
        )
        task.result()
        # loop.call_soon_threadsafe(task)
        # while not task.done():
        #     time.sleep(10)

    elif function_name == "sync_drop":
        drop_id = crypto_util.b64decode(args[0].encode())

        # takes drop_id as b64 and save+directory
        async def sync_wrapper(drop_id: bytes, save_dir: str) -> None:

            await drop_util.sync_drop(drop_id, save_dir)

        task = asyncio.run_coroutine_threadsafe(
            sync_wrapper(drop_id, args[1]),
            loop,
        )
        task.result()

    else:
        print("Function [%s] not found" % (function_name))
Пример #2
0
def list_drops() -> List[bytes]:
    """
    List the drops on this node

    :return: List of drop IDs
    """
    save_path = _get_save_path()
    names = os.listdir(save_path)

    return [crypto_util.b64decode(os.fsencode(e)) for e in names]
Пример #3
0
async def handle_remove_owner(
    request: Dict[str, Any],
    conn: asyncio.StreamWriter,
) -> None:
    """
    Handling function to remove an owner from a drop

    :param request: { \
    "action": string, \
    "drop_id": string, \
    "owner_id": string, \
    }
    :param conn: socket.accept() connection
    :return: None
    """

    if request['drop_id'] is None or request['owner_id'] is None:
        response = {
            'status': 'error',
            'error': ERR_INVINPUT,
        }
    else:
        drop_id = crypto_util.b64decode(request['drop_id'])
        owner_id = crypto_util.b64decode(request['owner_id'])
        response = {
            'status': 'ok',
            'result': 'success',
            'message': 'owner successfully removed',
        }

        await make_new_version(
            drop_id,
            remove_secondary_owner=owner_id,
        )

        md = await get_drop_metadata(drop_id, [])

        if owner_id in md.other_owners:
            response['result'] = 'failure'
            response['message'] = 'unable to remove owner from drop'

    await send_response(conn, response)
Пример #4
0
async def handle_input_subscribe_drop(
    request: Dict[str, Any],
    conn: asyncio.StreamWriter,
) -> None:
    """
    Handling function to subscribe to drop that user specifies.

    :param request: { \
    "action": string, \
    "drop_id": string, \
    "file_path": string, \
    }
    :param conn: socket.accept() connection
    :return: None
    """
    if request.get('drop_id') is None or request.get('directory') is None:
        response = {
            'status': 'error',
            'error': ERR_INVINPUT,
        }
    else:

        drop_id = crypto_util.b64decode(request['drop_id'])
        file_path = request['directory']

        metadata = await do_metadata_request(drop_id, [])

        if metadata is None:
            response = {
                'status': 'error',
                'error': ERR_INVINPUT,
            }
            await send_response(conn, response)
            return

        name = metadata.name
        full_path = os.path.join(file_path, name)

        try:
            await queue_sync(drop_id, full_path)
            response = {
                'status': 'ok',
                'result': 'success',
                'message': 'subscribed to drop ' + name,
            }
        except RuntimeError:
            response = {
                'status': 'error',
                'result': 'failure',
                'message': 'Cannot subscribe to drop!',
            }

    await send_response(conn, response)
Пример #5
0
async def a_main() -> None:
    """Lots to await on, so call this whole function in a run_until_complete"""
    args = parser().parse_args()

    id_prefix = b'dropid:'

    drop_id = args.drop_id.encode('utf-8')
    if drop_id.startswith(id_prefix):
        drop_id = crypto_util.b64decode(drop_id[len(id_prefix):])
    else:
        raise ValueError("drop Id must start with prefix 'dropid:'")

    drop_location = await get_drop_location(drop_id)
    metadata_dir = os.path.join(drop_location, DEFAULT_DROP_METADATA_LOCATION)
    file_metadata_dir = os.path.join(
        drop_location,
        DEFAULT_FILE_METADATA_LOCATION,
    )
    metadata = await DropMetadata.read_file(
        id=drop_id,
        metadata_location=metadata_dir,
        version=None,
    )

    if metadata is None:
        logger.error("Drop metadata not found, failing")
        exit(1)

    for file_name, file_id in metadata.files.items():
        file_metadata = await FileMetadata.read_file(
            file_id=file_id,
            metadata_location=file_metadata_dir,
            file_name=file_name,
        )

        if file_metadata is None:
            logger.error("File metadata for %s not found, exiting", file_name)
            exit(1)

        file_metadata.file_name = file_name

        needed_chunks = await file_metadata.needed_chunks
        if needed_chunks:
            logger.error(
                "File %s has needed chunks %s, exiting",
                file_name,
                needed_chunks,
            )
            exit(1)

    logger.info("All good, exiting with success")
    exit(0)
Пример #6
0
def main() -> None:
    args = parser().parse_args()

    loop = asyncio.get_event_loop()

    id = crypto_util.b64decode(args.drop_id.encode('utf-8'))

    done, _ = loop.run_until_complete(drop_util.sync_drop(id, args.directory))

    if done:
        print("Drop successfully synced")
    else:
        print("Drop not completed, re-run command")
Пример #7
0
def get_drop_id_from_directory(save_dir: str) -> Optional[bytes]:
    """
    Figure out the drop ID from a directory

    :param save_dir: The directory to check
    :return: The drop ID or none
    """
    metadata_dir = os.path.join(save_dir, DEFAULT_DROP_METADATA_LOCATION)
    files = os.listdir(metadata_dir)

    for f in files:
        full_name = os.path.join(metadata_dir, f)
        if os.path.isfile(full_name) and f.endswith("_LATEST"):
            b = f.split("_")[0]
            return crypto_util.b64decode(b.encode('utf-8'))

    return None
Пример #8
0
async def handle_unsubscribe(
    request: Dict[str, Any],
    conn: asyncio.StreamWriter,
) -> None:
    """
    Handling function to unsubscribe from a subscribed drop.

    :param request: { \
    "action": string, \
    "drop_id": string, \
    }
    :param conn: socket.accept() connection
    :return: None
    """
    if request['drop_id'] is None:
        response = {
            'status': 'error',
            'error': ERR_INVINPUT,
        }
    else:
        drop_id = crypto_util.b64decode(request['drop_id'])
        file_location = await get_drop_location(drop_id)
        file_location = os.path.join(
            file_location,
            DEFAULT_DROP_METADATA_LOCATION,
        )
        drop_metadata = await DropMetadata.read_file(
            id=drop_id,
            metadata_location=file_location,
        )
        if drop_metadata is None:
            response = {
                'status': 'error',
                'error': ERR_INVINPUT,
            }
        else:
            drop_metadata.unsubscribe()
            response = {
                'status': 'ok',
                'result': 'success',
                'message': 'unsubscribed from drop ' + request['drop_id'],
            }

    await send_response(conn, response)
Пример #9
0
def main() -> None:
    args = parser().parse_args()
    loop = asyncio.get_event_loop()

    if not (args.drop_id or args.save_dir):
        print("Either drop id or save dir must be specified")
        exit(1)

    if args.drop_id:
        drop_id = args.drop_id.encode('utf-8')
        drop_id = crypto_util.b64decode(drop_id)
    if not args.drop_id:
        drop_id = drop_util.get_drop_id_from_directory(args.save_dir)

    if drop_id is None:
        print("Drop ID not found")
        exit(1)

    loop.run_until_complete(drop_util.make_new_version(drop_id))
Пример #10
0
async def handle_make_new_version(
    request: Dict[str, Any],
    conn: asyncio.StreamWriter,
) -> None:
    if request['drop_id'] is None:
        response = {
            'status': 'error',
            'error': ERR_INVINPUT,
        }
    else:
        drop_id = crypto_util.b64decode(request['drop_id'])

        await make_new_version(drop_id)

        response = {
            'status': 'ok',
            'result': 'success',
            'message': 'new version created',
        }

    await send_response(conn, response)
Пример #11
0
def main() -> None:
    args = parser().parse_args()
    loop = asyncio.get_event_loop()

    if not (args.drop_id or args.save_dir):
        print("Either drop id or save dir must be specified")
        exit(1)

    if args.drop_id:
        drop_id = args.drop_id.encode('utf-8')
        drop_id = crypto_util.b64decode(drop_id)
    if not args.drop_id:
        drop_id = drop_util.get_drop_id_from_directory(args.save_dir)

    if drop_id is None:
        print("Drop ID not found")
        exit(1)

    md, update_avail = loop.run_until_complete(
        drop_util.check_for_update(drop_id),
    )
    if not update_avail or md is None:
        print("No update available, exiting")
        exit(0)

    drop_dir = loop.run_until_complete(
        drop_metadata.get_drop_location(drop_id),
    )

    done, _ = loop.run_until_complete(
        drop_util.sync_drop(drop_id, drop_dir, md.version),
    )

    if done:
        print("updated successfully")
        exit(0)
    else:
        print("did not update succussfully")
        exit(1)
Пример #12
0
async def _handle_selected_drop(
    get_pending_changes: bool,
    request: Dict[str, Any],
    conn: asyncio.StreamWriter,
) -> None:
    """
    Handling function to a drop selected by user.

    :param request: { \
    "action": string, \
    "drop_id": string, \
    }
    :param conn: socket.accept() connection
    :return: None
    """

    if request['drop_id'] is None:
        response = {
            'status': 'error',
            'error': ERR_INVINPUT,
        }
    else:
        drop_id = crypto_util.b64decode(request['drop_id'])
        md = await get_drop_metadata(drop_id, [])
        drop = await drop_metadata_to_response(md)
        if get_pending_changes:
            file_update_status = await check_for_changes(drop_id)
            if file_update_status is None:
                local_pending_changes = {}  # type: Dict[str, List[str]]
            else:
                local_pending_changes = {
                    'added': list(file_update_status.added),
                    'removed': list(file_update_status.removed),
                    'changed': list(file_update_status.changed),
                    'unchanged': list(file_update_status.unchanged),
                }

            new_metadata, new_version_available = \
                await check_for_update(drop_id)
            remote_pending_changes = {}  # type: Dict[str, List[str]]
            if new_version_available:
                remote_update_status = await find_changes_in_new_version(
                    drop_id,
                    new_metadata,
                )
                if remote_update_status is not None:
                    remote_pending_changes = {
                        'added': list(remote_update_status.added),
                        'removed': list(remote_update_status.removed),
                        'changed': list(remote_update_status.changed),
                        'unchanged': list(remote_update_status.unchanged),
                    }
        else:
            local_pending_changes = {}
        if drop is None:
            response = {
                'status': 'error',
                'result': 'failure',
                'requested_drops': {},
                'message': 'drop retrieval failed',
            }
        else:
            response = {
                'status': 'ok',
                'result': 'success',
                'message': 'selected files retrieved',
                'requested_drops': {
                    'drop': drop,
                    'pending_changes': local_pending_changes,
                    'remote_pending_changes': remote_pending_changes,
                },
            }

    await send_response(conn, response)