Ejemplo n.º 1
0
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 !')
Ejemplo n.º 2
0
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 !')
Ejemplo n.º 3
0
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 !')
Ejemplo n.º 4
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 !')
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
def cli(logger=None):
    def clearscreen():
        subprocess.call('clear', shell=True)        
    def display_dict(the_json, connector=None):
        if connector:
            print('\n', 'Connector : '+str(connector))
        #print('\n', json.dumps(the_json, indent=4, sort_keys=True),'')
        for the_key, value in sorted(the_json.items(), key=lambda x:int(x[0])):
            print(str(the_key)+')    '+str(value))
    
    if not logger:
        logger = aioconnectors.get_logger(logger_name='cli', first_run=True)    
    print('\nWelcome to aioconnectors CLI')
    Connector = aioconnectors.core.Connector    
    the_path = input('\nPlease type your connector_files_dirpath, or Enter if it is '
                     f'{Connector.CONNECTOR_FILES_DIRPATH}\n')
    if the_path:
        the_path = os.path.abspath(os.path.normpath(os.path.expandvars(os.path.expanduser(the_path))))
    else:
        the_path = Connector.CONNECTOR_FILES_DIRPATH
    
    while True:
        active_connectors_path = os.path.join(the_path, Connector.DEFAULT_ACTIVE_CONNECTORS_NAME)
        dict_connector_names = {}
        try:         
            if os.path.exists(active_connectors_path):
                with open(active_connectors_path, 'r') as fd:
                    set_active_connectors = json.load(fd)    
                dict_connector_names = {str(index):connector_name for index,connector_name in \
                                            enumerate(sorted(set_active_connectors))}
                display_dict(dict_connector_names)        
                print('\nPlease type the connector number you would like to run, or')
        except Exception as exc:
            print(exc)
        
        name_input = input(f'\nTo check your server, please type your server <ip> <port> '
                     f'(default port is {Connector.SERVER_ADDR[1]}).\nTo check your client, please type your '
                     'client name.\nType "q" to quit.\n')        
        if name_input == 'q':
            sys.exit(0)
        name = dict_connector_names.get(name_input, name_input)
        names = name.split(maxsplit=1) #assume that client name has no spaces
        server_sockaddr = client_name = None
        if len(names) == 2:
            server_sockaddr = (names[0], int(names[1]))
        else:
            client_name = name
        
        loop = asyncio.get_event_loop()
        is_server = (server_sockaddr is not None)
        connector_remote_tool = aioconnectors.ConnectorRemoteTool(use_default_logger=False, is_server=is_server, 
                                                server_sockaddr=server_sockaddr, client_name=client_name, 
                                                connector_files_dirpath=the_path)
        if not os.path.exists(connector_remote_tool.connector.uds_path_commander):
            clearscreen()
            print(f'The connector {name} does not exist')
            if name_input in dict_connector_names:
                #deleting invalid name_input from  dict_connector_names
                set_active_connectors.remove(name)
                with open(active_connectors_path, 'w') as fd:
                    json.dump(set_active_connectors, fd)
            continue
        clearscreen()
        list_cmds = ['start', 'stop gracefully', 'stop hard', 'restart', 'show_connected_peers', 
                     'ignore_peer_traffic', 'peek_queues', 'delete_client_certificate', 'disconnect_client',
                     'show_log_level', 'set_log_level', 'show_subscribe_message_types', 'set_subscribe_message_types']
        dict_cmds = {str(index):cmd for index,cmd in enumerate(list_cmds)}
        display_dict(dict_cmds, connector=server_sockaddr or client_name)        
        res = input('\nPlease type the command number you would like to run, or q to quit\n')
        def show_connected_peers():
            task = loop.create_task(connector_remote_tool.show_connected_peers())
            loop.run_until_complete(task)
            print(f'\nConnected peers : {task.result().decode()}')
            
        while True:
            clearscreen()
            if res == 'q':
                break
            if res not in dict_cmds:
                print('Invalid number : '+str(res))
            else:
                the_cmd = dict_cmds[res]
                if the_cmd == 'start':
                    task = loop.create_task(connector_remote_tool.start_connector())
                    loop.run_until_complete(task)
                    print(task.result().decode())                        
                elif the_cmd == 'stop gracefully':
                    task = loop.create_task(connector_remote_tool.stop_connector(client_wait_for_reconnect=False, hard=False))
                    loop.run_until_complete(task)
                    print(task.result().decode())
                elif the_cmd == 'stop hard':
                    task = loop.create_task(connector_remote_tool.stop_connector(client_wait_for_reconnect=False, hard=True))
                    loop.run_until_complete(task)
                    print(task.result().decode())                    
                elif the_cmd == 'restart':
                    task = loop.create_task(connector_remote_tool.restart_connector(sleep_between=2, hard=False))
                    loop.run_until_complete(task)
                    print(task.result().decode())
                elif the_cmd == 'show_connected_peers':
                    show_connected_peers()                     
                elif the_cmd == 'ignore_peer_traffic':
                    while True:
                        task = loop.create_task(connector_remote_tool.ignore_peer_traffic_show())
                        loop.run_until_complete(task)
                        status = task.result().decode()
                        print('\nignore_peer_traffic current status : ', status)
                        if status == 'False':
                            show_connected_peers()
                            res = input('\nType "y" to ignore peer traffic, or <peer name> to ignore a unique peer '
                                        'traffic, or Enter to quit\n')
                            if res == 'y':
                                task = loop.create_task(connector_remote_tool.ignore_peer_traffic_enable())
                                loop.run_until_complete(task)
                                continue
                            elif res == '':
                                break
                            else:
                                task = loop.create_task(connector_remote_tool.ignore_peer_traffic_enable_unique(res))
                                loop.run_until_complete(task)
                                continue                                    
                        else:
                            res = input('\nType "y" to stop ignoring peer traffic, or Enter to quit\n')
                            if res == 'y':
                                task = loop.create_task(connector_remote_tool.ignore_peer_traffic_disable())
                                loop.run_until_complete(task)
                                continue
                            else:
                                break                                
                elif the_cmd == 'peek_queues':
                    task = loop.create_task(connector_remote_tool.peek_queues())
                    loop.run_until_complete(task)
                    print(json.dumps(json.loads(task.result().decode()), indent=4, sort_keys=True))
                elif the_cmd == 'delete_client_certificate':
                    if is_server:
                        show_connected_peers()
                        client_name = input('\nPlease type the client name whose certificate you would '
                                            'like to delete, or q to quit\n')
                        res = input('\nAre you sure you want to delete '+client_name+' \'s certificate ? y/n\n')
                        if res =='y':
                            task = loop.create_task(connector_remote_tool.delete_client_certificate(client_id=client_name, 
                                                                                            remove_only_symlink=False))
                            loop.run_until_complete(task)
                            print(task.result().decode())                            
                            task = loop.create_task(connector_remote_tool.disconnect_client(client_id=client_name))
                            loop.run_until_complete(task)
                            print(task.result().decode())                            
                    else:
                        res = input('\nAre you sure you want to delete '+client_name+' \'s certificate ? y/n\n')
                        if res =='y':                            
                            task = loop.create_task(connector_remote_tool.delete_client_certificate())
                            loop.run_until_complete(task)
                            print(task.result().decode())
                elif the_cmd == 'disconnect_client':
                    if is_server:
                        show_connected_peers()
                        client_name = input('\nPlease type the client name you would '
                                            'like to disconnect, or q to quit\n')
                        res = input('\nAre you sure you want to disconnect '+client_name+' ? y/n\n')
                        if res =='y':
                            task = loop.create_task(connector_remote_tool.disconnect_client(client_id=client_name))
                            loop.run_until_complete(task)
                            print(task.result().decode())                          
                    else:
                        print('A client cannot use this functionality')                        
                elif the_cmd == 'show_log_level':
                    task = loop.create_task(connector_remote_tool.show_log_level())
                    loop.run_until_complete(task)
                    print(task.result().decode())                                   
                elif the_cmd == 'set_log_level':
                    list_levels = ['ERROR', 'WARNING', 'INFO', 'DEBUG']
                    dict_levels = {str(index):level for index,level in enumerate(list_levels)}
                    display_dict(dict_levels)        
                    res = input('\nPlease type the log level you would like to set, or q to quit\n')
                    clearscreen()                    
                    if res == 'q':
                        break
                    if res not in dict_levels:
                        print('Invalid number : '+str(res))
                        break
                    new_level = dict_levels[res]
                    task = loop.create_task(connector_remote_tool.set_log_level(new_level))
                    loop.run_until_complete(task)
                    print(task.result().decode())       
                elif the_cmd == 'show_subscribe_message_types':
                    if is_server:
                        print('Only available for clients')
                    else:
                        task = loop.create_task(connector_remote_tool.show_subscribe_message_types())
                        loop.run_until_complete(task)
                        print(task.result().decode())     
                elif the_cmd == 'set_subscribe_message_types':
                    if is_server:
                        print('Only available for clients')
                    else:                    
                        print('Current subscribed message types are :')
                        task = loop.create_task(connector_remote_tool.show_subscribe_message_types())
                        loop.run_until_complete(task)
                        print(task.result().decode())
                        res = input('\nPlease type the list of all message types you would like to subscribe, or q to quit\n')
                        clearscreen()                    
                        if res == 'q':
                            break
                        new_message_types = res.split()                        
                        res2 = input(f'\nAre you sure you want to subscribe to these message types : {new_message_types} ? y/n\n')
                        if res2.lower() != 'y':
                            break      
                        task = loop.create_task(connector_remote_tool.set_subscribe_message_types(*new_message_types))
                        loop.run_until_complete(task)
                        print(task.result().decode())   
                    
            display_dict(dict_cmds, connector=server_sockaddr or client_name)                    
            res = input('\nPlease type the command number you would like to run, or q to quit\n')