hunting/middleware/FilesManager/src/sqlite3/SqliteHandle.cpp
2024-07-15 19:31:06 +08:00

448 lines
16 KiB
C++

/*
* Copyright (c) 2023 Fancy Code.
* 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 "SqliteHandle.h"
#include "IFilesManager.h"
#include "ILog.h"
#include "sqlite3.h"
#include <cstdlib>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <time.h>
#include <vector>
#define FILES_TABLE "files"
#define TABLE_KEY "key"
#define FILE_PATH "path"
#define CREATE_TIME "create_time"
#define FILE_TYPE "type"
#define FILE_SIZE "size"
#define FILE_STATUS "status"
#define FILE_DURATION "duration"
#define FILE_STATUS_BE_RECORDING "recording"
#define FILE_STATUS_COMPLETE_RECORD "complete_record"
#define FILE_STATUS_SHOULD_BE_UPLOADED "should_be_uploaded"
#define FILE_STATUS_UPLOADING "uploading"
#define FILE_STATUS_UPLOADED "uploaded"
#define FIEL_TYPE_PIR "pir"
#define FIEL_TYPE_MANUAL_TEST "manual_test"
#define FIEL_TYPE_MANUAL_PHONE "manual_phone"
#define FIEL_TYPE_TIMED "timed"
#define FILE_TYPE_UNDEFINE "undefine"
SqliteHandle::SqliteHandle() : mDb(nullptr)
{
}
std::shared_ptr<SqliteHandle> &SqliteHandle::GetInstance(std::shared_ptr<SqliteHandle> *impl)
{
static auto instance = std::make_shared<SqliteHandle>();
if (impl) {
if (instance.use_count() == 1) {
LogInfo("Instance changed succeed.\n");
instance = *impl;
}
else {
LogError("Can't changing the instance becase of using by some one.\n");
}
}
return instance;
}
void SqliteHandle::Init(const std::string &dbFileName)
{
if (nullptr != mDb) {
LogWarning("SqliteHandle has been init.\n");
return;
}
int rc = SQLITE_UNDEFINE;
rc = sqlite3_open(dbFileName.c_str(), &mDb);
if (SQLITE_OK != rc) {
LogError("open sqlite3 failed: %s\n", sqlite3_errmsg(mDb));
sqlite3_close(mDb);
return;
}
DbInit(mDb);
}
void SqliteHandle::UnInit(void)
{
if (mDb) {
sqlite3_close(mDb);
mDb = nullptr;
}
}
unsigned long int SqliteHandle::CreateFiles(const unsigned int &count)
{
char *err_msg = nullptr;
int rc = SQLITE_UNDEFINE;
const char *sql =
"INSERT INTO " FILES_TABLE " (" FILE_PATH ", " CREATE_TIME ", " FILE_TYPE ", " FILE_SIZE ", " FILE_STATUS
", " FILE_DURATION ") VALUES (\"\", 0, \"" FILE_TYPE_UNDEFINE "\", 0, \"" FILE_STATUS_BE_RECORDING "\", 0);";
for (unsigned int i = 0; i < count; ++i) {
rc = sqlite3_exec(mDb, sql, nullptr, nullptr, &err_msg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", err_msg);
sqlite3_free(err_msg);
return 0;
}
}
auto last_rowid_lambda = [](void *last_rowid, int argc, char **argv, char **azColName) -> int {
if (argc > 0) {
LogInfo("last_rowid key = %s\n", argv[0]);
*(unsigned long int *)last_rowid = strtoul(argv[0], nullptr, 10);
}
return 0;
};
unsigned long int last_rowid = 0;
const char *sql2 = "SELECT last_insert_rowid();";
rc = sqlite3_exec(mDb, sql2, last_rowid_lambda, &last_rowid, &err_msg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", err_msg);
sqlite3_free(err_msg);
return 0;
}
constexpr int MINIMUM_AUTO_INCREMENT_PRIMARY_KEY = 1;
return last_rowid - count + MINIMUM_AUTO_INCREMENT_PRIMARY_KEY;
}
bool SqliteHandle::SyncFile(const SyncFileInfo &info)
{
if (UNDEFINE_SERIAL_NUMBER == info.mSerialNumber) {
LogError("Serial number is undefine.\n");
return false;
}
std::stringstream sqlStream;
std::string comma = " ";
sqlStream << "UPDATE " FILES_TABLE " SET ";
if (UNDEFINE_CREATE_TIME != info.mCreateTime_s) {
sqlStream << comma << CREATE_TIME " = '" << info.mCreateTime_s << "'";
comma = ", ";
}
if (info.mFileName.empty() == false) {
sqlStream << comma << FILE_PATH " = '" << info.mFileName << "'";
comma = ", ";
}
if (UNDEFINE_FILE_SIZE != info.mFileSize) {
sqlStream << comma << FILE_SIZE " = '" << info.mFileSize << "'";
comma = ", ";
}
if (FileStatus::END != info.mStatus) {
sqlStream << comma << FILE_STATUS " = '" << ConvertFileStatusToString(info.mStatus) << "'";
comma = ", ";
}
if (FileCreateType::END != info.mType) {
sqlStream << comma << FILE_TYPE " = '" << ConvertFileTypeToString(info.mType) << "'";
comma = ", ";
}
if (UNDEFINE_FILE_DURATION != info.mFileDuration) {
sqlStream << comma << FILE_DURATION " = '" << info.mFileDuration << "'";
comma = ", ";
}
sqlStream << " WHERE " TABLE_KEY " = " << info.mSerialNumber << ";";
LogInfo("Sql: %s\n", sqlStream.str().c_str());
char *errMsg = nullptr;
int rc = SQLITE_UNDEFINE;
rc = sqlite3_exec(mDb, sqlStream.str().c_str(), nullptr, nullptr, &errMsg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
return false;
}
LogInfo("Sync file success.\n");
return true;
}
bool SqliteHandle::SearchFiles(const std::vector<FileCreateType> &types, std::vector<SyncFileInfo> &info)
{
std::string sqlAnd = " ";
// if (types.size() > 1) {
// sqlAnd = " AND ";
// }
constexpr FileCreateType END_MEANS_SEARCHING_ALL_FILES = FileCreateType::END;
std::stringstream sqlStream;
if (types.size() == 1 && types[0] == END_MEANS_SEARCHING_ALL_FILES) {
sqlStream << "SELECT * from " FILES_TABLE << ";";
}
else {
sqlStream << "SELECT * from " FILES_TABLE " WHERE ";
for (auto &type : types) {
sqlStream << sqlAnd << FILE_TYPE " = '" << ConvertFileTypeToString(type) << "'";
sqlAnd = " OR ";
}
sqlStream << ";";
}
LogInfo("Sql: %s\n", sqlStream.str().c_str());
return SearchFiles(mDb, sqlStream.str(), info);
}
void SqliteHandle::DbInit(sqlite3 *db)
{
if (nullptr == db) {
LogError("db is null.\n");
return;
}
char *errMsg = nullptr;
int rc = SQLITE_UNDEFINE;
const char *sql = "CREATE TABLE IF NOT EXISTS " FILES_TABLE " (" TABLE_KEY
" INTEGER PRIMARY KEY AUTOINCREMENT, " FILE_PATH " TEXT, " CREATE_TIME " INTEGER," FILE_TYPE
" TEXT, " FILE_SIZE " INTEGER, " FILE_STATUS " TEXT," FILE_DURATION " INTEGER);";
rc = sqlite3_exec(db, sql, nullptr, nullptr, &errMsg);
if (SQLITE_OK != rc) {
LogError("Sql: %s, errMsg: %s\n", sql, errMsg);
sqlite3_free(errMsg);
}
else {
LogInfo("Sqlite init success. table = %s\n", FILES_TABLE);
}
}
bool SqliteHandle::UpdateCreateTime(sqlite3 *db, const unsigned long &key, const time_t &createTime)
{
if (nullptr == db) {
LogError("db is null.\n");
return false;
}
char *errMsg = nullptr;
int rc = SQLITE_UNDEFINE;
if (UNDEFINE_CREATE_TIME != createTime) {
std::stringstream sqlStream;
sqlStream << "UPDATE " FILES_TABLE " SET " CREATE_TIME " = '" << createTime << "' WHERE " TABLE_KEY " = " << key
<< ";";
LogInfo("Sql: %s\n", sqlStream.str().c_str());
rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
return false;
}
}
return true;
}
bool SqliteHandle::UpdateFileName(sqlite3 *db, const unsigned long &key, const std::string &fileName)
{
if (nullptr == db) {
LogError("db is null.\n");
return false;
}
char *errMsg = nullptr;
int rc = SQLITE_UNDEFINE;
if (fileName.empty() == false) {
std::stringstream sqlStream;
sqlStream << "UPDATE " FILES_TABLE " SET " FILE_PATH " = '" << fileName << "' WHERE " TABLE_KEY " = " << key
<< ";";
LogInfo("Sql: %s\n", sqlStream.str().c_str());
rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
return false;
}
}
return true;
}
bool SqliteHandle::UpdateFileSize(sqlite3 *db, const unsigned long &key, const unsigned long &fileSize)
{
if (nullptr == db) {
LogError("db is null.\n");
return false;
}
char *errMsg = nullptr;
int rc = SQLITE_UNDEFINE;
if (UNDEFINE_FILE_SIZE != fileSize) {
std::stringstream sqlStream;
sqlStream << "UPDATE " FILES_TABLE " SET " FILE_SIZE " = '" << fileSize << "' WHERE " TABLE_KEY " = " << key
<< ";";
LogInfo("Sql: %s\n", sqlStream.str().c_str());
rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
return false;
}
}
return true;
}
bool SqliteHandle::UpdateFileType(sqlite3 *db, const unsigned long &key, const FileCreateType &type)
{
if (nullptr == db) {
LogError("db is null.\n");
return false;
}
char *errMsg = nullptr;
int rc = SQLITE_UNDEFINE;
if (FileCreateType::END != type) {
std::stringstream sqlStream;
sqlStream << "UPDATE " FILES_TABLE " SET " FILE_TYPE " = '" << ConvertFileTypeToString(type)
<< "' WHERE " TABLE_KEY " = " << key << ";";
LogInfo("Sql: %s\n", sqlStream.str().c_str());
rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
return false;
}
}
return true;
}
bool SqliteHandle::UpdateFileDuration(sqlite3 *db, const unsigned long &key, const unsigned int &duration)
{
if (nullptr == db) {
LogError("db is null.\n");
return false;
}
char *errMsg = nullptr;
int rc = SQLITE_UNDEFINE;
std::stringstream sqlStream;
sqlStream << "UPDATE " FILES_TABLE " SET " FILE_DURATION " = '" << duration << "' WHERE " TABLE_KEY " = " << key
<< ";";
LogInfo("Sql: %s\n", sqlStream.str().c_str());
rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
return false;
}
return true;
}
bool SqliteHandle::SearchFiles(sqlite3 *db, const std::string &sql, std::vector<SyncFileInfo> &info)
{
if (nullptr == db) {
LogError("db is null.\n");
return false;
}
auto dbCallback = [](void *data, int argc, char **argv, char **azColName) -> int {
/********************** Do not delete this code to avoid debugging. *********************/
int i = 0;
fprintf(stderr, "%s: ", "searchFiles");
for (i = 0; i < argc; i++) {
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
/********************** Do not delete this code to avoid debugging. *********************/
/**
* @brief The magic number in the argv variable refers to the SQL statement that creates the form, which is as
* follows:
* CREATE TABLE IF NOT EXISTS files (key INTEGER PRIMARY KEY AUTOINCREMENT, path TEXT, create_time INTEGER,type
* 0 1 2 3
* TEXT, size INTEGER, status TEXT, duration INTEGER);
* 4 5 6
*/
constexpr int TABLE_MEMBER_NUM = 7;
if (TABLE_MEMBER_NUM != argc) {
LogError("Something wrong happened, argc = %d.\n", argc);
return 0;
}
std::vector<SyncFileInfo> *info = (std::vector<SyncFileInfo> *)data;
const unsigned long serialNumber = std::stoul(argv[0]);
const std::string fileName = argv[1];
const unsigned int fileSize = std::stoi(argv[4]);
const unsigned int fileDuration = std::stoi(argv[6]);
const time_t createTime_s = std::stol(argv[2]);
const std::string typeString(argv[3]);
const FileCreateType type = SqliteHandle::ConvertStringToFileType(typeString);
const std::string statusString(argv[5]);
const FileStatus status = SqliteHandle::ConvertStringToFileStatus(statusString);
SyncFileInfo fileInfo(serialNumber, fileName, fileSize, fileDuration, createTime_s, type, status);
(*info).push_back(fileInfo);
return 0;
};
char *errMsg = nullptr;
int rc = SQLITE_UNDEFINE;
rc = sqlite3_exec(db, sql.c_str(), dbCallback, &info, &errMsg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
return false;
}
return true;
}
std::string SqliteHandle::ConvertFileTypeToString(const FileCreateType &type)
{
switch (type) {
case FileCreateType::PIR:
return FIEL_TYPE_PIR;
case FileCreateType::MANUAL_TEST:
return FIEL_TYPE_MANUAL_TEST;
case FileCreateType::MANUAL_PHONE:
return FIEL_TYPE_MANUAL_PHONE;
case FileCreateType::TIMED:
return FIEL_TYPE_TIMED;
case FileCreateType::END:
default:
return FILE_TYPE_UNDEFINE;
}
}
FileCreateType SqliteHandle::ConvertStringToFileType(const std::string &type)
{
std::map<std::string, FileCreateType> fileTypeMap;
fileTypeMap[FIEL_TYPE_PIR] = FileCreateType::PIR;
fileTypeMap[FIEL_TYPE_MANUAL_TEST] = FileCreateType::MANUAL_TEST;
fileTypeMap[FIEL_TYPE_MANUAL_PHONE] = FileCreateType::MANUAL_PHONE;
fileTypeMap[FIEL_TYPE_TIMED] = FileCreateType::TIMED;
fileTypeMap[FILE_TYPE_UNDEFINE] = FileCreateType::END;
auto it = fileTypeMap.find(type);
if (it != fileTypeMap.end()) {
return it->second;
}
return FileCreateType::END;
}
bool SqliteHandle::UpdateFileStatus(sqlite3 *db, const unsigned long &key, const FileStatus &status)
{
if (nullptr == db) {
LogError("db is null.\n");
return false;
}
char *errMsg = nullptr;
int rc = SQLITE_UNDEFINE;
if (FileStatus::END != status) {
std::stringstream sqlStream;
sqlStream << "UPDATE " FILES_TABLE " SET " FILE_STATUS " = '" << ConvertFileStatusToString(status)
<< "' WHERE " TABLE_KEY " = " << key << ";";
LogInfo("Sql: %s\n", sqlStream.str().c_str());
rc = sqlite3_exec(db, sqlStream.str().c_str(), nullptr, nullptr, &errMsg);
if (SQLITE_OK != rc) {
LogError("SQL error: %s\n", errMsg);
sqlite3_free(errMsg);
return false;
}
}
return true;
}
std::string SqliteHandle::ConvertFileStatusToString(const FileStatus &status)
{
switch (status) {
case FileStatus::RECORDING:
return "RECORDING";
case FileStatus::FINISHED_RECORD:
return "FINISHED_RECORD";
case FileStatus::SHOULD_BE_UPLOAD:
return "SHOULD_BE_UPLOAD";
case FileStatus::UPLOADING:
return "UPLOADING";
case FileStatus::UPLOADED:
return "UPLOADED";
case FileStatus::END:
default:
return "undefine";
}
}
FileStatus SqliteHandle::ConvertStringToFileStatus(const std::string &status)
{
std::map<std::string, FileStatus> fileStatusMap;
fileStatusMap[FILE_STATUS_BE_RECORDING] = FileStatus::RECORDING;
fileStatusMap[FILE_STATUS_COMPLETE_RECORD] = FileStatus::FINISHED_RECORD;
fileStatusMap[FILE_STATUS_SHOULD_BE_UPLOADED] = FileStatus::SHOULD_BE_UPLOAD;
fileStatusMap[FILE_STATUS_UPLOADING] = FileStatus::UPLOADING;
fileStatusMap[FILE_STATUS_UPLOADED] = FileStatus::UPLOADED;
auto it = fileStatusMap.find(status);
if (it != fileStatusMap.end()) {
return it->second;
}
return FileStatus::END;
}