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))
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]
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)
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)
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)
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")
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
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)
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))
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)
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)
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)