def _send_request(zmqclient: ZmqClient, xml_tree_full: Tree, message_id: str, timeout: float, statistic: Statistic) -> Tree: """Функция отправки сообщения и с возможностью переотправки. :param zmqclient: объект класса ZmqClient; :param xml_tree_full: запрос дерево XML; :param message_id: id сообщения; :param timeout: время ожидания ответа; :param statistic: объект класса Statistic. :return: ответ в виде дерева XML. """ zmqclient.send_request(xml_tree_full) statistic.append_info("Отправка запроса с id: " + str(message_id), "ИНФО") send_count = 0 while True: list_xml_responses = _get_response(zmqclient, timeout) if list_xml_responses == -1: if send_count == 3: statistic.append_error("Повторная отправка сообщения '" + str(message_id) + "' завершилась с ошибкой!", "ZMQ_ОТВЕТ", True) break zmqclient.send_request(xml_tree_full) send_count += 1 statistic.append_warn("Попытка повторной отправки сообщеия '" + str(message_id), "ZMQ_ОТВЕТ") continue response_index = search_response_index_by_message_id(list_xml_responses, message_id, statistic) if response_index > -1: statistic.append_info("Получен ответ на запрос с id '" + str(message_id) + "'", "ИНФО") zmqclient.remove_response(message_id) return list_xml_responses[response_index] return -1
def get_cams_names(db_path: str, server: str, statistic: Statistic) -> tuple: """Получение списка имен камер с указанного сервера. :param db_path: путь к бд; :param server: имя сервера; :param statistic: объект класса Statistic. :return: список имен камер с конкретного сервера. """ if not os.path.exists(db_path): statistic.append_error("Файла БД не существует!", "БД", True) full_names = [] try: time.sleep(0.2) conn = sqlite3.connect(db_path) cursor = conn.cursor() sql_cmd = "SELECT setname FROM setting WHERE settypeid = ? AND setname LIKE ?" cursor.execute(sql_cmd, [1, server + "%"]) full_names: list = cursor.fetchall() conn.commit() conn.close() except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True) if not full_names: statistic.append_warn("Сервер: " + server + "!", "НЕТ_КАМЕР") cams_names: list = [] for full_name in full_names: first_index_ = full_name[0].find("_") last_index_ = full_name[0].rfind("_") new_cam_name = full_name[0][first_index_ + 1:last_index_] # из-за разных профилей по одной камере могут быть одинаковые имена, # а дублирование имен не нужно. add = True for cam_name in cams_names: if new_cam_name == cam_name: add = False break if add: cams_names.append(new_cam_name) return tuple(cams_names)
def get_max_value_by_key(dicts: list, key: str, statistic: Statistic) -> int: """Поиск максимума в списке словарей по ключу. :param dicts: список словарей; :param key: имя ключа; :param statistic: объект класса Statistic. :return: максимальное найденное значение. """ max_val = 0 for dict_ in dicts: if key not in dict_: statistic.append_warn(key, "НЕТ КЛЮЧА") if dict_[key] > max_val: max_val = dict_[key] return max_val
def listener_pinger_keys_verifier(string: dict, statistic: Statistic) -> None: """Функция проверка правильность ответа ws метода listener_pinger. :param string: значение ключа string из ответа метода :param statistic: объект класса Statistic """ key_names: list = [ 'is_central_server', 'server_name', 'iv54server_port', 'rtmpPort', 'rtspPort', 'wsPort', 'direct_access', 'cams', 'down_servers' ] tools.check_keys_exist(string, key_names, 'string', True, statistic) key_values: list = [ string['is_central_server'], string['server_name'], string['iv54server_port'], string['rtmpPort'], string['rtspPort'], string['wsPort'], string['direct_access'], string['cams'], string['down_servers'] ] key_types: list = [bool, str, int, int, int, int, int, list, list] tools.check_types(key_names, key_values, key_types, statistic) if string["cams"]: for cam in string["cams"]: key_names = ['key2', 'key3', 'ptzStat', 'Status'] key_values = [ cam['key2'], cam['key3'], cam['ptzStat'], cam['Status'] ] key_types = [str, str, bool, bool] tools.check_keys_exist(cam, key_names, 'string["cams"]', True, statistic) tools.check_types(key_names, key_values, key_types, statistic) if string["archive"]: for cam in string["archive"][0]: key_names = [ 'key1', 'key2', 'key3', 'is_video', 'is_audio', 'is_video_linked', 'is_audio_linked' ] tools.check_keys_exist(cam, key_names, 'string["cams"]', True, statistic) key_values = [ cam['key1'], cam['key2'], cam['key3'], cam['is_video'], cam['is_audio'], cam['is_video_linked'], cam['is_audio_linked'] ] key_types = [str, str, str, bool, bool, bool, bool] tools.check_types(key_names, key_values, key_types, statistic) else: statistic.append_warn("Архив пустой!", "НЕВАЛИД_ЗНАЧ")
def faceva_get_data_base(client: SoapClient, token: str, statistic: Statistic) -> tuple: """Функция выполнеия ws метода FaceVA:GetDataBase :param client: объект класса SoapClient для отправки и приема ws запросов; :param token: токен соединения; :param statistic: объект класса Statistic для ведения статистики ошибок и предупреждений. :return: список персон, который приходит в ответе в ключе persons вида: [ { "id": 26617065162932227, "name": Иванов Иван Иванович, ["pacs": 1], ["category": "category"], ["department": "department"], ["comment": "comment"], ["information": "information"] } ] """ logger = statistic.get_log().get_logger("scripts/ws/analytics") logger.info("was called(client, login, password)") logger.debug("with params (client_obj, " + token + ", stat_obj)") params, sysparams, method = pattern.faceva_get_data_base(token) response_json = client.call_method2(method, params, sysparams, [0]) result = response_json["result"][0] tools.check_keys_exist(result, ['persons'], "result", True, statistic) persons = result["persons"] tools.check_types(["persons"], [persons], [list], statistic) if not persons: statistic.append_warn("data base persons", "EMPTY") for person in persons: tools.check_keys_exist(person, ["id", "name"], 'person', True, statistic) logger.info("ws method FaceVA:GetDataBase was executed successfully!") statistic.append_info(method + " выполнен успешно!", "WS МЕТОД") return tuple(persons)
def run_events_test(ws_client: SoapClient, token: str, cam_info: dict, events: tuple, inaccuracy: int, event_type: int, video_source: str, statistic: Statistic) -> None: """Функция запуска проверки наличия событий по детектору. Каждое событие появляется через определенное время от начала видео. Функция, учитывая погрешность, вычисляет интервал времени, в котором должно быть событие и уходит в sleep на это время. После пробуждения проверяет наличие события в этом интервале, используя ws метод ewriter:exec с командой select и нужными фильтрами. :param ws_client: объект класса SoapClient; :param token: токен авторизации; :param cam_info: информация по камере (сервер, имя, профиль); :param events: список событий из входных данных вида: [ { "time": 15, "info": {...} } ] см. подробное описание в тестах по аналитике, которые используют данную функцию; :param inaccuracy: погрешность для вычисления грациц интервала, в которых должно быть событие; :param event_type: номер события; :param video_source: путь к видеоисточнику (нужен для удобства вывода сообщений); :param statistic: объект класса Statistic. """ if _video_start_expecting(ws_client, token, cam_info, statistic) is False: statistic.append_error("Источник: " + video_source + "!", "НЕТ ВИДЕО") return # Заранее высчитываются временные интервалы, # в которых должны находиться события start_server_time: str = ws_common.get_current_server_time(ws_client, token, statistic) date_start_server_time = tools.get_date_from_str(start_server_time, statistic) for event in events: event_time = tools.increment_time(date_start_server_time, event['time']) left_interval_time_utc = tools.decrement_time(event_time, inaccuracy) right_interval_time_utc = tools.increment_time(event_time, inaccuracy) left_interval_time = str(tools.convert_time_from_gtc(left_interval_time_utc))[:-9] right_interval_time = str(tools.convert_time_from_gtc(right_interval_time_utc))[:-9] left_interval_time_utc = str(left_interval_time_utc) right_interval_time_utc = str(right_interval_time_utc) event.update({ "start": left_interval_time_utc, "end": right_interval_time_utc }) previous_sleep = 0 for index, event in enumerate(events): time.sleep(event['time'] - previous_sleep + inaccuracy) result = _check_event_existing(ws_client, token, event['start'], event['end'], event_type, cam_info, statistic) if result[0] == 0: statistic.append_success("#" + str(index + 1) + " по источнику " + video_source + " в интервале с " + left_interval_time + " по " + right_interval_time + "!", "ПОЛУЧЕНО СОБЫТИЕ") _check_event_comment(event['info'], result[1][0], statistic) elif result[0] == -1: statistic.append_error("Событие #" + str(index + 1) + " по источнику " + video_source + " в интервале с " + left_interval_time + " по " + right_interval_time + "!", "НЕТ СОБЫТИЯ") time.sleep(inaccuracy / 2) current_server_time: str = ws_common.get_current_server_time(ws_client, token, statistic) event.update({ "start": start_server_time, "end": current_server_time }) result = _check_event_existing(ws_client, token, event['start'], event['end'], event_type, cam_info, statistic) if result[0] == 0: statistic.append_warn("#" + str(index + 1) + " по источнику " + video_source + " в интервале с " + start_server_time + " по " + current_server_time + "!", "ПОЛУЧЕНО СОБЫТИЕ") _check_event_comment(event['info'], result[1][0], statistic) elif result[0] > 1: statistic.append_error("Событие #" + str(index + 1) + " по источнику " + video_source + " в интервале с " + start_server_time + " по " + current_server_time + "!", "МНОГО СОБЫТИй") else: statistic.append_error( "Событие #" + str(index + 1) + " по источнику " + video_source + " в интервале с " + start_server_time + " по " + current_server_time + "!", "НЕТ СОБЫТИЯ") else: statistic.append_error("Событие #" + str(index + 1) + " по источнику " + video_source + " в интервале с " + left_interval_time + " по " + right_interval_time + "!", "МНОГО СОБЫТИй") previous_sleep = event['time']
def compare_local_servers(string: dict, template_string: dict, local_server_ip: str, statistic: Statistic) -> bool: """Функция сравнивает значения всех ключей поля string из ws метода listener_pinger_get_local_servers с другим таким же словарем. Оба словаря должны быть равны значению ключа string из ws метода listener_pinger_get_local_servers или listener_pinger_get_down_servers :param string: строка ответа; :param template_string: эталонная строка; :param local_server_ip: ip локального сервера; :param statistic: объект класса Statistic. :return: флаг корректности. """ is_correct = True if string == template_string: return is_correct checked_keys: list = [] for template_key in template_string.keys(): if template_key not in string: statistic.append_error( template_key + " в 'string' у " + local_server_ip + "!", "НЕТ КЛЮЧА") continue checked_keys.append(template_key) if template_key == "cams": if template_string["cams"] == string["cams"]: continue if not template_string["cams"] and string["cams"]: statistic.append_warn( "Список камер у сервера " + local_server_ip + " не пустой!", "ЕСТЬ КАМЕРЫ") continue if not string["cams"] and template_string["cams"]: statistic.append_error("Сервер " + local_server_ip + "!", "НЕТ КАМЕР") is_correct = False continue # ищем камеру, которая отсутствует # либо ищем отличие в конкретных ключах у камеры # также ищем какие ключи отсутствуют в шаблоне, но есть по факту for template_cam in template_string["cams"]: # проверка на отсутствие камеры string_cam_index = tools.get_dict_by_keys_values( string["cams"], ["key2", "key3"], [template_cam["key2"], template_cam["key3"]]) if string_cam_index == -1: statistic.append_error( template_cam["key2"] + "(" + template_cam["key3"] + ") на сервере " + local_server_ip + "!", "НЕТ КАМЕРЫ") is_correct = False continue if template_cam == string["cams"][string_cam_index]: continue # поиск отличий в конкретных ключах у камеры for template_cam_key in template_cam: if template_cam_key not in string["cams"][ string_cam_index]: statistic.append_error( template_cam_key + " в " + template_cam + " на сервере " + local_server_ip + "'!", "НЕТ КЛЮЧА ПО КАМЕРЕ") is_correct = False continue current_key_value = string["cams"][string_cam_index][ template_cam_key] if template_cam[ template_cam_key] != current_key_value and template_cam_key != "Status": statistic.append_error( template_cam_key + " в камере " + template_cam["key2"] + "(" + template_cam["key3"] + ") на сервере " + local_server_ip + "!" + " Требуется: " + str(template_cam[template_cam_key]) + "(" + str(current_key_value) + ")!", "НЕВАЛИД ЗНАЧ") is_correct = False continue # поиск отсутствующих ключей в шаблоне for string_cam_key in string["cams"][string_cam_index]: if string_cam_key not in template_cam: statistic.append_warn( string_cam_key + " в камере " + template_cam + " на сервере" + local_server_ip + " в ШАБЛОНЕ!", "НЕТ КЛЮЧА") # ищем камеры, которых нет в шаблоне # но есть по факту for string_cam in string["cams"]: string_cam_is_in_template = False for template_cam in template_string["cams"]: if string_cam["key2"] == template_cam["key2"]: string_cam_is_in_template = True break if string_cam_is_in_template is False: statistic.append_warn( string_cam["key2"] + " на сервере " + local_server_ip + " в ШАБЛОНЕ!", "НЕТ КАМЕРЫ") elif template_key == "archive": if template_string[template_key] == string[template_key]: continue if not template_string[template_key] and string[template_key]: statistic.append_warn("Сервер " + local_server_ip, "ЕСТЬ АРХИВ") #is_correct = False continue if not string[template_key] and template_string[template_key]: statistic.append_error("Сервер " + local_server_ip, "НЕТ АРХИВА") is_correct = False for archive in template_string[template_key][0]: if string[template_key][0].count(archive) > 0: continue else: statistic.append_error( str(archive) + " на сервере " + local_server_ip, "НЕТ АРХИВА") is_correct = False for archive in string[template_key][0]: if template_string[template_key][0].count(archive) > 0: continue else: statistic.append_warn( str(archive) + " на сервере " + local_server_ip, "НЕТ АРХИВА") is_correct = False else: if string[template_key] != template_string[ template_key] and template_key != "down_servers": statistic.append_error( str(string[template_key]) + " по ключу" + template_key + " на сервере " + local_server_ip + "! Требуется: " + str(template_string[template_key]) + "(" + str(string[template_key]) + ")!", "НЕВАЛИД ЗНАЧ") is_correct = False return is_correct
def compare_down_servers(string: dict, template_string: dict, main_server_ip: str, statistic: Statistic) -> bool: """Функция проверки эквивалентности "нижних" серверов :param string: строка ответа; :param template_string: эталонная строка; :param main_server_ip: ip главного сервера; :param statistic: объект класса Statistic. :return: флаг корректности. """ is_correct = True if string == template_string: return is_correct if compare_local_servers(string, template_string, main_server_ip, statistic) is False: statistic.append_info( "Локальный сервер некорректен в ответе 'get_down' на сервере " + main_server_ip, "СРАВНЕНИЕ") is_correct = False if string["down_servers"] == template_string["down_servers"]: return is_correct if not string["down_servers"] and template_string["down_servers"]: statistic.append_error("Сервер " + main_server_ip + "!", "НЕТ НИЖНИХ СЕРВЕРОВ") is_correct = False if not template_string["down_servers"] and string["down_servers"]: statistic.append_warn("Сервер " + main_server_ip + "!", "ЕСТЬ НИЖНИЕ СЕРВЕРА") #is_correct = False # проход по шаблону и поиск отличий down_servers_names: list = get_down_servers_names(string["down_servers"]) for template_down_server in template_string["down_servers"]: template_down_server_name: str = list(template_down_server.keys())[0] statistic.append_info( "Сравнение нижнего сервера " + template_down_server_name + " с шаблоном...", "ИНФО") if template_down_server_name not in down_servers_names: statistic.append_error( template_down_server_name + " на сервере" + main_server_ip + "!", "НЕТ НИЖНЕГО СЕРВЕРА") is_correct = False continue down_server_index = down_servers_names.index(template_down_server_name) down_server_string = string["down_servers"][down_server_index][ template_down_server_name] down_server_template_string = template_down_server[ template_down_server_name] if compare_local_servers( down_server_string, down_server_template_string, template_down_server_name, statistic) is False: statistic.append_error( "Нижний сервер " + template_down_server_name + " не корректен!", "СРАВНЕНИЕ") is_correct = False continue # поиск отсутвующих нижних серверов в шаблоне # тобиш, которые есть по факту, но нет в шаблоне template_down_servers_names: list = get_down_servers_names( template_string["down_servers"]) for down_server_name in down_servers_names: if template_down_servers_names.count(down_server_name) == 0: statistic.append_warn( down_server_name + " на сервере " + main_server_ip + " в ШАБЛОНЕ!", "НЕТ НИЖНЕГО СЕРВЕРА") return is_correct