def ping(config_file_path, logger=None): #lets a connector ping a remote connector peer if not logger: logger = aioconnectors.get_logger(logger_name='ping', first_run=True) logger.info('Creating connector api with config file '+config_file_path) connector_api = aioconnectors.ConnectorAPI(config_file_path=config_file_path) destination_id = None if connector_api.is_server: destination_id = input('\nPlease type the name of your remote client\n') loop = asyncio.get_event_loop() async def send_messages(destination_id): index = 0 while True: index += 1 print(f'\nSENDING PING to peer {destination_id or connector_api.server_sockaddr} with index {index}') response = await connector_api.send_message_await_response(data=f'PING {str(index)*5}', data_is_json=False, destination_id=destination_id, message_type='_ping', request_id=index) #response_id=None, binary=b'\x01\x02\x03\x04\x05', with_file=None, wait_for_ack=False) if response: try: transport_json, data, binary = response except Exception as exc: print(exc) return print(f'RECEIVING REPLY from peer {destination_id or connector_api.server_sockaddr} with data {data}') await asyncio.sleep(2) task_send = loop.create_task(send_messages(destination_id)) try: loop.run_forever() except: task_send.cancel() print('ping stopped !')
def test_receive_messages(config_file_path, logger=None): if not logger: logger = aioconnectors.get_logger(logger_name='test_receive_messages', first_run=True) print('Warning : No other application should be receiving events from this connector') logger.info('Creating connector api with config file '+config_file_path) connector_api = aioconnectors.ConnectorAPI(config_file_path=config_file_path) loop = asyncio.get_event_loop() tasks_waiting_for_messages = [] async def message_received_cb(logger, transport_json , data, binary): logger.info(f'RECEIVED MESSAGE {transport_json}') print(f'RECEIVED MESSAGE {transport_json}') if data: print(f'\tWith data {data.decode()}') if binary: print(f'\tWith binary {binary}') for message_type in connector_api.recv_message_types: task_api = loop.create_task(connector_api.start_waiting_for_messages(message_type=message_type, message_received_cb=message_received_cb)) tasks_waiting_for_messages.append(task_api) try: loop.run_forever() except: for message_type in connector_api.recv_message_types: connector_api.stop_waiting_for_messages(message_type=message_type) #for task_api in tasks_waiting_for_messages: # task_api.cancel() print('test_receive_messages stopped !')
def test_publish_messages(config_file_path, logger=None): if not logger: logger = aioconnectors.get_logger(logger_name='test_publish_messages', first_run=True) logger.info('Creating connector api with config file '+config_file_path) connector_api = aioconnectors.ConnectorAPI(config_file_path=config_file_path) destination_id = None if connector_api.is_server: destination_id = input('\nPlease type the name of your remote client\n') loop = asyncio.get_event_loop() async def send_messages(destination_id): index = 0 while True: index += 1 for message_type in connector_api.send_message_types: if message_type == '_pubsub': continue print(f'PUBLISHING MESSAGE to peer {destination_id or connector_api.server_sockaddr} of type ' f'{message_type} and index {index}') response = await connector_api.publish_message(data=f'"TEST_MESSAGE {str(index)*5}"', data_is_json=False, destination_id=destination_id, message_type=message_type, await_response=False, request_id=index) #response_id=None, binary=b'\x01\x02\x03\x04\x05', with_file=None, wait_for_ack=False) await asyncio.sleep(2) task_send = loop.create_task(send_messages(destination_id)) try: loop.run_forever() except: task_send.cancel() print('test_publish_messages stopped !')
def chat(args, logger=None): #chat supports sending messages and files/directories between 2 connectors if not logger: logger = aioconnectors.get_logger(logger_name='chat', first_run=True) custom_prompt = 'aioconnectors>> ' chat_client_name = 'chat_client' CONNECTOR_FILES_DIRPATH = aioconnectors.get_tmp_dir() delete_connector_dirpath_later = not os.path.exists(CONNECTOR_FILES_DIRPATH) is_server = not args.target accept_all_clients = args.accept loop = asyncio.get_event_loop() cwd = os.getcwd() class AuthClient: #helper for client authentication on server connector perform_client_authentication = False authenticate = asyncio.Event() allow = False @staticmethod def update_allow(status): #User chooses the value of "allow", which is sent back to server connector AuthClient.allow = status AuthClient.perform_client_authentication = False AuthClient.authenticate.set() @staticmethod async def authenticate_client(client_name): #called as a hook by server when receiving new connection #waits for user input AuthClient.perform_client_authentication = True print(f'Accept client {client_name} ? y/n') await AuthClient.authenticate.wait() AuthClient.authenticate.clear() return AuthClient.allow if is_server: listening_ip = args.bind_server_ip or '0.0.0.0' if '.' not in listening_ip: listening_ip = aioconnectors.iface_to_ip(listening_ip) server_sockaddr = (listening_ip, int(args.port or 0) or aioconnectors.core.Connector.SERVER_ADDR[1]) connector_files_dirpath = CONNECTOR_FILES_DIRPATH aioconnectors.ssl_helper.create_certificates(logger, certificates_directory_path=connector_files_dirpath) connector_manager = aioconnectors.ConnectorManager(is_server=True, server_sockaddr=server_sockaddr, use_ssl=True, ssl_allow_all=True, connector_files_dirpath=connector_files_dirpath, certificates_directory_path=connector_files_dirpath, send_message_types=['any'], recv_message_types=['any'], file_recv_config={'any': {'target_directory':cwd}}, hook_server_auth_client=None if accept_all_clients else \ AuthClient.authenticate_client) connector_api = aioconnectors.ConnectorAPI(is_server=True, server_sockaddr=server_sockaddr, connector_files_dirpath=connector_files_dirpath, send_message_types=['any'], recv_message_types=['any'], default_logger_log_level='INFO', default_logger_rotate=True) destination_id = chat_client_name else: server_sockaddr = (args.target, args.port or aioconnectors.core.Connector.SERVER_ADDR[1]) connector_files_dirpath = CONNECTOR_FILES_DIRPATH aioconnectors.ssl_helper.create_certificates(logger, certificates_directory_path=connector_files_dirpath) connector_manager = aioconnectors.ConnectorManager(is_server=False, server_sockaddr=server_sockaddr, use_ssl=True, ssl_allow_all=True, connector_files_dirpath=connector_files_dirpath, certificates_directory_path=connector_files_dirpath, send_message_types=['any'], recv_message_types=['any'], file_recv_config={'any': {'target_directory':cwd}}, client_name=chat_client_name, enable_client_try_reconnect=False) connector_api = aioconnectors.ConnectorAPI(is_server=False, server_sockaddr=server_sockaddr, connector_files_dirpath=connector_files_dirpath, client_name=chat_client_name, send_message_types=['any'], recv_message_types=['any'], default_logger_log_level='INFO', default_logger_rotate=True) destination_id = None task_manager = loop.create_task(connector_manager.start_connector()) #run_until_complete now, in order to exit in case of exception #for example because of already existing socket loop.run_until_complete(task_manager) task_recv = task_console = task_send_file = None async def message_received_cb(logger, transport_json , data, binary): #callback when a message is received from peer if transport_json.get('await_response'): #this response is necessary in args.upload mode, to know when to exit #it is in fact used also in chat mode by send_file, even if not mandatory loop.create_task(connector_api.send_message(data=data, data_is_json=False, message_type='any', response_id=transport_json['request_id'], destination_id=transport_json['source_id'])) if data: #display message received from peer print(data.decode()) print(custom_prompt,end='', flush=True) if not args.upload: task_recv = loop.create_task(connector_api.start_waiting_for_messages(message_type='any', message_received_cb=message_received_cb)) async def send_file(data, destination_id, with_file, delete_after_upload): #upload file to peer. uses await_response always, mandatory for upload mode await connector_api.send_message(data=data, data_is_json=False, destination_id=destination_id, await_response=True, request_id=random.randint(1,1000), message_type='any', with_file=with_file) if delete_after_upload: os.remove(delete_after_upload) class InputProtocolFactory(asyncio.Protocol): #hook user input : sends message to peer, and support special cases (!) def connection_made(self, *args, **kwargs): super().connection_made(*args, **kwargs) print(custom_prompt,end='', flush=True) def data_received(self, data): data = data.decode().strip() if AuthClient.perform_client_authentication: if data == 'y': AuthClient.update_allow(True) else:# data == 'n': AuthClient.update_allow(False) print(custom_prompt,end='', flush=True) return if data == '!exit': os.kill(os.getpid(), signal.SIGINT) return if data.startswith('!upload '): try: with_file = None delete_after_upload = False upload_path = data[len('!upload '):] if not os.path.exists(upload_path): raise Exception(upload_path + ' does not exist') if os.path.isdir(upload_path): upload_path_zip = f'{upload_path}.zip' if not os.path.exists(upload_path_zip): shutil.make_archive(upload_path, 'zip', upload_path) delete_after_upload = upload_path_zip upload_path = upload_path_zip #if zip already exists, don't override it, just send it (even if it may not be the correct zip) data = f'Receiving {upload_path}' with_file={'src_path':upload_path,'dst_type':'any', 'dst_name':os.path.basename(upload_path), 'delete':False} loop.create_task(send_file(data, destination_id, with_file, delete_after_upload)) except Exception as exc: res = str(exc) print(custom_prompt,end='', flush=True) print(res) print(custom_prompt,end='', flush=True) return if data.startswith('!dezip '): try: target = data.split('!dezip ')[1] #copy target to cwd #shutil.copy(os.path.join(CONNECTOR_FILES_DIRPATH, target), target) target_dir = target.split('.zip')[0] with zipfile.ZipFile(target) as zf: zf.extractall(path=target_dir) except Exception as exc: res = str(exc) print(custom_prompt,end='', flush=True) print(res) print(custom_prompt,end='', flush=True) return elif data.startswith('!'): data_shell = data[1:] if data_shell: try: res = subprocess.check_output(data_shell, stderr=subprocess.PIPE, shell=True) res = res.decode().strip() except subprocess.CalledProcessError as exc: res = str(exc) print(custom_prompt,end='', flush=True) print(res) print(custom_prompt,end='', flush=True) return loop.create_task(connector_api.send_message(data=data, data_is_json=False, destination_id=destination_id, message_type='any')) print(custom_prompt,end='', flush=True) async def connect_pipe_to_stdin(loop, connector_manager): #hook user input if not is_server: print('Connector waiting to connect ... (Ctrl+C to quit)') while True: await asyncio.sleep(1) if connector_manager.show_connected_peers(): print('Connected !') break transport, protocol = await loop.connect_read_pipe(InputProtocolFactory, sys.stdin) async def upload_file(args, destination_id): #called when client uses the upload mode, which uploads and disconnects, without opening a chat await asyncio.sleep(3) #wait for connection upload_path = args.upload delete_after_upload = False if os.path.isdir(upload_path): upload_path_zip = f'{upload_path}.zip' if not os.path.exists(upload_path_zip): shutil.make_archive(upload_path, 'zip', upload_path) delete_after_upload = upload_path_zip upload_path = upload_path_zip #if zip already exists, don't override it, just send it (even if it may not be the correct zip) with_file={'src_path':upload_path,'dst_type':'any', 'dst_name':os.path.basename(upload_path), 'delete':False} await send_file('', destination_id, with_file, delete_after_upload) if not args.upload: #chat mode, hook stdin task_console = loop.create_task(connect_pipe_to_stdin(loop, connector_manager)) else: #upload mode, upload and exit task_send_file = loop.create_task(upload_file(args, destination_id)) task_send_file.add_done_callback(lambda inp:os.kill(os.getpid(), signal.SIGINT)) try: loop.run_forever() except: print('Connector stopped !') task_stop = loop.create_task(connector_manager.stop_connector(delay=None, hard=False, shutdown=True)) loop.run_until_complete(task_stop) if task_console: del task_console if task_recv: connector_api.stop_waiting_for_messages(message_type='any') del task_recv del task_stop del task_manager del connector_manager if delete_connector_dirpath_later and os.path.exists(connector_files_dirpath): shutil.rmtree(connector_files_dirpath)
except: task_stop = loop.create_task( connector_manager.stop_connector(shutdown=True)) loop.run_until_complete(task_stop) del connector_manager print('Client stopped !') elif sys.argv[1] == 'send2client': print('Started send2client') own_source_id = local_name or CLIENT_NAMES[0] connector_api = aioconnectors.ConnectorAPI( default_logger_log_level=DEFAULT_LOGGER_LOG_LEVEL, server_sockaddr=SERVER_SOCKADDR, client_name=own_source_id, is_server=False, send_message_types=CLIENT_MESSAGE_TYPES, recv_message_types=SERVER_MESSAGE_TYPES, uds_path_send_preserve_socket=UDS_PATH_SEND_PRESERVE_SOCKET ) #, uds_path_receive_preserve_socket=UDS_PATH_RECEIVE_PRESERVE_SOCKET) loop = asyncio.get_event_loop() if TEST_COMMANDER_CLIENT: loop.create_task(connector_api.delete_client_certificate()) async def client_cb_type1(logger, transport_json, data, binary): peer_id = transport_json['source_id'] increment_result(own_source_id, peer_id, 'type1', 'recv') async def client_cb_type2(logger, transport_json, data, binary): peer_id = transport_json['source_id']