Add support for database wipe on exit, including delayed deletion handling and user-triggered wipe option in GUI. Update DatabaseManager with sentinel logic and file path utilities.
This commit is contained in:
parent
709c7d0490
commit
992073d43d
@ -33,6 +33,30 @@ DatabaseManager &DatabaseManager::instance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
QString DatabaseManager::dbFilePath() {
|
||||
const QSettings settings("config.ini", QSettings::IniFormat);
|
||||
QString dbPath = settings.value("db/dbPath").toString();
|
||||
if (dbPath.startsWith("~")) {
|
||||
dbPath.replace(0, 1, QDir::homePath());
|
||||
}
|
||||
return dbPath;
|
||||
}
|
||||
|
||||
void DatabaseManager::wipeDatabaseFiles() {
|
||||
const QString dbPath = dbFilePath();
|
||||
QFile::remove(dbPath);
|
||||
QFile::remove(dbPath + "-wal");
|
||||
QFile::remove(dbPath + "-shm");
|
||||
QFile::remove(dbPath + ".wipe");
|
||||
}
|
||||
|
||||
void DatabaseManager::writeWipeSentinel() {
|
||||
QFile marker(dbFilePath() + ".wipe");
|
||||
if (marker.open(QIODevice::WriteOnly)) {
|
||||
marker.close();
|
||||
}
|
||||
}
|
||||
|
||||
QSqlDatabase DatabaseManager::database() {
|
||||
QMutexLocker<QRecursiveMutex> locker(&mutex);
|
||||
QString name = connectionName();
|
||||
@ -40,12 +64,8 @@ QSqlDatabase DatabaseManager::database() {
|
||||
// Создаем новое соединение, если его ещё нет
|
||||
if (!connectionPool.contains(name)) {
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", name);
|
||||
const QSettings settings("config.ini", QSettings::IniFormat);
|
||||
|
||||
QString dbPath = settings.value("db/dbPath").toString();
|
||||
if (dbPath.startsWith("~")) {
|
||||
dbPath.replace(0, 1, QDir::homePath());
|
||||
}
|
||||
const QString dbPath = dbFilePath();
|
||||
|
||||
// Создаём директорию для БД, если её нет
|
||||
QDir().mkpath(QFileInfo(dbPath).absolutePath());
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <QMap>
|
||||
#include <QMutex>
|
||||
#include <QSet>
|
||||
#include <atomic>
|
||||
|
||||
class DatabaseManager {
|
||||
public:
|
||||
@ -15,6 +16,17 @@ public:
|
||||
void cleanupOldData(int days = 5);
|
||||
void closeConnection();
|
||||
|
||||
// Путь к файлу БД из config.ini (с раскрытием ~). Единая точка вычисления.
|
||||
static QString dbFilePath();
|
||||
// Удалить файл БД вместе с WAL/SHM-сайдкарами и sentinel-файлом.
|
||||
static void wipeDatabaseFiles();
|
||||
// Создать sentinel <dbPath>.wipe — отложенное удаление БД при следующем старте.
|
||||
static void writeWipeSentinel();
|
||||
|
||||
// Флаг «удалить БД при выходе», выставляется из GUI-потока.
|
||||
void setWipeOnExit(bool wipe) { m_wipeOnExit.store(wipe); }
|
||||
bool wipeOnExit() const { return m_wipeOnExit.load(); }
|
||||
|
||||
private:
|
||||
DatabaseManager();
|
||||
~DatabaseManager();
|
||||
@ -24,4 +36,5 @@ private:
|
||||
QRecursiveMutex mutex;
|
||||
QSet<QString> activeConnections;
|
||||
QMap<QString, QSqlDatabase> connectionPool;
|
||||
std::atomic<bool> m_wipeOnExit{false};
|
||||
};
|
||||
25
main.cpp
25
main.cpp
@ -350,6 +350,13 @@ int main(int argc, char *argv[]) {
|
||||
QDir().mkpath(QFileInfo(dbPath).absolutePath());
|
||||
}
|
||||
|
||||
// Отложенное удаление БД (если файл был занят при прошлом выходе, напр. на Windows).
|
||||
// Делаем здесь, до открытия любого соединения.
|
||||
if (QFile::exists(DatabaseManager::dbFilePath() + ".wipe")) {
|
||||
DatabaseManager::wipeDatabaseFiles();
|
||||
qInfo() << "[main] Локальная БД удалена по запросу пользователя";
|
||||
}
|
||||
|
||||
// Миграции БД
|
||||
DatabaseManager::instance().initSchema();
|
||||
DatabaseManager::instance().cleanupOldData(30);
|
||||
@ -444,5 +451,21 @@ int main(int argc, char *argv[]) {
|
||||
loader->close();
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
return QApplication::exec();
|
||||
const int rc = QApplication::exec();
|
||||
|
||||
// Пользователь выбрал «Выйти» с удалением БД. Потоки уже остановлены через
|
||||
// aboutToQuit, их соединения сняты. Пробуем удалить файл сразу; если он занят
|
||||
// (Windows: незавершившийся поток) — оставляем sentinel, удалим при старте.
|
||||
if (DatabaseManager::instance().wipeOnExit()) {
|
||||
dbReady.store(false); // прекращаем дозапись логов в БД
|
||||
DatabaseManager::instance().closeConnection();
|
||||
if (QFile::remove(DatabaseManager::dbFilePath())) {
|
||||
DatabaseManager::wipeDatabaseFiles(); // подчистить -wal/-shm/sentinel
|
||||
qInfo() << "[main] Локальная БД удалена при выходе";
|
||||
} else {
|
||||
DatabaseManager::writeWipeSentinel();
|
||||
qInfo() << "[main] Файл БД занят — удаление отложено до следующего старта";
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include "db/DeviceInfo.h"
|
||||
#include "device/DeviceWidget.h"
|
||||
#include "dao/BankProfileDAO.h"
|
||||
#include "DatabaseManager.h"
|
||||
#include "dao/DeviceDAO.h"
|
||||
#include "dao/MaterialDAO.h"
|
||||
#include "dao/SettingsDAO.h"
|
||||
@ -63,11 +64,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
||||
auto *tutorialPageAction = new QAction("Инструкция", this);
|
||||
auto *eventAction = new QAction("События", this);
|
||||
auto *fileLogAction = new QAction("Логи", this);
|
||||
auto *exitAction = new QAction("Выйти", this);
|
||||
menu->addAction(devicesPageAction);
|
||||
// menu->addAction(accountPageAction);
|
||||
menu->addAction(eventAction);
|
||||
menu->addAction(tutorialPageAction);
|
||||
menu->addAction(fileLogAction);
|
||||
menu->addAction(exitAction);
|
||||
|
||||
connect(devicesPageAction, &QAction::triggered, this, [=]() {
|
||||
if (!m_devicesWindow) {
|
||||
@ -114,6 +117,19 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
||||
}
|
||||
});
|
||||
|
||||
connect(exitAction, &QAction::triggered, this, [this]() {
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle("Выход");
|
||||
msgBox.setText("Удалить локальную базу данных и выйти из приложения?");
|
||||
auto *yesBtn = msgBox.addButton("Выйти", QMessageBox::YesRole);
|
||||
msgBox.addButton("Отмена", QMessageBox::NoRole);
|
||||
msgBox.exec();
|
||||
if (msgBox.clickedButton() == yesBtn) {
|
||||
DatabaseManager::instance().setWipeOnExit(true);
|
||||
qApp->quit(); // штатное завершение фоновых потоков (aboutToQuit)
|
||||
}
|
||||
});
|
||||
|
||||
if (SettingsDAO::get("tutorial_shown").isEmpty()) {
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
m_tutorialWindow = new TutorialWindow(this);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user