def __init__(self, parent=None):
     QWidget.__init__(self, parent)
     # uic.loadUi(os.path.join(UI_DIR, 'server.ui'), self)
     self.ui = ServerMainWindow()
     self.ui.setupUi(self)
     logging.getLogger(log_config.LOGGER_NAME)\
         .addHandler(UiLogHandler(self.ui.logPtx))
     self.storage = ServerStorage()
     self.__init_ui()
 def __init__(self, bind_addr, port):
     self.logger = logging.getLogger(log_config.LOGGER_NAME)
     self.bind_addr = bind_addr
     self.port = port
     self.clients = []
     self.client_keys = {}
     self.users = {}
     self.storage = ServerStorage()
     self.__init_commands()
     self.__init_req_handlers()
def import_from_sqlite(sqlite_file=None, mongo_host=None):
    print(f'{sqlite_file if sqlite_file else "SQLite Default"} -> {mongo_host if mongo_host else "Mongo Default"}')

    sqlite = ServerStorage(sqlite_file)
    mongo = ServerStorageMongo(mongo_host)

    s_users = sqlite.get_users()
    s_history = sqlite.get_history()
    s_avatars = sqlite.get_users_avatar()

    print('Move users')
    load_users_to_mongo(s_users, s_history, s_avatars)
    print('-' * 50)
    print('Move contacts')
    load_contacts_to_mongo(sqlite, s_users)
    print('-' * 50)

    s_messages = sqlite.get_user_messages()
    print('Move user messages')
    load_messages_to_mongo(s_messages)
    print('-' * 50)
    s_rooms = sqlite.get_rooms()
    print('Move room messages')
    load_room_messages(sqlite, s_rooms)
    print('-' * 50)
def main():

    config = load_config()

    port = config['port'] if config and 'port' in config else 7777
    bind = config['bind'] if config and 'bind' in config else ''
    db_file = config['database'] \
        if config and 'database' in config \
        else 'server_db.db'

    if not config or config['is_sqlite_db']:
        storage = ServerStorage(db_file)
    elif config['is_mongo_db']:
        storage = ServerStorageMongo()
    else:
        storage = ServerStorage()

    parser = argparse.ArgumentParser()
    parser.add_argument('-p',
                        '--port',
                        default=port,
                        type=int,
                        nargs='?',
                        help='Port [default=7777]')
    parser.add_argument('-a',
                        '--addr',
                        default=bind,
                        type=str,
                        nargs='?',
                        help='Bind address')

    args = parser.parse_args()
    addr = args.addr
    port = args.port

    server = Server(addr, port)
    server.set_db_storage(storage)
    server.start()

    application = QApplication(sys.argv)
    main_window = MainWindow(storage=storage)
    main_window.show()
    application.exec_()
def main():
    # Загрузка параметров командной строки, если нет параметров, то задаём значения по умоланию.
    listen_address, listen_port = arg_parser()

    # Инициализация базы данных
    database = ServerStorage()

    # Создание экземпляра класса - сервера и его запуск:
    server = Server(listen_address, listen_port, database)
    server.daemon = True
    server.start()

    # Печатаем справку:
    print_help()

    # Основной цикл сервера:
    while True:
        command = input('Введите комманду: ')
        if command == 'help':
            print_help()
        elif command == 'exit':
            break
        elif command == 'users':
            for user in sorted(database.users_list()):
                print(f'Пользователь {user[0]}, последний вход: {user[1]}')
        elif command == 'connected':
            for user in sorted(database.online_users_list()):
                print(
                    f'Пользователь {user[0]}, подключен: {user[1]}:{user[2]}, время установки соединения: {user[3]}'
                )
        elif command == 'loghist':
            name = input(
                'Введите имя пользователя для просмотра истории. Для вывода всей истории, просто нажмите Enter: '
            )
            for user in sorted(database.login_history(name)):
                print(
                    f'Пользователь: {user[0]} время входа: {user[1]}. Вход с: {user[2]}:{user[3]}'
                )
        else:
            print('Команда не распознана.')
