448 lines
16 KiB
C++
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;
|
|
} |