Example #1
0
def create_connector(config_file_path, logger=None):
    if not logger:
        logger = aioconnectors.get_logger(logger_name='create_connector', first_run=True)    
    logger.info('Creating connector with config file '+config_file_path)
    connector_manager = aioconnectors.ConnectorManager(config_file_path=config_file_path)
    loop = asyncio.get_event_loop()
    #task = loop.create_task(connector_manager.delete_previous_persistence_remains())
    #loop.run_until_complete(task)
    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)
    
    try:
        loop.run_forever()
    except:    
        task_stop = loop.create_task(connector_manager.stop_connector(delay=None, hard=False, shutdown=True))            
        loop.run_until_complete(task_stop)
        del task_stop
        del task_manager
        del connector_manager
        print('Connector stopped !')
Example #2
0
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)
Example #3
0
        if len(sys.argv) > 2:
            local_name = sys.argv[2]  #currently only for client

        if sys.argv[1] == 'server':
            print('Started server')

            connector_manager = aioconnectors.ConnectorManager(
                config_file_path=None,
                default_logger_log_level=DEFAULT_LOGGER_LOG_LEVEL,
                is_server=True,
                server_sockaddr=SERVER_SOCKADDR,
                use_ssl=TEST_WITH_SSL,
                certificates_directory_path=CERTIFICATES_DIRECTORY_PATH,
                disk_persistence_send=PERSISTENCE_SERVER,
                disk_persistence_recv=PERSISTENCE_SERVER,
                debug_msg_counts=TEST_DEBUG_MSG_COUNTS,
                silent=SILENT,  #use_ack=TEST_WITH_ACK,
                send_message_types=SERVER_MESSAGE_TYPES,
                recv_message_types=CLIENT_MESSAGE_TYPES,
                file_recv_config=FILE_RECV_CONFIG,
                reuse_server_sockaddr=True,
                uds_path_receive_preserve_socket=
                UDS_PATH_RECEIVE_PRESERVE_SOCKET,
                uds_path_send_preserve_socket=UDS_PATH_SEND_PRESERVE_SOCKET,
                ssl_allow_all=TEST_WITH_SSL_ALLOW_ALL)
            loop = asyncio.get_event_loop()

            if PERSISTENCE_CLIENT_DELETE_PREVIOUS_PERSISTENCE_FILE:
                connector_manager.delete_previous_persistence_remains()

            loop.create_task(connector_manager.start_connector())