def main():
    # Загрузка файла конфигурации сервера
    config = configparser.ConfigParser()

    dir_path = os.path.dirname(os.path.realpath(__file__))
    config.read(f"{dir_path}/{'server.ini'}")

    # Загрузка параметров командной строки, если нет параметров, то задаём значения по умоланию.
    listen_address, listen_port = arg_parser(config['SETTINGS']['Default_port'], config['SETTINGS']['Listen_Address'])

    # Инициализация базы данных
    database = ServerStorage(os.path.join(config['SETTINGS']['Database_path'], config['SETTINGS']['Database_file']))

    # Создание экземпляра класса - сервера и его запуск:
    server = Server(listen_address, listen_port, database)
    server.daemon = True
    server.start()

    # Создаём графическое окуружение для сервера:
    server_app = QApplication(sys.argv)
    main_window = MainWindow()

    # Инициализируем параметры в окна
    main_window.statusBar().showMessage('Server Working')
    main_window.active_clients_table.setModel(gui_create_model(database))
    main_window.active_clients_table.resizeColumnsToContents()
    main_window.active_clients_table.resizeRowsToContents()

    # Функция обновляющяя список подключённых, проверяет флаг подключения, и если надо обновляет список
    def list_update():
        global new_connection
        if new_connection:
            main_window.active_clients_table.setModel(gui_create_model(database))
            main_window.active_clients_table.resizeColumnsToContents()
            main_window.active_clients_table.resizeRowsToContents()
            with conflag_lock:
                new_connection = False

    # Функция создающяя окно со статистикой клиентов
    def show_statistics():
        global stat_window
        stat_window = HistoryWindow()
        stat_window.history_table.setModel(create_stat_model(database))
        stat_window.history_table.resizeColumnsToContents()
        stat_window.history_table.resizeRowsToContents()
        stat_window.show()

    # Функция создающяя окно с настройками сервера.
    def server_config():
        global config_window
        # Создаём окно и заносим в него текущие параметры
        config_window = ConfigWindow()
        config_window.db_path.insert(config['SETTINGS']['Database_path'])
        config_window.db_file.insert(config['SETTINGS']['Database_file'])
        config_window.port.insert(config['SETTINGS']['Default_port'])
        config_window.ip.insert(config['SETTINGS']['Listen_Address'])
        config_window.save_btn.clicked.connect(save_server_config)

    # Функция сохранения настроек
    def save_server_config():
        global config_window
        message = QMessageBox()
        config['SETTINGS']['Database_path'] = config_window.db_path.text()
        config['SETTINGS']['Database_file'] = config_window.db_file.text()
        try:
            port = int(config_window.port.text())
        except ValueError:
            message.warning(config_window, 'Ошибка', 'Порт должен быть числом')
        else:
            config['SETTINGS']['Listen_Address'] = config_window.ip.text()
            if 1023 < port < 65536:
                config['SETTINGS']['Default_port'] = str(port)
                print(port)
                with open('server.ini', 'w') as conf:
                    config.write(conf)
                    message.information(config_window , 'OK' , 'Настройки успешно сохранены!')
            else:
                message.warning(config_window , 'Ошибка' , 'Порт должен быть от 1024 до 65536')

    # Таймер, обновляющий список клиентов 1 раз в секунду
    timer = QTimer()
    timer.timeout.connect(list_update)
    timer.start(1000)

    # Связываем кнопки с процедурами
    main_window.refresh_button.triggered.connect(list_update)
    main_window.show_history_button.triggered.connect(show_statistics)
    main_window.config_btn.triggered.connect(server_config)

    # Запускаем GUI
    server_app.exec_()
