// Copyright 2016 Etix Labs // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include /* DATA FORMAT ** ** Example : ** ** "address" : "173.16.100.45", ** "ids_found" : true, ** "password" : "123456", ** "path_found" : true, ** "port" : 554, ** "product" : "Vivotek FD9381-HTV", ** "protocol" : "tcp", ** "route" : "/live.sdp", ** "service_name" : "rtsp", ** "state" : "open", ** "thumbnail_path" : "/tmp/127.0.0.1/1463735257.jpg", ** "username" : "admin" ** */ namespace etix { namespace cameradar { const std::string mysql_cache_manager::create_table_query = "CREATE TABLE IF NOT EXISTS `results` (" "`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, " "`address` tinytext NOT NULL, " "`password` tinytext NOT NULL, " "`product` tinytext NOT NULL, " "`protocol` tinytext NOT NULL, " "`route` tinytext NOT NULL, " "`service_name` tinytext NOT NULL, " "`state` tinytext NOT NULL, " "`thumbnail_path` tinytext NOT NULL, " "`username` tinytext NOT NULL, " "`port` int(11) UNSIGNED NOT NULL, " "`ids_found` tinytext NOT NULL, " "`path_found` tinytext NOT NULL, " "PRIMARY KEY (`id`));"; const std::string mysql_cache_manager::insert_with_id_query = "INSERT INTO `%s`.`results`" " (`address`, `password`, `product`, `protocol`, `route`, `service_name`, `state`, " "`thumbnail_path`, `username`, `port`, `ids_found`, `path_found`)" " VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')"; const std::string mysql_cache_manager::update_result_query = "UPDATE `%s`.`results` SET" " `results`.`address` = '%s'," " `results`.`password` = '%s'," " `results`.`product` = '%s'," " `results`.`protocol` = '%s'," " `results`.`route` = '%s'," " `results`.`service_name` = '%s'," " `results`.`state` = '%s'," " `results`.`thumbnail_path` = '%s'," " `results`.`username` = '%s'," " `results`.`port` = '%s'," " `results`.`ids_found` = '%s'," " `results`.`path_found` = '%s'" " WHERE `results`.`address` LIKE '%s'"; const std::string mysql_cache_manager::exist_query = "SELECT * FROM `%s`.`results` WHERE `results`.`address` = '%s'"; const std::string mysql_cache_manager::get_results_query = "SELECT * FROM `%s`.`results`"; const std::string mysql_cache_manager::name = "mysql-cache-manager"; mysql_cache_manager::~mysql_cache_manager() {} const std::string& mysql_cache_manager::get_name() const { return mysql_cache_manager::static_get_name(); } const std::string& mysql_cache_manager::static_get_name() { return mysql_cache_manager::name; } bool mysql_cache_manager::configure(std::shared_ptr configuration) { return this->load_mysql_conf(configuration); } bool mysql_cache_manager::execute_query(const std::string& query) { auto check_err = [](const auto& res) { if (res.state == mysql::execute_result::sql_error) { LOG_WARN_(res.error_msg, "mysql_cache_manager"); return false; } return true; }; return check_err(this->connection.execute(query)); } bool mysql_cache_manager::load_mysql_conf( std::shared_ptr configuration) { this->configuration = configuration; try { this->db_conf.host = configuration->raw_conf["mysql_db"]["host"].asString(); this->db_conf.port = configuration->raw_conf["mysql_db"]["port"].asUInt(); this->db_conf.user = configuration->raw_conf["mysql_db"]["user"].asString(); this->db_conf.password = configuration->raw_conf["mysql_db"]["password"].asString(); this->db_conf.db_name = configuration->raw_conf["mysql_db"]["db_name"].asString(); } catch (const std::exception& e) { LOG_ERR_("Configuration of the MySQL db failed : " + std::string(e.what()), "mysql_cache_manager"); return false; } if (not this->connection .connect(db_conf.host + ":" + std::to_string(db_conf.port), db_conf.user, db_conf.password, db_conf.db_name) .first) { LOG_ERR_("Configuration of the MySQL DB failed", "mysql_cache_manager"); return false; } // Tries to create the Result table in the DB and returns the success state return (execute_query(create_table_query)); } //! Replaces all cached streams by the content of the vector given as //! parameter void mysql_cache_manager::set_streams(std::vector models) { LOG_DEBUG_("Beginning stream list DB insertion", "mysql_cache_manager"); std::lock_guard lock(m); for (const auto& model : models) { if (!model.service_name.compare("rtsp") && !model.state.compare("open")) { auto query = tool::fmt( this->exist_query, this->connection.get_db_name().c_str(), model.address.c_str()); auto result = this->connection.query(query); if (result.data->next()) continue; query = tool::fmt(this->insert_with_id_query, this->connection.get_db_name().c_str(), model.address.c_str(), model.password.c_str(), model.product.c_str(), model.protocol.c_str(), model.route.c_str(), model.service_name.c_str(), model.state.c_str(), model.thumbnail_path.c_str(), model.username.c_str(), std::to_string(model.port).c_str(), std::to_string(model.ids_found).c_str(), std::to_string(model.path_found).c_str()); execute_query(query); } } } //! Inserts a single stream to the cache void mysql_cache_manager::update_stream(const etix::cameradar::stream_model& model) { auto query = tool::fmt(this->update_result_query, this->connection.get_db_name().c_str(), model.address.c_str(), model.password.c_str(), model.product.c_str(), model.protocol.c_str(), model.route.c_str(), model.service_name.c_str(), model.state.c_str(), model.thumbnail_path.c_str(), model.username.c_str(), std::to_string(model.port).c_str(), std::to_string(model.ids_found).c_str(), std::to_string(model.path_found).c_str(), model.address.c_str()); std::lock_guard lock(m); execute_query(query); } //! Gets all cached streams std::vector mysql_cache_manager::get_streams() { auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str()); auto result = this->connection.query(query); if (not result.data) { delete result.data; return {}; } std::vector lst; while (result.data->next()) { // If it's an open RTSP stream if (not result.data->getString("state").compare("open") && not result.data->getString("service_name").compare("rtsp")) { stream_model s{ result.data->getString("address"), result.data->getUInt("port"), result.data->getString("username"), result.data->getString("password"), result.data->getString("route"), result.data->getString("service_name"), result.data->getString("product"), result.data->getString("protocol"), result.data->getString("state"), result.data->getBoolean("path_found"), result.data->getBoolean("ids_found"), result.data->getString("thumbnail_path") }; lst.push_back(s); } } delete result.data; return lst; } //! Gets all valid streams std::vector mysql_cache_manager::get_valid_streams() { auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str()); auto result = this->connection.query(query); if (not result.data) { delete result.data; return {}; } std::vector lst; while (result.data->next()) { // If the ID and the Path were found add this stream if (not result.data->getString("ids_found").compare("1") && not result.data->getString("path_found").compare("1")) { stream_model s{ result.data->getString("address"), result.data->getUInt("port"), result.data->getString("username"), result.data->getString("password"), result.data->getString("route"), result.data->getString("service_name"), result.data->getString("product"), result.data->getString("protocol"), result.data->getString("state"), result.data->getBoolean("path_found"), result.data->getBoolean("ids_found"), result.data->getString("thumbnail_path") }; lst.push_back(s); } } delete result.data; return lst; } // Returns true if the stream passed as a parameter has changed in the cache bool mysql_cache_manager::has_changed(const etix::cameradar::stream_model& old) { auto query = tool::fmt(this->get_results_query, this->connection.get_db_name().c_str()); auto result = this->connection.query(query); if (not result.data) { delete result.data; return {}; } while (result.data->next()) { if (result.data->getString("address") == old.address) if (result.data->getBoolean("ids_found") != old.ids_found || result.data->getBoolean("path_found") != old.path_found) return true; } return false; } extern "C" { cache_manager_iface* cache_manager_instance_new() { return new mysql_cache_manager(); } } } }