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_setid(path_to_db: str, key1: str, key2: str, key3: str, statistic: Statistic) -> int: """Получить первичный ключ камеры (поле setid) по ее полному имени. :param path_to_db: путь до БД :param key1: имя сервера :param key2: имя камеры :param key3: профиль :param statistic: объект класса Statistic :return: первичный ключ камеры """ if not os.path.exists(path_to_db): statistic.append_error("Файла БД не существует!", "БД", True) try: time.sleep(0.2) conn = sqlite3.connect(path_to_db) cursor = conn.cursor() db_setname = key1 + "_" + key2 + "_" + key3 sql_cmd = "SELECT setid FROM setting WHERE settypeid = ? AND setname = ?" cursor.execute(sql_cmd, [1, db_setname]) db_setid = cursor.fetchall()[0][0] conn.close() return db_setid except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True)
def check_ptz_cams(string_cams: list, ptz_cams: list, statistic: Statistic) -> bool: """Функиия проверки статусов ptz у камер. :param string_cams: список камер из ответа; :param ptz_cams: список реальных ptz камер; :param statistic: объект класса Statistic. :return: флаг корректности. """ is_correct = True for ptz_cam in ptz_cams: cam_index_exist = tools.get_dict_by_keys_values( string_cams, ["key2"], [ptz_cam["key2"]]) if cam_index_exist == -1: statistic.append_error("'" + ptz_cam["key2"] + "'!", "НЕТ КАМЕРЫ") is_correct = False continue cam_index_ptz = tools.get_dict_by_keys_values(string_cams, ["key2", "ptzStat"], [ptz_cam["key2"], True]) if cam_index_ptz == -1: statistic.append_error( ptz_cam["key2"] + " в ответе ws listener_pinger!", "НЕ PTZ") is_correct = False return is_correct
def init_data(common_input_data: dict, test_name: str, statistic: Statistic) -> dict: """Получение данных для нужного теста из общего json с входными данными для всех тестов. :param common_input_data: словарь со всеми тестами и их входными данными; :param test_name: имя теста, для которого нужно извлечь его входные данные; :param statistic: обхект класса Statistic. :return: словарь с входными данными для указанного теста. """ logger = log.get_logger("scripts/common/initializer") logger.info("was called (common_input_data, test_name)") logger.debug("params (" + str(common_input_data) + ", " + test_name + ")") test_data = {} for test in common_input_data['tests']: tools.check_keys_exist(test, ['name'], 'test', True, statistic) if test['name'] != test_name: continue tools.check_keys_exist(test, ['input_data'], 'test', True, statistic) test_data = test['input_data'] logger.info("put data into 'test_data'") logger.debug("test_data: " + str(test_data)) break if not test_data: statistic.append_error("Отсутствуют для теста " + test_name, "ВХОДНЫЕ_ДАННЫЕ", True) return test_data
def get_points_from_region(json_detector: dict, region_name: str, statistic: Statistic) -> dict: """Получение словаря со списком _points из указанной зоны детектора. :param json_detector: json с секцией детектора; :param region_name: имя зоны; :param statistic: объект класса Statistic. :return: словарь со списком _points. """ logger = statistic.get_log().get_logger("scripts/common/graph") logger.info("was called (json_detector: dict, region_name: str, statistic: Statistic") logger.debug("get_points_from_region(" + str(json_detector) + ", " + region_name + ")") data = get_region_from_detector_json(json_detector, region_name, statistic) index_region = data[0] region = data[1] if index_region == -1: statistic.append_error("в " + region_name, "НЕТ_ЗОНЫ", False) return {} for first_lvl_key in region: if first_lvl_key == '_points': return { first_lvl_key: region[first_lvl_key] } return {}
def open_json_file(path: str, statistic: Statistic) -> dict: """Открытие файла с содержимым в формате json. Функция считывает json из файла и преобразует в словарь. Если файл не существует - генерируется критическая ошибка. :param path: путь к файлу; :param statistic: объект класса Statistic. :return: сожержимое json файла в виде словаря. """ logger = statistic.get_log().get_logger("scripts/common/tools") logger.info("was called (path: str, statistic: Statistic)") logger.debug("with params (" + path + ", statistic_obj)") if not os.path.exists(path): statistic.append_error(path, "НЕ СУЩЕСТВУЕТ", True) with open(path, encoding='utf-8') as json_file: try: logger.info("open json file '" + path + "' was executed successfully") result = json.load(json_file) statistic.append_info( "Открытие файла '" + path + "' выполнено успешно...", "JSON_ФАЙЛ") return result except json.JSONDecodeError: logger.error("В файле '" + path + "' отсутствует корректная строка JSON!") statistic.append_error( "В файле '" + path + "' отсутствует корректная строка JSON!", "JSON_ФАЙЛ", True)
def delete_cam(path_to_db: str, key1: str, key2: str, key3: str, statistic: Statistic) -> int: """Функция удаления камеры из БД. :param path_to_db: путь до БД :param key1: имя сервера :param key2: имя камеры :param key3: профиль :param statistic: объект класса Statistic :return: код ошибки: 0 - все ок. """ if not os.path.exists(path_to_db): statistic.append_error("Файла БД не существует!", "БД", True) try: time.sleep(0.2) conn = sqlite3.connect(path_to_db) cursor = conn.cursor() db_setname = key1 + "_" + key2 + "_" + key3 sql_cmd = "SELECT setid FROM setting WHERE settypeid = ? AND setname = ?" cursor.execute(sql_cmd, [1, db_setname]) db_setid = cursor.fetchall()[0][0] time.sleep(0.2) sql_cmd = "DELETE FROM setting WHERE setid = ?" cursor.execute(sql_cmd, [str(db_setid)]) conn.commit() conn.close() return 0 except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True)
def get_date_from_str(current_date: str, statistic: Statistic) -> datetime: """Функция возвращает datetime из строки. Аргумент current_date может быть вида: 1) %Y.%m.%d %H:%M:%S 2) %Y-%m-%dT%H:%M-%S 3) %Y-%m-%d %H:%M:%S 4) %Y-%m-%d %H:%M:%S.%f :param current_date: строка текущей даты; :param statistic: объект класса Statistic. :return: datetime. """ logger = statistic.get_log().get_logger("scripts/common/tools") logger.info("was called (current_date: str)") logger.debug("params (client_obj, " + current_date + ")") formats = [ '%Y.%m.%d %H:%M:%S', '%Y-%m-%dT%H:%M-%S', '%Y-%m-%d %H:%M:%S', "%Y-%m-%d %H:%M:%S.%f" ] for format_ in formats: try: return datetime.strptime(current_date, format_) except ValueError: continue statistic.append_error( "Не поддерживаемый формат даты " + current_date + "!", "НЕВАЛИД ФОРМАТ", True)
def get_cams_id(db_path: str, statistic: Statistic) -> tuple: if not os.path.exists(db_path): statistic.append_error("Файла БД не существует!", "БД", True) cam_jsons = [] try: time.sleep(0.2) conn = sqlite3.connect(db_path) cursor = conn.cursor() sql_cmd = "SELECT setvalue FROM setting WHERE settypeid = ?" cursor.execute(sql_cmd, [1]) cam_jsons: list = cursor.fetchall() conn.commit() conn.close() except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True) list_id54 = [] for cam_json in cam_jsons: cam_json = json.loads(cam_json[0]) if tools.check_keys_exist(cam_json, ['network_5_4'], 'cam_json', False, statistic) is False: continue tools.check_types(['network_5_4'], [cam_json['network_5_4']], [list], statistic) if not cam_json['network_5_4']: continue if tools.check_keys_exist(cam_json['network_5_4'][0], ['iv54server'], 'cam_json["network_5_4"][0]', False, statistic) is False: continue if tools.check_keys_exist( cam_json['network_5_4'][0]['iv54server'], ['ID_54'], 'cam_json["network_5_4"][0]["iv54server"]', False, statistic) is False: continue if tools.check_keys_exist( cam_json['network_5_4'][0]['iv54server']['ID_54'], ['_value'], 'cam_json["network_5_4"][0]["iv54server"]["ID_54"]', False, statistic) is False: continue to_add = True for id54 in list_id54: if id54 == cam_json['network_5_4'][0]['iv54server']['ID_54'][ "_value"]: to_add = False break if to_add: list_id54.append( cam_json['network_5_4'][0]['iv54server']['ID_54']["_value"]) return tuple(list_id54)
def replace_region_values_on_cam_json(json_detector: dict, region_name: str, new_region: dict, force: bool, statistic: Statistic) -> dict: """Замена зоны по ключам (только существующие ключи). :param json_detector: json с секцией детектора; :param region_name: имя зоны; :param new_region: словарь с новым регионом; :param force: вставить принудительно настройку, если ее нет в json; :param statistic: объект класса Statistic. :return: json с измененной секцией детектора в зоне """ logger = statistic.get_log().get_logger("scripts/common/graph") logger.info("was called (json_detector: dict, region_name: str, new_region: dict, statistic: Statistic") logger.debug("with params (" + str(json_detector) + ", " + region_name + ", " + str(new_region) + ")") detector_name = get_plugin_type(json_detector, statistic) data = get_region_from_detector_json(json_detector, region_name, statistic) index_region = data[0] region = data[1] if index_region == -1: statistic.append_error(region_name, "НЕТ ЗОНЫ") return {} region_json = json_detector[detector_name]['detection_regions']['square']['_value'][index_region] for first_lvl_key in new_region.keys(): if tools.check_keys_exist(region, [first_lvl_key], region_name, False, statistic) is False: if force: region_json[first_lvl_key] = new_region[first_lvl_key] txt_msg = first_lvl_key + " в зоне '" + region_name + " выполнена успешно!" logger.info(txt_msg) statistic.append_success(txt_msg, "ПРИНУДИТЕЛЬНАЯ ВСТАВКА КЛЮЧА В ЗОНЕ") continue # если данный ключ является отрисовкой зоны _points, то содержимое меняем # немного по другому if first_lvl_key == '_points': region_json['_points'] = new_region['_points'] txt_msg = "_ points в зоне " + region_name + " выполнена успешно!" logger.info(txt_msg) statistic.append_info(txt_msg, "ЗАМЕНА КЛЮЧЕЙ В ЗОНЕ") continue # для остальных ключей делаем замену в _value if tools.check_keys_exist(region[first_lvl_key], ['_value'], region_name + "[" + str(index_region) + "]", False, statistic) is False: continue if tools.check_keys_exist(new_region[first_lvl_key], ['_value'], first_lvl_key + " в новом регионе!", False, statistic) is False: continue region_json[first_lvl_key]['_value'] = new_region[first_lvl_key]['_value'] txt_msg = first_lvl_key + "[_value] в зоне '" + region_name + " выполнена успешно!" logger.info(txt_msg) statistic.append_success(txt_msg, "ЗАМЕНА КЛЮЧА В ЗОНЕ") return json_detector
def update_setname_by_cam(path_to_db: str, key1: str, key2: str, key3: str, new_key1: str, new_key2: str, new_key3: str, statistic: Statistic) -> int: """Функция изменения имени камеры в БД. :param path_to_db: :param key1: имя сервера :param key2: имя камеры :param key3: профиль камеры :param new_key1: новое имя сервера :param new_key2: новое имя камеры :param new_key3: новый профиль :param statistic: объект класса Statistic :return: код ошибки: 0 - все ок. """ logger = statistic.get_log().get_logger("scripts/common/db") logger.info( "was called (path_to_db: str, key1: str, key2: str, key3: str, new_key1: str, new_key2: str," + "new_key3: str, statistic: Statistic)") logger.debug("with params (" + path_to_db + ", " + key1 + ", " + key2 + ", " + key3 + ", " + new_key1 + ", " + new_key2 + ", " + new_key3 + ")") if not os.path.exists(path_to_db): statistic.append_error("Файла БД не существует!", "БД", True) try: time.sleep(0.2) conn = sqlite3.connect(path_to_db) cursor = conn.cursor() db_setname = key1 + "_" + key2 + "_" + key3 db_new_setname = new_key1 + "_" + new_key2 + "_" + new_key3 sql_cmd = "SELECT setid FROM setting WHERE settypeid = ? AND setname = ?" cursor.execute(sql_cmd, [1, db_setname]) db_setid = cursor.fetchall()[0][0] time.sleep(0.2) sql_cmd = "UPDATE setting SET setname = ? WHERE setid = ?" cursor.execute(sql_cmd, [db_new_setname, str(db_setid)]) conn.commit() conn.close() logger.info("db update setname for '" + key2 + "' cam was executed successfully") log.print_all("Обновление имени камеры c '" + db_setname + "' на '" + db_new_setname + "' выполнено успешно!") return 0 except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True)
def _common_check_response(xml_response: Tree, method_name: str, statistic: Statistic) -> Tree: logger = statistic.get_log().get_logger("scripts/xml/zmq") logger.info("was called (xml_response)") logger.debug("(" + Tree.tostring(xml_response).decode() + ")") if xml_response == -1: statistic.append_error(method_name + " завершился с ошибкой!", "ZMQ_ОТВЕТ") return -1 status = int(xml_response.find(".//status").text) if status != 0: status_descr = xml_response.find(".//statusDescr").text statistic.append_error("Статус ответа: " + str(status_descr), "ZMQ_ОТВЕТ") return -1 return xml_response
def check_types(names: List[str], values: list, types: list, statistic: Statistic) -> None: """Проверка типов значений. :param names: список имен значений; :param values: список значений; :param types: список типов; :param statistic: объект класса Statistic. """ for index, value in enumerate(values): # студия подчеркивает красным, но этом работает... if isinstance(value, types[index]) is False: statistic.append_error( "'" + str(value) + "' ключ '" + names[index] + "'... требуется " + str(types[index]), "НЕВАЛИД_ТИП", True)
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 compare_dirs(dir1: str, dir2: str, statistic: Statistic) -> None: """Сравнение двух директорий Рекурсивное сравнение двух директорий. Два файла равны, если их имена и содержимое одинаковы. :param dir1: Путь к первой директории; :param dir2: Путь к второй директории; :param statistic: объект класса Statistic. """ slash_index = dir1.rfind("/") simple_dir1_name = dir1[slash_index + 1:] slash_index = dir2.rfind("/") simple_dir2_name = dir2[slash_index + 1:] dirs_cmp = filecmp.dircmp( dir1, dir2) # сравнение директорий по количеству файлов и поддиректориям if len(dirs_cmp.left_only) > 0: message = "\nПапки только в " + simple_dir1_name + "\n" + str( dirs_cmp.left_only) + "\n" statistic.append_error(message, "ОТЛИЧИЕ") # print("Папки и файлы, содержащиеся только в пути ", dir1, dirs_cmp.left_only) if len(dirs_cmp.right_only) > 0: message = "\nПапки только в " + simple_dir2_name + "\n" + str( dirs_cmp.right_only) + "\n" statistic.append_error(message, "ОТЛИЧИЕ") (_, mismatch, errors) = filecmp.cmpfiles( dir1, dir2, dirs_cmp.common_files, shallow=False) # непосредственное сравнение файлов if len(mismatch) > 0: for file in mismatch: if os.stat(dir1 + "/" + file).st_mtime > os.stat(dir2 + "/" + file).st_mtime: first_dir_date = " (новее)" second_dir_date = "" else: first_dir_date = "" second_dir_date = " (новее)" first_file_info = "\nИмя: /" + simple_dir1_name + "/" + file + "\n" + \ "Размер: " + str(os.stat(dir1 + "/" + file).st_size) + " Б" + "\n" + \ "Дата изменения: " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(os.stat(dir1 + "/" + file).st_mtime)) + first_dir_date second_file_info = "Имя: /" + simple_dir2_name + "/" + file + "\n" + \ "Размер: " + str(os.stat(dir2 + "/" + file).st_size) + " Б" + "\n" + \ "Дата изменения: " + time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(os.stat(dir2 + "/" + file).st_mtime)) + second_dir_date + "\n" message = first_file_info + "\n------------------------------------\n" + second_file_info message = message.replace("\\", "/") statistic.append_error(message, "ОТЛИЧИЕ") if len(errors) > 0: statistic.append_error("Ошибка доступа к файлам: " + errors, "КРИТ", True) # рекурсивный переход по общим поддиректориям for common_dir in dirs_cmp.common_dirs: new_dir1 = os.path.join(dir1, common_dir) new_dir2 = os.path.join(dir2, common_dir) compare_dirs(new_dir1, new_dir2, statistic)
def ptzserver_list_profiles(client: SoapClient, token: str, statistic: Statistic) -> list: logger = statistic.get_log().get_logger("scripts/ws/ptz") logger.info( "was called (client: SoapClient, token: str, statistic: Statistic)") logger.debug("with params (client_obj, " + token + ", stat_obj)") params, sysparams, method = pattern.ptzserver_list_profiles(token) response = client.call_method2(method, params, sysparams, [0]) logger.info("ws method " + method + " was executed successfully!") statistic.append_info(method + " выполнен успешно!", "WS_МЕТОД") if not response["result"] or response["result"] == [{}]: statistic.append_error("Список PTZ камер пуст!", "НЕТ PTZ КАМЕР") return [] return response["result"]
class TestRunner(threading.Thread): """Класс для запуска тесте из тест кейса в отдельном потоке. """ def __init__(self, thread_id: int, module: str, test: str, input_data: dict, config: dict, log: Log): threading.Thread.__init__(self) self._statistic = Statistic(test, thread_id, config, log) self._test_class = test_classes[module](input_data, config, self._statistic) self._test = test self._id = str(thread_id) def get_statistic(self): """Метод-геттер получения объекта статистики. :return: """ return self._statistic def run(self): """Переопределенный метод запуска потока. """ full_test_name = self._test + "[Поток #" + self._id + "]" test_method = getattr(self._test_class, self._test) error_msg = "" try: self._test_class.setup() test_method() except SystemExit as e: error_msg = e.args[0] self._test_class.teardown() if error_msg: self._statistic.append_error( "Тест " + full_test_name + " завершился с критической ошибкой: " + error_msg, "КРИТ") else: self._statistic.append_success( "Тест " + full_test_name + " завершился без критических ошибок!", "УСПЕХ")
def init_run_tests(statistic: Statistic) -> Tuple[Tuple[str]]: """Получение списка тестов из тест-кейса Временно тест-кейс - это файл run_list.ini :return: список тестов вида ИМЯ-КЛАССА.ИМЯ-ТЕСТА """ if not os.path.exists(main.RUN_INI_PATH): statistic.append_error("run_list_ini", "ФАЙЛ_НЕ_СУЩ-ЕТ") run_list = [] with open(main.RUN_INI_PATH, encoding="utf-8") as run_list_file: for line in run_list_file: test_run_info = list(line.partition(" ")) test_run_info.remove(" ") test_run_info[1].replace("\n", "") run_list.append(tuple(test_run_info)) return tuple(run_list)
def _check_event_comment(event_info: dict, event: dict, statistic: Statistic) -> None: """Функция проверки вхождений значений ключей из event_info в event['evtcomment']. То есть есть ли указанные значения в комментарии события. :param event_info: ключи со значениями, которые надо искать в комментарии; :param event: событие (ответ ws); :param statistic: объект класса Statistic. """ logger = statistic.get_log().get_logger("scripts/tools/analytics") logger.info("was called (event_info: dict, event: dict, statistic: Statistic)") logger.debug("params (client_obj, " + str(event_info) + ", " + str(event) + ", stat_obj)") for key, value in event_info.items(): index = event['evtcomment'].find(value) if index == -1: statistic.append_error("Ожидалось: " + value + ". Получено: " + event['evtcomment'] + "!", "НЕВАЛИД " + key, False) else: statistic.append_success("Получено: '" + event['evtcomment'] + "'", "ВАЛИД " + key)
def send_hello(zmqclient: ZmqClient, id_: int, timeout: float, statistic: Statistic) -> int: """Функция отправки Hello. :param zmqclient: объект класса ZmqClient; :param id_: идентификатор; :param timeout: максимальное ожидание ответа; :param statistic: объект класса Statistic. :return: индекс успешности ответа: 0 - все ок, 1 - ошибка. """ message_id = str(uuid.uuid1()) xml_tree_hello = zmq.hello(message_id, id_) xml_tree_full = zmq.common_head(xml_tree_hello) xml_response = _send_request(zmqclient, xml_tree_full, message_id, timeout, statistic) if xml_response == -1: statistic.append_error("Запрос 'Hello' прошел неуспешно!", "ZMQ_ОТВЕТ", False) return -1 #log.print_test("Запрос 'Hello' выполнен успешно!") return 0
def replace_region_on_cam_json(json_detector: dict, new_region: dict, only_points: bool, statistic: Statistic) -> dict: """Полное замены зоны на детекторе без проверки внутренних ключей. :param json_detector: json с секцией детектора; :param new_region: словарь с новым регионом; :param only_points: заменить только список points; :param statistic: объект класса Statistic. :return: новые словарь json детектора. """ logger = statistic.get_log().get_logger("scripts/common/graph") logger.info("was called (json_detector: dict, new_region: dict, only_points: bool, statistic: Statistic)") logger.debug("replace_region_on_cam_json(" + str(json_detector) + ", " + str(new_region) + ", " + str(only_points) + ")") region_name = get_region_name(new_region, statistic) detector_name = get_plugin_type(json_detector, statistic) data = get_region_from_detector_json(json_detector, region_name, statistic) index_region = data[0] original_region = data[1] if index_region == -1: statistic.append_error("в " + region_name, "НЕТ_ЗОНЫ", False) return {} if only_points: if '_points' not in original_region: statistic.append_error("'_points' в '" + region_name + "'!", "НЕТ_КЛЮЧА", False) elif '_points' not in new_region: statistic.append_error("'_points' в новой зоне!", "НЕТ_КЛЮЧА", False) json_detector[detector_name]['detection_regions']['square']['_value'][index_region]['_points'] = \ new_region['_points'] else: json_detector[detector_name]['detection_regions']['square']['_value'][index_region] = new_region return json_detector
def get_servers(db_path: str, statistic: Statistic) -> Tuple[str]: """Получение списка всех серверов из БД. :param db_path: путь к бд; :param statistic: объект класса Statistic. :return: список серверов. """ logger = statistic.get_log().get_logger("scripts/common/db") logger.info("was called (path_to_db: str, statistic: Statistic)") logger.debug("with params (" + db_path + ")") if not os.path.exists(db_path): statistic.append_error("Файла БД не существует!", "БД", True) try: time.sleep(0.2) conn = sqlite3.connect(db_path) cursor = conn.cursor() sql_cmd = "SELECT vsrname FROM videoserver" cursor.execute(sql_cmd) query_result = cursor.fetchall() conn.commit() conn.close() servers = [] for result in query_result: servers.append(result[0]) if not servers: statistic.append_error("Не обнаружено ни одного сервера!", "БД") return tuple(servers) except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True)
def check_keys_exist(dict_on_check: dict, keys: list, dict_name: str, is_critical: bool, statistic: Statistic) -> bool: """проверка на наличия ключей в словаре. :param dict_on_check: словарь к проверке; :param keys: список ключей, на существование которых идет проверка; :param dict_name: имя проверяемого словаря для понимания пользователем; :param is_critical: флаг - выбрасывать исключение при отсутствии ключа или нет и отпечатать только сообщение; :param statistic: экземляр класса Statistic для добавления ошибок и предупреждений. :return: флак успешности проверки. """ logger = statistic.get_log().get_logger("scripts/common/tools") logger.info("was called") logger.debug("with params (" + str(dict_on_check) + ", " + str(keys) + ", " + dict_name + ", " + str(is_critical) + ")") if isinstance(dict_on_check, dict) is False: statistic.append_error("'" + dict_name + "'", "НЕТ_СЛОВАРЯ", True) success = True for key in keys: if key not in dict_on_check: success = False if is_critical: statistic.append_error("'" + key + "' в '" + dict_name + "'!", "НЕТ_КЛЮЧА", True) else: logger.error("'" + key + "' в '" + dict_name + "'!") statistic.append_error("'" + key + "' в '" + dict_name + "'!", "НЕТ_КЛЮЧА") return success
def search_response_index_by_message_id(xml_responses: list, message_id: str, statistic: Statistic) -> int: """Поиск в списке xml у которого значение тега messageId совпадает с message_id. :param xml_responses: список xml :param message_id: значение тега messageId :param statistic: объект класса Statistic :return: 1) индекс в списке; 2) -1 в случае отсутствия совпадения """ logger = log.get_logger("scripts/xml/zmq") logger.info("was called (list_xml_responses, message_id)") logger.debug("(" + str(xml_responses) + ", " + str(message_id) + ")") for index, response in enumerate(xml_responses): tag_nessage_id = response.find(".//messageId") if tag_nessage_id is None: statistic.append_error("Отсутствует тег 'messageId'", "ZMQ_ОТВЕТ", True) logger.debug("response messageId is " + tag_nessage_id.text) if message_id == tag_nessage_id.text: logger.info("message_Id is equal!") return index logger.info("message_Id isn't equal!") return -1
def insert_new_cam(path_to_db: str, key1: str, key2: str, key3: str, json_graph: dict, statistic: Statistic) -> int: """Вставка нового графа (камеры) в таблицу :param path_to_db: путь до БД :param key1: имя сервера :param key2: имя камеры :param key3: профиль :param json_graph: граф в формате json :param statistic: объект класса Statistic :return: первичный ключ """ if not os.path.exists(path_to_db): statistic.append_error("Файла БД не существует!", "БД", True) try: time.sleep(0.5) conn = sqlite3.connect(path_to_db) cursor = conn.cursor() db_setname = key1 + "_" + key2 + "_" + key3 db_setvalue = json.dumps(json_graph).replace("\\\\/$", "\\/$") obj_md5_hash = hashlib.md5(db_setvalue.encode('utf-8')) db_sethash = obj_md5_hash.hexdigest() sql_cmd = "INSERT INTO setting (setid, settypeid, setname, setvalue, setcomment, setinfo, sethash) " \ "VALUES (?, ?, ?, ?, ?, ?, ?)" cursor.execute(sql_cmd, [None, 1, db_setname, db_setvalue, "", "", db_sethash]) conn.commit() time.sleep(0.5) db_setid = get_setid(path_to_db, key1, key2, key3, statistic) conn.close() return db_setid except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True)
def get_cam_json(path_to_db: str, key1: str, key2: str, key3: str, statistic: Statistic) -> dict: """Получение json графа (камеры) из БД. Делает SELECT запрос к БД на получение json-ов всех камер и профилей, а затем осуществляется поиск нужной камеры. :param path_to_db: путь к файлу БД; :param key1: имя сервера; :param key2: имя камеры; :param key3: профиль камеры; :param statistic: объект класса Statistic. :return: json в виде словаря. """ logger = statistic.get_log().get_logger("scripts/common/db") logger.info( "was called path_to_db: str, key1: str, key2: str, key3: str, statistic: Statistic)" ) logger.debug("with params (" + path_to_db + ", " + key1 + ", " + key2 + ", " + key3 + ")") if not os.path.exists(path_to_db): statistic.append_error("Файла БД не существует!", "БД", True) try: time.sleep(0.2) conn = sqlite3.connect(path_to_db) cursor = conn.cursor() db_setname = key1 + "_" + key2 + "_" + key3 sql_cmd = 'SELECT setvalue FROM setting WHERE settypeid = ? AND setname = ?' cursor.execute(sql_cmd, [1, db_setname]) json_cam = cursor.fetchall() conn.commit() conn.close() if not json_cam: statistic.append_error("Камера '" + db_setname + "' отсутствует!", "БД") return {} logger.info("db select json by '" + db_setname + "' cam was executed successfully!") statistic.append_info( "Получение json из БД камеры '" + db_setname + "' выполнено успешно!", "БД") # в некоторых плагинах есть сочетания слешей вида: \/, которое нельзя никак заменять. # При десериализации по умолчанию символ \ пропадает, как служебный. # Поэтому перед десериализацией необходимо добавить два слеша, чтобы было так (\\/). # Однако почему то в таком случае после десериализации оно так и останется (\\/), а не (\/). # То есть потом при сериализации этот момент нужно учесть и заменить на \/. replaced_json_cam = json_cam[0][0].replace("\\/", "\\\\/") return json.loads(replaced_json_cam, parse_float=json_float_parser) except sqlite3.OptimizedUnicode: statistic.append_error("Ошибка выполнения команды!", "БД", True)
def send_enroll_models(zmqclient: ZmqClient, photo_path: str, timeout: float, statistic: Statistic) -> tuple: """Функция отправки EnrollModels. :param zmqclient: объект класса ZmqClient; :param photo_path: путь к фото; :param timeout: время ожидания ответа; :param statistic: объект класса Statistic. :return: дескриптор фото и ее id. """ logger = statistic.get_log().get_logger("scripts/xml/zmq") logger.info("was called (zmqclient, list_photo_paths, timeout)") message_id = str(uuid.uuid1()) photo_type = tools.get_file_type(photo_path) photo_id = str(uuid.uuid1()) photo_base64 = tools.get_photos_base64([photo_path])[0] xml_tree_enroll_models = zmq.enroll_models(message_id, False, photo_base64, photo_type, photo_id) xml_tree_full = zmq.common_head(xml_tree_enroll_models) xml_response = _common_check_response(_send_request(zmqclient, xml_tree_full, message_id, timeout, statistic), "EnrollModels", statistic) list_faces = xml_response.findall(".//face") if not list_faces: statistic.append_error("В ответе нет лиц!", "ZMQ_ОТВЕТ", True) if len(list_faces) > 1: statistic.append_error("Кол-во лиц > 1", "ZMQ_ОТВЕТ", True) descriptor = "" image_id = xml_response.find(".//image") if image_id is None: statistic.append_error("Отсутствует тек 'image'!", "ZMQ_ОТВЕТ", False) image_id = xml_response.find(".//image").text if image_id != photo_id: statistic.append_error("ID каритнки не совпадают!", "ZMQ_ОТВЕТ", False) for face in list_faces: descriptor = face.find(".//model").text break return descriptor, photo_id
def faceva_update_person(client: SoapClient, token: str, id_: int, pacs_id: int, name: str, category: str, comment: str, information: str, department: str, faces: Tuple[dict], delete_faces: Tuple[dict], statistic: Statistic) -> str: """Функция выполнения ws метода FaceVA:UpdatePerson. :param client: объект класса SoapClient для отправки и приема ws запросов; :param token: токен соединения; :param id_: идентификатор персоны в БД; :param pacs_id: идентификатор персоны в БД для СКД; :param name: ФИО персоны; :param category: категория; :param comment: комментарий; :param information: информация; :param department: отдел; :param faces: список фото лиц для добавления; :param delete_faces: список фото для удаления; :param statistic: объект класса Statistic для ведения статистики ошибок и предупреждений. :return: идентификатор персоны в базе. """ logger = statistic.get_log().get_logger("scripts/ws/analytics") logger.info( "was called faceva_update_person(client: SoapClient, login: str, id_: int, pacs_id: int,\ name: str, category: str, comment: str, information: str, department: str, faces: List[dict], \ delete_faces: List[dict])") logger.debug("faceva_update_person(client_obj" + token + ", " + str(id_) + ", " + str(pacs_id) + ", " + name + ", " + category + ", " + comment + ", " + information + ", " + department + ", " + ", " + str(faces) + ", " + str(delete_faces) + ")") params, sysparams, method = pattern.faceva_update_person( token, id_, pacs_id, name, category, comment, information, department, faces, delete_faces) response_json = client.call_method2(method, params, sysparams, [0]) person = response_json['result'][0] key_names = [ "id", "pacs", "name", "category", "comment", "information", "department", "result", "faces" ] tools.check_keys_exist(person, key_names, "['result'][0]", True, statistic) key_names.remove("result") key_names.remove("faces") key_values = [ person["id"], person["pacs"], person["name"], person["category"], person["comment"], person["information"], person["department"] ] key_need_values = [ id_, str(pacs_id), name, category, comment, information, department ] operations = ["==", "==", "==", "==", "==", "==", "=="] if id_ == -1: key_names.pop(0) key_values.pop(0) key_need_values.pop(0) operations.pop(0) tools.check_values(key_names, key_values, key_need_values, operations, statistic) tools.check_types(["faces"], [person["faces"]], [list], statistic) if not person['faces'] and faces: statistic.append_error("Список faces", "НЕТ_ЛИЦ", True) for index, face in enumerate(person["faces"]): tools.check_keys_exist(face, ["result"], "face", True, statistic) if face["result"] == "error": tools.check_keys_exist(face, ["reason"], "face", True, statistic) statistic.append_error("причина: " + face["reason"], "ПЛОХОЕ_ФОТО", False) logger.info("ws method FaceVA:UpdatePerson was executed successfully!") statistic.append_info(method + " выполнен успешно!", "WS МЕТОД") return person["id"]
def get_coordinates(client: SoapClient, login: str, password: str, key2: str, statistic: Statistic) -> dict: """Функция для получения координат (использует ws метод ptzclient:Command). :param client: объект soap клиента; :param login: логин пользователя; :param password: пароль пользователя; :param key2: имя камеры; :param statistic: объект класса Statistic. :return: словарь с координатами (ключи pan и tilt). """ logger = statistic.get_log().get_logger("scripts/tools/ptz") logger.info( "was called (client: SoapClient, login: str, password: str, key2: str)" ) logger.debug("with params (client_obj, " + login + ", " + password + ", " + key2 + ")") logger.info("call ptzclient_command_simple()") statistic.append_info("получение старых координат...", "ИНФО") logger.info("getting old coordinates") query_all_result = ws.ptzclient_command_simple(client, key2, login, password, False, 0, 0, 0, 0, 0, 0, True, 0, 0, -1, -1, False) tools.check_types(["old_coordinates['result'][0]"], [query_all_result["result"][0]], [dict], statistic) is_old_coordinates = tools.check_keys_exist( query_all_result["result"][0], ["pan", "tilt", "timecoords"], 'old_coordinates["result"][0]', False, statistic) old_timecoords = 0 if is_old_coordinates: old_pan = query_all_result["result"][0]["pan"] old_tilt = query_all_result["result"][0]["tilt"] old_timecoords = query_all_result["result"][0]["timecoords"] logger.debug("old_pan: " + str(old_pan) + ", old_tilt: " + str(old_tilt) + ", old_timecoords: " + str(old_timecoords)) count_coordinates_missing = 0 while True: logger.info("call ptzclient_command_simple()") statistic.append_info("получение текуших координат...", "ИНФО") logger.info("getting current coordinates") current_coordinates = ws.ptzclient_command_simple( client, key2, login, password, False, 0, 0, 0, 0, 0, 0, True, 0, 0, -1, -1, False) tools.check_types(["current_coordinates['result'][0]"], [current_coordinates["result"][0]], [dict], statistic) is_current_coordinates = tools.check_keys_exist( current_coordinates["result"][0], ["pan", "tilt"], 'current_coordinates["result"][0]', False, statistic) if is_current_coordinates is False: count_coordinates_missing += 1 if count_coordinates_missing == 3: statistic.append_error( "Получение координат завершилось с ошибкой!", "НЕТ_КООРДИНАТ", False) break continue current_timecoords = current_coordinates["result"][0]["timecoords"] if is_old_coordinates and current_timecoords != old_timecoords or is_old_coordinates is False: current_pan = current_coordinates["result"][0]["pan"] current_tilt = current_coordinates["result"][0]["tilt"] logger.debug("current_pan: " + str(current_pan) + ", current_tilt: " + str(current_tilt)) return {"pan": current_pan, "tilt": current_tilt}
def go_to_coordinate(client: SoapClient, login: str, password: str, key2: str, ws_method: str, cmd: str, coordinate: int, statistic: Statistic, inaccuracy: int = 0) -> bool: """Функция перевода камеры в указанные координаты. :param client: объект soap клиентя :param login: логин пользователя :param password: пароль пользователя :param key2: имя камеры :param ws_method: через какой метод выполнять команду (ptzserver или ptzclient) :param cmd: команда :param coordinate: координаты :param statistic: объект класса Statistic :param inaccuracy точность :return: флаг успешности перехода """ logger = statistic.get_log().get_logger("scripts/tools/ptz") logger.info( "was called (client: SoapClient, login: str, password: str, key2: str, \ cmd: str, coordinate: int, inaccuracy: int = 0)") logger.debug("with params (client_obj, " + login + ", " + password + ", " + key2 + ", " + cmd + ", " + str(coordinate) + ", " + str(inaccuracy) + ")") pan_to = -1 tilt_to = -1 if cmd == "PanTo": pan_to = coordinate elif cmd == "TiltTo": tilt_to = coordinate else: statistic.append_error(cmd, "НЕВАЛИД_КОМАНДА_PTZ", True) if ws_method == "ptzclient": ws.ptzclient_command_simple(client, key2, login, password, False, 0, 0, 0, 0, 0, 0, False, 0, 0, pan_to, tilt_to, False) message = "ws 'ptzclient:Command[" + cmd + "=" + str( coordinate) + "]' отправлен..." elif ws_method == "ptzserver": ws.ptzserver_command_simple(client, key2, login, password, False, 0, 0, 0, 0, 0, 0, False, 0, 0, pan_to, tilt_to, False) message = "ws 'ptzserver:Command[" + cmd + "=" + str( coordinate) + "]' отправлен..." else: statistic.append_error(ws_method, "НЕВАЛИД_МЕТОД_PTZ", True) statistic.append_info(message, "ПЕРЕХОД В КООРДИНАТЫ") logger.info(message) time.sleep(1) coordinates = get_coordinates(client, login, password, key2, statistic) if cmd == "TiltTo": current_coordinate = coordinates["tilt"] else: current_coordinate = coordinates["pan"] if compare_coordinates(coordinate, current_coordinate, inaccuracy): statistic.append_info( cmd + " " + str(coordinate) + " выполнена успешно!", "УСПЕХ") logger.info(cmd + " " + str(coordinate) + " was executed successfully!") return True else: return False