Beispiel #7
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        uic.loadUi(os.path.join(UI_DIR, 'server.ui'), self)
        logging.getLogger(log_config.LOGGER_NAME).addHandler(UiLogHandler(self.logPtx))
        self.storage = ServerStorage()
        self.__init_ui()

    def __init_ui(self):

        def switch_refresh():
            if self.action_refresh.isChecked():
                self.timer_refresh.start()
            else:
                self.timer_refresh.stop()

        def open_config_func():
            win = ConfigWindow(self)
            win.exec_()

        self.open_config.triggered.connect(lambda: open_config_func())
        self.action_refresh.triggered.connect(lambda: switch_refresh())
        self.refresh()

        self.timer_refresh = QTimer()
        self.timer_refresh.setInterval(10000)
        self.timer_refresh.timeout.connect(self.refresh)

        self.action_refresh.trigger()

    def refresh(self):
        self.load_users()
        self.load_users_online()
        self.load_users_stats()
        self.load_history()
        self.load_messages()

    def load_users(self):
        users = self.storage.get_users()  # temp
        tbl = self.users_tbl
        fill_table(tbl, users, ['id', 'name', 'password'], ['id', 'name', 'password'])

    def load_users_online(self):
        online = self.storage.get_users_online()
        tbl = self.users_online_tbl
        fill_table(tbl, online, ['name'], ['name'])

    def load_users_stats(self):
        stats = self.storage.get_user_stats()
        tbl = self.user_stats_tbl
        fill_table(tbl, stats, ['name', 'sent', 'recv'], ['User.name', 'UserStat.mes_sent', 'UserStat.mes_recv'])

    def load_history(self):
        history = self.storage.get_history()
        tbl = self.history_tbl
        fill_table(tbl, history, ['id', 'name', 'date', 'ip'],
                   ['LoginHistory.id', 'User.name', 'LoginHistory.datetime', 'LoginHistory.ip'])

    def load_messages(self):
        messages = self.storage.get_user_messages()
        tbl = self.messages_tbl
        fill_table(tbl, messages, ['id', 'sender', 'recipient', 'text', 'time'],
                   ['UserMessage.id', '[0].name', '[2].name', 'UserMessage.text', 'UserMessage.time'])
class Server:
    """ Class implement receive, handle, response to client request """

    __slots__ = ('bind_addr', '_port', 'logger', 'socket', 'clients', 'users',
                 'client_keys', 'listener', 'storage', 'commands',
                 'request_handlers')

    TCP = (AF_INET, SOCK_STREAM)
    TIMEOUT = 5

    port = Port('_port')

    def __init__(self, bind_addr, port):
        self.logger = logging.getLogger(log_config.LOGGER_NAME)
        self.bind_addr = bind_addr
        self.port = port
        self.clients = []
        self.client_keys = {}
        self.users = {}
        self.storage = ServerStorage()
        self.__init_commands()
        self.__init_req_handlers()

    def __init_commands(self):
        """ Method fills dictionary commands """

        self.commands = {
            'get_users': self.storage.get_users_online,
            'add_contact': self.storage.add_contact,
            'rem_contact': self.storage.remove_contact,
            'get_contacts': self.storage.get_contacts,
            'get_chat': self.storage.get_chat_str
        }

    def __init_req_handlers(self):
        """ Method fills dictionary request handlers """

        self.request_handlers = {
            RequestAction.PRESENCE: self.__req_presence_handler,
            RequestAction.AUTH: self.__req_auth_handler,
            RequestAction.QUIT: lambda r, c, *a: self.__client_disconnect(c),
            RequestAction.START_CHAT: self.__req_start_chat_handler,
            RequestAction.ACCEPT_CHAT: self.__req_accept_chat_handler,
            RequestAction.MESSAGE: self.__req_message_handler,
            RequestAction.COMMAND: self.__req_command_handler,
        }

    def start(self, request_count=5):
        """ Method the start configuration server """

        self.socket = socket(*self.TCP)
        self.socket.settimeout(0.5)
        self.socket.bind((self.bind_addr, self.port))
        start_msg = f'Config server port - {self.port}| ' \
                    f'Bind address - {self.bind_addr}'
        self.logger.info(start_msg)

        self.socket.listen(request_count)
        self.listener = ServerThread(self.__listen, self.logger)
        self.listener.start()

    def __listen(self):
        """ Method the listener client connections """

        self.logger.info('Start listen')
        while True:
            try:
                client, addr = self.socket.accept()
            except OSError:
                pass
            except Exception as ex:
                self.logger.error(ex)
            else:
                self.logger.info(f'Connection from {addr}')
                self.clients.append(client)

            i_clients, o_clients = [], []
            try:
                i_clients, o_clients, ex = select(self.clients, self.clients,
                                                  [], self.TIMEOUT)
            except OSError:
                pass
            except Exception as exc:
                self.logger.error(exc)

            requests = self.__get_requests(i_clients)
            if requests:
                self.__send_responses(requests, o_clients)

    @try_except_wrapper
    def __get_requests(self, i_clients):
        """ Method the handler of client requests """

        requests = {}
        for client in i_clients:
            try:
                request = get_data(client)
                requests[client] = request

                if request.action == RequestAction.PRESENCE:
                    if request.body in self.users:
                        requests.pop(client)
                        send_data(client, Response(CONFLICT))
                        self.clients.remove(client)
                    else:
                        self.users[request.body] = client
                elif request.action == RequestAction.QUIT:
                    self.__client_disconnect(client)
            except (ConnectionError, ValueError):
                self.__client_disconnect(client)
            except Exception as e:
                raise e
        return requests

    @try_except_wrapper
    def __send_responses(self, requests, o_clients):
        """ Method the sender of responses to clients """

        for client, i_req in requests.items():
            other_clients = [c for c in o_clients if c != client]
            self.logger.info(client)
            self.logger.info(i_req)
            action = i_req.action
            if action in self.request_handlers:
                self.request_handlers[action](i_req, client, other_clients)
            else:
                self.__send_to_client(client, Response(INCORRECT_REQUEST))
                self.logger.error(f'Incorrect request:\n {i_req}')

    @try_except_wrapper
    def __send_to_client(self, client, resp):
        try:
            self.logger.debug(resp)
            send_data(client, resp)
        except ConnectionError:
            self.__client_disconnect(client)
        except Exception as e:
            raise e

    def __send_to_all(self, clients, resp):
        for cl in clients:
            self.__send_to_client(cl, resp)

    @try_except_wrapper
    def __client_disconnect(self, client):
        self.clients.remove(client)
        user = [u for u, c in self.users.items() if c == client].pop()
        self.users.pop(user)
        self.storage.logout_user(user)
        disconnection_response = Response(DISCONNECTED, user)
        self.logger.debug(disconnection_response)
        for cl in self.clients:
            send_data(cl, disconnection_response)

    def __execute_command(self, command, *args):
        if command in self.commands:
            answer = self.commands[command](*args)
            if answer is False:
                return Response(SERVER_ERROR, 'Command error')
            elif isinstance(answer, list):
                answer = [str(a) for a in answer]
                return Response(ANSWER, answer)
            elif answer is None:
                return Response(ANSWER, 'Done')
            return Response(ANSWER, answer)
        else:
            return Response(INCORRECT_REQUEST, 'Command not found')

    # region Request handlers

    @try_except_wrapper
    def __req_presence_handler(self, i_req, client, *args):
        """ Mathod the handler presence request """

        prv, pub = gen_keys()
        self.client_keys[i_req.body] = (client, prv)
        self.__send_to_client(client, Response(AUTH,
                                               pub.export_key().decode()))

    @try_except_wrapper
    def __req_auth_handler(self, i_req, client, *args):
        """ Mathod the handler authorization request """

        other_clients = args[0]
        user = [u for u, c in self.users.items() if c == client]
        if len(user) == 0:
            self.logger.warning(f'AUTH: user not found')
            return
        user = user[0]
        cl, key = self.client_keys[user]
        if cl != client:
            self.logger.warning('AUTH: connection sockets not equals')
            return
        password = decrypt_password(key, i_req.body)
        if password is None:
            self.logger.warning('AUTH: decrypt error')
            return
        password_hash = get_hash_password(password, user.encode())
        if not self.storage.authorization_user(user, password_hash):
            self.__send_to_client(client, Response(UNAUTHORIZED))
            self.clients.remove(client)
            self.users.pop(user)
            return
        self.storage.login_user(user, client.getpeername()[0])
        self.__send_to_client(client, Response(OK))
        self.__send_to_all(other_clients, Response(CONNECTED, user))

    @try_except_wrapper
    def __req_start_chat_handler(self, i_req, client, *args):
        """ Mathod the handler start chat request """

        msg = Msg.from_dict(i_req.body)
        if msg.to not in self.users:
            self.logger.warning(f'{msg.to} not found')
            return
        self.__send_to_client(self.users[msg.to],
                              Response(START_CHAT, str(msg)))

    @try_except_wrapper
    def __req_accept_chat_handler(self, i_req, client, *args):
        """ Mathod the handler accept chat request """

        msg = Msg.from_dict(i_req.body)
        if msg.to not in self.users:
            self.logger.warning(f'{msg.to} not found')
            return
        self.__send_to_client(self.users[msg.to],
                              Response(ACCEPT_CHAT, str(msg)))

    @try_except_wrapper
    def __req_message_handler(self, i_req, client, *args):
        """ Mathod the handler message request """

        other_clients = args[0]
        msg = Msg.from_dict(i_req.body)
        self.storage.user_stat_update(msg.sender, ch_sent=1)
        if msg.to.upper() != 'ALL' and msg.to in self.users:
            self.storage.user_stat_update(msg.to, ch_recv=1)
            self.storage.add_message(msg.sender, msg.to, msg.text)
            self.__send_to_client(self.users[msg.to],
                                  Response(LETTER, str(msg)))
        else:
            self.__send_to_all(other_clients, Response(LETTER, str(msg)))
            for u in self.storage.get_users_online():
                if str(u) == msg.sender:
                    continue
                self.storage.user_stat_update(str(u), ch_recv=1)
                self.storage.add_message(msg.sender, str(u), msg.text)

    @try_except_wrapper
    def __req_command_handler(self, i_req, client, *args):
        """ Mathod the handler command request """

        command, *args = i_req.body.split()
        user = [u for u, c in self.users.items() if c == client].pop()
        if len(args) < 1 or args[0] != user:
            args.insert(0, user)
        o_resp = self.__execute_command(command, *args)
        self.__send_to_client(client, o_resp)
class MainWindow(QMainWindow):
    """ Class the implementation of main window logic """
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        # uic.loadUi(os.path.join(UI_DIR, 'server.ui'), self)
        self.ui = ServerMainWindow()
        self.ui.setupUi(self)
        logging.getLogger(log_config.LOGGER_NAME)\
            .addHandler(UiLogHandler(self.ui.logPtx))
        self.storage = ServerStorage()
        self.__init_ui()

    def __init_ui(self):
        """ Method the initialization ui and link ui widgets to logic """
        def switch_refresh():
            """ Function the handler of refresh action """

            if self.ui.action_refresh.isChecked():
                self.timer_refresh.start()
            else:
                self.timer_refresh.stop()

        def open_config_func():
            """ Function of opens config dialog """

            win = ConfigWindow(self)
            win.exec_()

        self.ui.open_config.triggered.connect(lambda: open_config_func())
        self.ui.action_refresh.triggered.connect(lambda: switch_refresh())
        self.refresh()

        self.timer_refresh = QTimer()
        self.timer_refresh.setInterval(10000)
        self.timer_refresh.timeout.connect(self.refresh)

        self.ui.action_refresh.trigger()

    def refresh(self):
        """ Method the reload all tables """

        self.load_users()
        self.load_users_online()
        self.load_users_stats()
        self.load_history()
        self.load_messages()

    def load_users(self):
        """ Method the load users table"""

        users = self.storage.get_users()  # temp
        tbl = self.ui.users_tbl
        fill_table(tbl, users, ['id', 'name', 'password'],
                   ['id', 'name', 'password'])

    def load_users_online(self):
        """ Method the load online users table"""

        online = self.storage.get_users_online()
        tbl = self.ui.users_online_tbl
        fill_table(tbl, online, ['name'], ['name'])

    def load_users_stats(self):
        """ Method the load users stats table"""

        stats = self.storage.get_user_stats()
        tbl = self.ui.user_stats_tbl
        fill_table(tbl, stats, ['name', 'sent', 'recv'],
                   ['User.name', 'UserStat.mes_sent', 'UserStat.mes_recv'])

    def load_history(self):
        """ Method the load history table"""

        history = self.storage.get_history()
        tbl = self.ui.history_tbl
        fill_table(tbl, history, ['id', 'name', 'date', 'ip'], [
            'LoginHistory.id', 'User.name', 'LoginHistory.datetime',
            'LoginHistory.ip'
        ])

    def load_messages(self):
        """ Method the load users messages table"""

        messages = self.storage.get_user_messages()
        tbl = self.ui.messages_tbl
        fill_table(tbl, messages,
                   ['id', 'sender', 'recipient', 'text', 'time'], [
                       'UserMessage.id', '[0].name', '[2].name',
                       'UserMessage.text', 'UserMessage.time'
                   ])
 def set_db_storage(self, storage=None):
     if storage:
         self.storage = storage
     else:
         self.storage = ServerStorage()
     self.__init_commands()