upload all files

This commit is contained in:
2026-01-07 21:26:28 +08:00
parent 1d35a422ec
commit 6d7544e0a3
17 changed files with 2987 additions and 0 deletions

72
Modules/Logger.cpp Normal file
View File

@@ -0,0 +1,72 @@
#include "Logger.h"
#include "global.h"
#include <iostream>
#include <string>
#include <Windows.h>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <array>
#include <string_view>
#include <mutex>
#include <QDebug> // For Qt logging
structIs is;
std::string colorOut_256(std::string_view s, int ForeColor = 7)
{
std::ostringstream oss;
oss << "\033[38;5;" << ForeColor << "m" << s << "\033[m";
return oss.str();
}
std::string getSystemTime() {
using namespace std::chrono;
const auto now = system_clock::now();
const auto now_time_t = system_clock::to_time_t(now);
const auto ms = duration_cast<milliseconds>(now.time_since_epoch()).count() % 1000;
std::tm ltm{};
localtime_s(&ltm, &now_time_t);
std::ostringstream oss;
oss << std::put_time(&ltm, "%Y-%m-%d %H:%M:%S")
<< '.' << std::setw(3) << std::setfill('0') << ms;
return oss.str();
}
// Logger mutex to ensure whole log lines are emitted atomically
static std::mutex loggerMutex;
void postLog(const std::string& message, int level) {
const auto timeNow = getSystemTime();
constexpr std::array<const char*, 5> levelNames = {"DEBUG", "INFO", "WARNING", "ERROR", "FATAL"};
constexpr std::array<int, 5> levelColors = {34, 27, 220, 196, 124};
const int idx = (level >= 0 && level < static_cast<int>(levelNames.size())) ? level : 1; // default to INFO
// Lock to make reading isDebug and all output atomic across threads
std::scoped_lock lock(loggerMutex);
if (is.debug == false) {
if (idx == 0) return; // skip DEBUG when debug is off
qInfo() << "[" << QString::fromStdString(timeNow) << " - " << QString::fromStdString(levelNames[idx]) << "] " << QString::fromStdString(message);
return;
}
// isDebug == 1 -> colored output
const std::string levelDisplay = colorOut_256(levelNames[idx], levelColors[idx]);
QString levelDisplayQt = QString::fromStdString(levelDisplay);
if (idx == 0) { // DEBUG level
qDebug("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
} else if (idx == 1) { // INFO level
qInfo("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
} else if (idx == 2) { // WARNING level
qWarning("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
} else if (idx == 3) { // ERROR level
qCritical("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
} else if (idx == 4) { // FATAL level
qFatal("[%s - %s] %s", QString::fromStdString(timeNow).toUtf8().data(), levelDisplayQt.toUtf8().data(), QString::fromStdString(message).toUtf8().data());
}
}

9
Modules/Logger.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef LOGGER_H
#define LOGGER_H
#include <string>
std::string getSystemTime();
void postLog(const std::string& message, int level);
#endif

83
Modules/global.h Normal file
View File

@@ -0,0 +1,83 @@
#ifndef GLOBAL_H
#define GLOBAL_H
#include <QDialog>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QCheckBox>
#include <QTextEdit>
#include <QLabel>
#include <QComboBox>
#include <QTableWidget>
// *** dialogLogin ***
struct structCheckBox {
QCheckBox *rememberMe = nullptr;
};
extern structCheckBox checkBox;
struct structComboBox{
QComboBox *findBy = nullptr;
};
extern structComboBox comboBox;
struct structTextEdit {
QTextEdit *username = nullptr;
QTextEdit *passwd = nullptr;
QTextEdit *search = nullptr;
};
extern structTextEdit textEdit;
struct structPushButton {
QPushButton *ok = nullptr;
QPushButton *cancel = nullptr;
QPushButton *seacrh = nullptr;
QPushButton *clear = nullptr;
QPushButton *submit = nullptr;
QPushButton *remove = nullptr;
};
extern structPushButton pushButton;
struct structLabel {
QLabel *connStatus = nullptr;
QLabel *salaryShould = nullptr;
QLabel *salaryDiscount = nullptr;
QLabel *salaryActual = nullptr;
};
extern structLabel label;
struct structTableWidget {
QTableWidget *teacherInfo = nullptr;
QTableWidget *teacherSalary = nullptr;
};
extern structTableWidget tableWidget;
namespace Ui {
class DialogLogin;
}
// *******************
// *** main ***
struct structIs{
bool debug = true;
bool loggedIn = false;
bool connected = false;
};
extern structIs is;
struct structSession{
std::string token;
std::string userName;
std::string userID;
};
extern structSession session;
struct structUserInfo{
std::string userName;
std::string passwd;
};
extern structUserInfo userInfo;
// ************
#endif // GLOBAL_H

960
Modules/inicpp.hpp Normal file
View File

@@ -0,0 +1,960 @@
/*
* MIT License
*
* Copyright (c) 2023 dujingning <djn2019x@163.com> <https://github.com/dujingning/inicpp.git>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __JN_INICPP_H__
#define __JN_INICPP_H__
#include <cstddef>
#include <stdexcept>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <string>
#include <list>
#include <map>
#ifdef _ENBABLE_INICPP_STD_WSTRING_ // Not all of C++ 11 support <codecvt>
// for std::string <==> std::wstring convert
#include <codecvt>
#include <locale>
#endif
#ifdef INICPP_DEBUG
#include <array>
#include <ctime>
#include <iostream>
class TimeFormatter
{
public:
static std::string format(const std::string &format = "%Y-%m-%d %H:%M:%S")
{
std::time_t t = std::time(nullptr);
std::tm tm = *std::localtime(&t);
std::array<char, 100> buffer;
std::strftime(buffer.data(), buffer.size(), format.c_str(), &tm);
return buffer.data();
}
};
#define CODE_INFO std::string(" \t``````|") + std::string(__FILE__) + ":" + std::to_string(__LINE__) + " fun:" + std::string(__FUNCTION__)
#define INI_DEBUG(x) std::cout << "INICPP " << TimeFormatter::format() << " : " << x << CODE_INFO << std::endl
#else // #ifdef INICPP_DEBUG
#define INI_DEBUG(x)
#endif // #ifdef INICPP_DEBUG
namespace inicpp
{
typedef struct ValueNode
{
std::string Value = "";
int lineNumber = -1; // text line start with 1
} ValueNode;
class parentHelper
{
public:
virtual parentHelper *parent()
{
INI_DEBUG("called parentHelper virtual impl: need to impl parent");
return nullptr;
}
virtual void setParent(parentHelper *parent)
{
INI_DEBUG("called parentHelper virtual impl: need to impl setParent");
}
virtual bool set(const std::string &Section, const std::string &Key, const std::string &Value, const std::string &comment = "")
{
INI_DEBUG("called parentHelper virtual impl: need to impl set");
return true;
}
};
class ValueProxy
{
public:
ValueProxy(std::string &value) : _value(value) {}
~ValueProxy() {}
template <typename T>
ValueProxy(const T &value) : _value(to_string(value)) {}
template <typename T>
static std::string to_string(const T &value)
{
std::ostringstream oss;
oss << value;
return oss.str();
}
template <typename T>
T get() const
{
static_assert(!std::is_pointer<T>::value, "Pointer types are not supported for conversion.");
std::istringstream iss(_value);
T result;
if (!(iss >> result))
{
throw std::runtime_error("Type mismatch or invalid conversion. with(section-key-value): " +_sectionName +"-"+ _keyName +"-"+ _value); // error notify
}
return result;
}
operator char() const { return this->get<char>(); }
operator short() const { return this->get<short>(); }
operator int() const { return this->get<int>(); }
operator long() const { return this->get<long>(); }
operator long long() const { return this->get<long long>(); }
operator float() const { return this->get<float>(); }
operator double() const { return this->get<double>(); }
operator unsigned char() const { return this->get<unsigned char>(); }
operator unsigned short() const { return this->get<unsigned short>(); }
operator unsigned int() const { return this->get<unsigned int>(); }
operator unsigned long() const { return this->get<unsigned long>(); }
operator unsigned long long() const { return this->get<unsigned long long>(); }
// false:'0' or 'false', true : others
operator bool() const
{
if (_value == "0" || _value == "false" || _value == "no")
{
return false;
}
return true;
}
operator std::string() const
{
return _value;
}
friend std::ostream &operator<<(std::ostream &os, const ValueProxy &proxy)
{
os << proxy._value;
return os;
}
// assignment
template <typename T>
ValueProxy &operator=(const T &other)
{
std::string value = this->to_string(other);
if (_value != value)
{
set(value);
}
_value = value;
return *this;
}
ValueProxy &operator=(const std::string &other)
{
if (_value != other)
{
INI_DEBUG("Value Proxy Wanna Set Value: " << other);
set(other);
}
_value = other;
return *this;
}
// specify std::string
const std::string &String() noexcept
{
return _value;
}
inline void setWriteCB(parentHelper *sectionObj, const std::string &sectionName, const std::string &keyName)
{
_section = sectionObj;
_sectionName = sectionName;
_keyName = keyName;
}
private:
void set(const std::string &value)
{
if (value.empty() || _keyName.empty())
{
return;
}
if (_section && _section->parent() && _section->parent()->parent())
{
_section->parent()->parent()->set(_sectionName, _keyName, value);
}
}
private:
std::string &_value;
std::string _sectionName, _keyName;
parentHelper *_section = nullptr;
};
} // namespace inicpp
namespace inicpp
{
class section : parentHelper
{
public:
section() : _sectionName()
{
}
explicit section(const std::string &sectionName) : _sectionName(sectionName)
{
}
const std::string &name()
{
return _sectionName;
}
const std::string getValue(const std::string &Key)
{
if (!_sectionMap.count(Key))
{
return "";
}
return _sectionMap[Key].Value;
}
void setName(const std::string &name, const int &lineNumber)
{
_sectionName = name;
_lineNumber = lineNumber;
}
void setValue(const std::string &Key, const std::string &Value, const int line)
{
_sectionMap[Key].Value = Value;
_sectionMap[Key].lineNumber = line;
}
void append(section &sec)
{
_sectionMap.insert(sec._sectionMap.begin(), sec._sectionMap.end());
}
bool isKeyExist(const std::string &Key)
{
return !_sectionMap.count(Key) ? false : true;
}
int getEndSection()
{
int line = -1;
if (_sectionMap.empty() && _sectionName != "")
{
return _lineNumber;
}
for (const auto &data : _sectionMap)
{
if (data.second.lineNumber > line)
{
line = data.second.lineNumber;
}
}
return line;
}
int getLine(const std::string &Key)
{
if (!_sectionMap.count(Key))
{
return -1;
}
return _sectionMap[Key].lineNumber;
}
void clear()
{
_lineNumber = -1;
_sectionName.clear();
_sectionMap.clear();
}
bool isEmpty() const
{
return _sectionMap.empty();
}
int toInt(const std::string &Key) noexcept
{
if (!_sectionMap.count(Key))
{
return 0;
}
int result = 0;
try
{
result = std::stoi(_sectionMap[Key].Value);
}
catch (const std::invalid_argument &e)
{
INI_DEBUG("Invalid argument: " << e.what() << ",input:\'" << _sectionMap[Key].Value << "\'");
}
catch (const std::out_of_range &e)
{
INI_DEBUG("Out of range: " << e.what() << ",input:\'" << _sectionMap[Key].Value << "\'");
}
return result;
}
std::string toString(const std::string &Key) noexcept
{
if (!_sectionMap.count(Key))
{
return "";
}
return _sectionMap[Key].Value;
}
#ifdef _ENBABLE_INICPP_STD_WSTRING_
std::wstring toWString(const std::string &Key)
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.from_bytes(toString(Key));
}
#endif
double toDouble(const std::string &Key) noexcept
{
if (!_sectionMap.count(Key))
{
return 0.0;
}
double result = 0.0;
try
{
result = std::stod(_sectionMap[Key].Value);
}
catch (const std::invalid_argument &e)
{
INI_DEBUG("Invalid argument: " << e.what() << ",input:\'" << _sectionMap[Key].Value << "\'");
}
catch (const std::out_of_range &e)
{
INI_DEBUG("Out of range: " << e.what() << ",input:\'" << _sectionMap[Key].Value << "\'");
}
return result;
}
std::map<std::string /*Key*/, std::string /*Value*/> getSectionMap()
{
std::map<std::string /*Key*/, std::string /*Value*/> sectionKVMap;
for (auto &iter : _sectionMap)
{
sectionKVMap[iter.first] = iter.second.Value;
}
return sectionKVMap;
}
// Automatically converts to any type; throws std::runtime_error if not found or conversion fails
ValueProxy operator[](const std::string &Key)
{
ValueProxy vp(_sectionMap[Key].Value);
vp.setWriteCB(this, _sectionName, Key);
return vp;
}
inline parentHelper *parent() override { return _parent; };
inline void setParent(parentHelper *parent) override { _parent = parent; };
private:
std::string _sectionName;
std::map<std::string /*Key*/, ValueNode> _sectionMap;
int _lineNumber = -1; // text line start with 1
parentHelper *_parent = nullptr;
};
class ini : parentHelper
{
public:
void addSection(section &sec)
{
if (_iniInfoMap.count(sec.name())) // if exist,need to merge
{
_iniInfoMap[sec.name()].append(sec);
return;
}
_iniInfoMap.emplace(sec.name(), sec);
return;
}
void removeSection(const std::string &sectionName)
{
if (!_iniInfoMap.count(sectionName))
{
return;
}
_iniInfoMap.erase(sectionName);
return;
}
bool isSectionExists(const std::string &sectionName)
{
return !_iniInfoMap.count(sectionName) ? false : true;
}
// may contains default of Unnamed section with ""
std::list<std::string> getSectionsList()
{
std::list<std::string> sectionList;
for (const auto &data : _iniInfoMap)
{
if (data.first == "" && data.second.isEmpty()) // default section: no section name,if empty,not count it.
{
continue;
}
sectionList.emplace_back(data.first);
}
return sectionList;
}
std::map<std::string /*key*/, std::string /*value*/> getSectionMap(const std::string &sectionName)
{
std::map<std::string /*key*/, std::string /*value*/> kvMap;
if (_iniInfoMap.count(sectionName) == 0)
{
return kvMap;
}
return _iniInfoMap[sectionName].getSectionMap();
}
const section &operator[](const std::string &sectionName)
{
_iniInfoMap[sectionName].setParent(this);
if (_iniInfoMap[sectionName].name().empty())
{
_iniInfoMap[sectionName].setName(sectionName, -1);
}
return _iniInfoMap[sectionName];
}
inline std::size_t getSectionSize()
{
return _iniInfoMap.size();
}
std::string getValue(const std::string &sectionName, const std::string &Key)
{
if (!_iniInfoMap.count(sectionName))
{
return "";
}
return _iniInfoMap[sectionName][Key];
}
// for none section
int getLine(const std::string &Key)
{
if (!_iniInfoMap.count(""))
{
return -1;
}
return _iniInfoMap[""].getLine(Key);
}
// for section-key
int getLine(const std::string &sectionName, const std::string &Key)
{
if (!_iniInfoMap.count(sectionName))
{
return -1;
}
return _iniInfoMap[sectionName].getLine(Key);
}
inline void clear() { _iniInfoMap.clear(); }
inline bool empty() { return _iniInfoMap.empty(); }
parentHelper *parent() override { return _parent; }
void setParent(parentHelper *parent) override { _parent = parent; }
protected:
std::map<std::string /*Section Name*/, section> _iniInfoMap;
private:
parentHelper *_parent = nullptr;
};
class IniManager : parentHelper
{
public:
#ifdef _ENBABLE_INICPP_STD_WSTRING_
explicit IniManager(const std::wstring &configFileName = L"")
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string stringValue = converter.to_bytes(configFileName);
_configFileName = stringValue;
_iniData.setParent(this);
parse();
}
#else
explicit IniManager(const std::string &configFileName = "") : _configFileName(configFileName)
{
_iniData.setParent(this);
parse();
}
#endif
~IniManager()
{
_iniFile.close();
}
section operator[](const std::string &sectionName)
{
return _iniData[sectionName];
}
void parse()
{
if (_configFileName.empty())
{
return;
}
if (!_iniFile.is_open())
{
_iniFile.clear();
_iniFile.open(_configFileName, std::ifstream::in | std::ifstream::out | std::fstream::app);
}
if (!_iniFile.is_open())
{
INI_DEBUG("Failed to open(WR),try to open with readonly(R).");
_iniFile.clear();
_iniFile.open(_configFileName, std::ifstream::in);
}
if (!_iniFile.is_open())
{
INI_DEBUG("Failed to open the input INI file for parsing! file:" << _configFileName);
return;
}
_iniData.clear();
_iniFile.seekg(0, _iniFile.beg);
std::string data, sectionName;
int sectionLine = -1;
section sectionRecord;
_SumOfLines = 1;
do
{
std::getline(_iniFile, data);
if (!filterData(data))
{
++_SumOfLines;
continue;
}
if (data.find('[') == 0) // section
{
if (!sectionRecord.isEmpty() || sectionRecord.name() != "")
{
_iniData.addSection(sectionRecord);
}
size_t first = data.find('[');
size_t last = data.find(']');
if (last == std::string::npos)
{
++_SumOfLines;
continue;
}
sectionName = data.substr(first + 1, last - first - 1);
sectionLine = _SumOfLines;
sectionRecord.clear();
sectionRecord.setName(sectionName, sectionLine);
}
size_t pos = data.find('=');
if (pos != std::string::npos)
{ // k=v
std::string key = data.substr(0, pos);
std::string value = data.substr(pos + 1);
trimEdges(key);
trimEdges(value);
sectionRecord.setValue(key, value, _SumOfLines);
}
++_SumOfLines;
} while (!_iniFile.eof());
if (!sectionRecord.isEmpty())
{
sectionRecord.setName(sectionName, -1);
_iniData.addSection(sectionRecord);
}
if (_iniFile.is_open())
{
_iniFile.close();
}
}
bool set(const std::string &Section, const std::string &Key, const std::string &Value, const std::string &comment = "") override
{
parse();
std::string key = Key, value = Value;
trimEdges(key);
trimEdges(key);
if (key == "" || value == "")
{
INI_DEBUG("Invalid parameter input: key[" << key << "],value[" << value << "]");
return false;
}
std::string keyValueData = key + "=" + value + "\n";
if (comment.length() > 0)
{
keyValueData = comment + "\n" + keyValueData;
if (comment[0] != ';')
{
keyValueData = ";" + keyValueData;
}
}
const std::string &tempFile = ".temp.ini";
std::fstream input(_configFileName, std::ifstream::in);
std::ofstream output(tempFile);
if (!input.is_open())
{
INI_DEBUG("Failed to open the input INI file for modification! File name:" << _configFileName);
return false;
}
if (!output.is_open())
{
INI_DEBUG("Failed to open the output INI file for modification!");
return false;
}
int line_number_mark = -1;
bool isInputDataWited = false;
do
{
// exist key at one section replace it, or need to create it
if (_iniData.isSectionExists(Section))
{
line_number_mark = (*this)[Section].getLine(key);
if (line_number_mark == -1)
{ // section exist, key not exist
line_number_mark = (*this)[Section].getEndSection();
std::string lineData;
int input_line_number = 0;
while (std::getline(input, lineData))
{
++input_line_number;
if (input_line_number == (line_number_mark + 1))
{ // new line,append to next line
isInputDataWited = true;
output << keyValueData;
}
output << lineData << "\n";
}
if (input.eof() && !isInputDataWited)
{
isInputDataWited = true;
output << keyValueData;
}
break;
}
}
if (line_number_mark <= 0) // not found key at config file
{
input.seekg(0, input.beg);
bool isHoldSection = false;
std::string newLine = "\n\n";
if (Section != "" && Section.find("[") == std::string::npos && Section.find("]") == std::string::npos && Section.find("=") == std::string::npos)
{
if (_iniData.empty() || _iniData.getSectionSize() <= 0)
{
newLine.clear();
}
isHoldSection = true;
}
// 1.section is exist or empty section
if (_iniData.isSectionExists(Section) || Section == "")
{
// write key/value to head
if (isHoldSection)
{
output << newLine << "[" << Section << "]" << "\n";
}
output << keyValueData;
// write others
std::string lineData;
while (std::getline(input, lineData))
{
output << lineData << "\n";
}
}
// 2.section is not exist
else
{
// write others
std::string lineData;
while (std::getline(input, lineData))
{
output << lineData << "\n";
}
// write key/value to end
if (isHoldSection)
{
output << newLine << "[" << Section << "]" << "\n";
}
output << keyValueData;
}
break;
}
else
{ // found, replace it
std::string lineData;
int input_line_number = 0;
while (std::getline(input, lineData))
{
++input_line_number;
// delete old comment if new comment is set
if (input_line_number == (line_number_mark - 1) && lineData.length() > 0 && lineData[0] == ';' && comment != "")
{
continue;
}
if (input_line_number == line_number_mark)
{ // replace to this line
output << keyValueData;
}
else
{
output << lineData << "\n";
}
}
break;
}
INI_DEBUG("error! inicpp lost process of set function");
return false;
} while (false);
// clear work
input.close();
output.close();
std::remove(_configFileName.c_str());
std::rename(tempFile.c_str(), _configFileName.c_str());
// reload
parse();
return true;
}
bool set(const std::string &Section, const std::string &Key, const int Value, const std::string &comment = "")
{
std::string stringValue = std::to_string(Value);
return set(Section, Key, stringValue, comment);
}
bool set(const std::string &Section, const std::string &Key, const double &Value, const std::string &comment = "")
{
std::string stringValue = std::to_string(Value);
return set(Section, Key, stringValue, comment);
}
bool set(const std::string &Section, const std::string &Key, const char &Value, const std::string &comment = "")
{
std::string stringValue = ValueProxy::to_string(Value);
return set(Section, Key, stringValue, comment);
}
// no sections: head of config file
bool set(const std::string &Key, const std::string &Value)
{
return set("", Key, Value, "");
}
bool set(const std::string &Key, const char *Value)
{
return set("", Key, Value, "");
}
template <typename T>
bool set(const std::string &Key, const T &Value)
{
std::string stringValue = std::to_string(Value);
return set("", Key, stringValue, "");
}
#ifdef _ENBABLE_INICPP_STD_WSTRING_
bool set(const std::string &Section, const std::string &Key, const std::wstring &Value, const std::string &comment = "")
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string stringValue = converter.to_bytes(Value);
return set(Section, Key, stringValue, comment);
}
#endif
// comment for section name of key
bool setComment(const std::string &Section, const std::string &Key, const std::string &comment)
{
return set(Section, Key, (*this)[Section].toString(Key), comment);
}
// comment for no section name of key
bool setComment(const std::string &Key, const std::string &comment)
{
return set("", Key, (*this)[""].toString(Key), comment);
}
bool isSectionExists(const std::string &sectionName)
{
return _iniData.isSectionExists(sectionName);
}
inline std::list<std::string /*section name*/> sectionsList()
{
return _iniData.getSectionsList();
}
inline std::map<std::string /*key*/, std::string /*value*/> sectionMap(const std::string &sectionName)
{
return _iniData.getSectionMap(sectionName);
}
#ifdef _ENBABLE_INICPP_STD_WSTRING_
void setFileName(const std::wstring &fileName)
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string name = converter.to_bytes(fileName);
_configFileName = name;
}
#else
void setFileName(const std::string &fileName)
{
_configFileName = fileName;
}
#endif
private:
bool filterData(std::string &data)
{
if (data.length() == 0)
{
return false;
}
if (data[0] == ';')
{
return false;
}
if (data[0] == '#')
{
return false;
}
return true;
}
void trimEdges(std::string &data)
{
// remove left ' ' and '\t'
data.erase(data.begin(), std::find_if(data.begin(), data.end(), [](unsigned char c)
{ return !std::isspace(c); }));
// remove right ' ' and '\t'
data.erase(std::find_if(data.rbegin(), data.rend(), [](unsigned char c)
{ return !std::isspace(c); })
.base(),
data.end());
// INI_DEBUG("trimEdges data:|" << data << "|");
}
private:
ini _iniData;
int _SumOfLines;
std::fstream _iniFile;
std::string _configFileName;
};
} // namespace inicpp
#endif

33
Modules/methods.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "methods.h"
#include <ctime>
#include <iostream>
methods::methods() {}
using inicpp::ini;
using inicpp::IniManager;
using std::string;
int getUnixTimestamp() { // 获取当前Unix时间戳
return static_cast<int>(time(nullptr));
}
string getTextMiddle(string source, string left, string right) {
size_t leftPos = source.find(left);
if (leftPos == string::npos) return "";
leftPos += left.length();
size_t rightPos = source.find(right, leftPos);
if (rightPos == string::npos) return "";
return source.substr(leftPos, rightPos - leftPos);
}
string getKeyText(string iniFilePath, string mainLevel, string subLevel) {
IniManager _ini(iniFilePath); // Load and parse the INI file
string returnValue = _ini[mainLevel][subLevel];
return (returnValue);
}
void setKeyText(string iniFilePath, string mainLevel, string subLevel, string value) {
IniManager _ini(iniFilePath); // Load and parse the INI file
_ini.set(mainLevel, subLevel, value);
}

19
Modules/methods.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef METHODS_H
#define METHODS_H
#include <iostream>
#include "Modules/inicpp.hpp"
using std::string;
class methods
{
public:
methods();
};
int getUnixTimestamp();
string getTextMiddle(string source, string left, string right); // Get a middle text from a string
string getKeyText(string iniFilePath, string mainLevel, string subLevel); // Get key value from INI file
void setKeyText(string iniFilePath, string mainLevel, string subLevel, string value); // Set key value to INI file
#endif // METHODS_H

348
Modules/socketactions.cpp Normal file
View File

@@ -0,0 +1,348 @@
#include "socketactions.h"
#include "Logger.h"
#include <QCoreApplication>
#include <QNetworkInterface>
#include <QEventLoop>
#include <QMutexLocker>
#include <QAbstractSocket>
#include <QDateTime>
#include <string>
namespace sockAct {
struct SocketContext {
std::unique_ptr<QTcpSocket> socket;
QMutex sendMutex;
QMutex connectMutex;
bool isInitialized = false;
std::string lastError;
QHostAddress lastConnectedHost;
quint16 lastConnectedPort = 0;
qint64 lastSendTime = 0;
qint64 lastReceiveTime = 0;
int sendCount = 0;
int receiveCount = 0;
};
static SocketContext& context() { // Static context
static SocketContext ctx;
return ctx;
}
namespace {
bool ensureInitialized();
bool internalConnectToHost(const std::string& host, quint16 port, int timeoutMs);
std::string waitForResponse(int timeoutMs);
void logNetworkEvent(const std::string& message, LogLevel level);
void handleSocketError(QAbstractSocket::SocketError error);
void resetSocket();
QString toQString(const std::string& str);
std::string fromQString(const QString& str);
// Add UTF-8 encoding helper functions
QByteArray stringToUtf8Bytes(const std::string& str);
std::string bytesToUtf8String(const QByteArray& bytes);
}
bool sockInit() {
QMutexLocker locker(&context().connectMutex);
if (context().isInitialized) {
logNetworkEvent("[Socket] Initialization completed.", INFO);
return true;
}
if (!QNetworkInterface::allInterfaces().isEmpty()) { // Check Qt Network Module
logNetworkEvent("[Socket] Qt Networking module initializing completed.", INFO);
} else {
logNetworkEvent("[Socket] No avaliable network interfaces", WARNING);
}
context().isInitialized = true;
logNetworkEvent("[Socket] Initialization completed.", INFO);
return true;
}
bool connectToHost(const std::string& host, quint16 port, int timeoutMs) {
if (!ensureInitialized()) {
return false;
}
QMutexLocker locker(&context().connectMutex);
QString qhost = toQString(host);
if (context().socket &&
context().lastConnectedHost.toString() == qhost &&
context().lastConnectedPort == port) {
if (context().socket->state() == QAbstractSocket::ConnectedState) {
logNetworkEvent(std::string("[Socket] Connected to server: ") + host + ":" + std::to_string(port), INFO);
return true;
}
}
return internalConnectToHost(host, port, timeoutMs);
}
std::string tcpSend(const std::string& data, int timeoutMs) {
if (!ensureInitialized()) {
return std::string();
}
QMutexLocker locker(&context().sendMutex);
if (!context().socket || context().socket->state() != QAbstractSocket::ConnectedState) {
logNetworkEvent("[Socket] No connection avaliable, cannot send any data.", ERROR);
return std::string();
}
// Convert string to UTF-8 bytes for transmission
QByteArray sendData = stringToUtf8Bytes(data);
qint64 bytesWritten = context().socket->write(sendData); // Send data
context().lastSendTime = QDateTime::currentMSecsSinceEpoch();
context().sendCount++;
if (bytesWritten == -1) {
QString errorStr = context().socket->errorString();
logNetworkEvent("[Socket] Failed to send data: " + fromQString(errorStr), ERROR);
return std::string();
}
if (bytesWritten != sendData.size()) {
logNetworkEvent("[Socket] Data send not complete, expected to send " + std::to_string(sendData.size()) +
" bytes, " + std::to_string(bytesWritten) + " bytes sent", WARNING);
}
logNetworkEvent("[Socket] " + std::to_string(bytesWritten) + " bytes has been sent to sevrer", DEBUG);
std::string response = waitForResponse(timeoutMs);
return response;
}
void clearSocket() {
QMutexLocker locker1(&context().connectMutex);
QMutexLocker locker2(&context().sendMutex);
if (context().socket) {
std::string serverInfo;
if (!context().lastConnectedHost.isNull()) {
serverInfo = fromQString(context().lastConnectedHost.toString()) + ":" +
std::to_string(context().lastConnectedPort);
}
logNetworkEvent("[Socket] Disconnecting from server " + serverInfo + "...", INFO);
if (context().socket->state() != QAbstractSocket::UnconnectedState) {
context().socket->abort();
}
context().socket->disconnect();
// Reset connection info
context().lastConnectedHost.clear();
context().lastConnectedPort = 0;
context().lastSendTime = 0;
context().lastReceiveTime = 0;
context().sendCount = 0;
context().receiveCount = 0;
logNetworkEvent("[Socket] Disconnected.", INFO);
}
}
bool isConnected() {
if (!context().socket) {
return false;
}
return context().socket->state() == QAbstractSocket::ConnectedState;
}
std::string getLastError() {
return context().lastError;
}
// ==================== Internal methods ====================
namespace {
QString toQString(const std::string& str) {
return QString::fromStdString(str);
}
std::string fromQString(const QString& str) {
return str.toStdString();
}
// Convert string to UTF-8 bytes
QByteArray stringToUtf8Bytes(const std::string& str) {
// Use QString to convert to UTF-8
QString qstr = QString::fromStdString(str);
return qstr.toUtf8();
}
// Convert UTF-8 bytes to string
std::string bytesToUtf8String(const QByteArray& bytes) {
// Convert from UTF-8 bytes to QString, then to std::string
QString qstr = QString::fromUtf8(bytes);
return qstr.toStdString();
}
bool ensureInitialized() {
if (!context().isInitialized) {
logNetworkEvent("[Socket] Not initialized.", ERROR);
return false;
}
return true;
}
bool internalConnectToHost(const std::string& host, quint16 port, int timeoutMs) {
if (context().socket) {
context().socket->abort();
context().socket.reset();
}
context().socket.reset(new QTcpSocket());
QString qhost = toQString(host);
QObject::connect(context().socket.get(), &QTcpSocket::connected, [host, port]() {
logNetworkEvent("[Socket] Connected to server " + host + ":" + std::to_string(port), INFO);
});
QObject::connect(context().socket.get(), QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred),
[](QAbstractSocket::SocketError error) {
handleSocketError(error);
});
logNetworkEvent("[Socket] Connecting to server " + host + ":" + std::to_string(port) +
" (Timeout: " + std::to_string(timeoutMs) + "ms)...", INFO);
context().socket->connectToHost(qhost, port);
QElapsedTimer timer;
timer.start();
while (context().socket->state() == QAbstractSocket::ConnectingState) {
if (timer.elapsed() > timeoutMs) {
logNetworkEvent("[Socket] Connection to server " + host + ":" + std::to_string(port) + " timeout", WARNING);
context().socket->abort();
return false;
}
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
QThread::msleep(10);
}
if (context().socket->state() != QAbstractSocket::ConnectedState) {
QString errorStr = context().socket->errorString();
logNetworkEvent("[Sockct] Failed to connect to server " + host + ":" + std::to_string(port) +
" Reason: " + fromQString(errorStr), ERROR);
return false;
}
context().lastConnectedHost = context().socket->peerAddress();
context().lastConnectedPort = context().socket->peerPort();
return true;
}
std::string waitForResponse(int timeoutMs) {
if (!context().socket) {
return std::string();
}
QElapsedTimer timer;
timer.start();
while (context().socket->bytesAvailable() == 0) {
if (timer.elapsed() > timeoutMs) {
logNetworkEvent("[Socket] Timeout when waiting for reply (" + std::to_string(timeoutMs) + "ms)", WARNING);
return std::string();
}
if (!context().socket->waitForReadyRead(100)) {
if (context().socket->state() != QAbstractSocket::ConnectedState) {
logNetworkEvent("[Socket] Connection lost.", ERROR);
return std::string();
}
}
}
QByteArray responseData = context().socket->readAll();
context().lastReceiveTime = QDateTime::currentMSecsSinceEpoch();
context().receiveCount++;
// Convert UTF-8 bytes to string
std::string response = bytesToUtf8String(responseData);
int waitTime = timer.elapsed();
logNetworkEvent("[Socket] Reply from server " + std::to_string(responseData.size()) +
" bytes, Time: " + std::to_string(waitTime) + "ms", DEBUG);
return response;
}
void logNetworkEvent(const std::string& message, LogLevel level) {
postLog(message, static_cast<int>(level));
}
void handleSocketError(QAbstractSocket::SocketError error) {
std::string errorMsg;
LogLevel level = ERROR;
switch (error) {
case QAbstractSocket::ConnectionRefusedError:
errorMsg = "[Socket] Connection refused.";
break;
case QAbstractSocket::RemoteHostClosedError:
errorMsg = "[Socket] Remote server closed connection.";
level = WARNING;
break;
case QAbstractSocket::HostNotFoundError:
errorMsg = "[Socket] No host found.";
break;
case QAbstractSocket::SocketAccessError:
errorMsg = "[Socket] Access error.";
break;
case QAbstractSocket::SocketResourceError:
errorMsg = "[Socket] Resource error.";
level = WARNING;
break;
case QAbstractSocket::SocketTimeoutError:
errorMsg = "[Socket] Timeout.";
level = WARNING;
break;
case QAbstractSocket::NetworkError:
errorMsg = "[Socket] Network fatal.";
level = FATAL;
break;
case QAbstractSocket::SslHandshakeFailedError:
errorMsg = "[Socket] TLS handshake error.";
break;
default:
errorMsg = "[Socket] Unknown error.";
break;
}
if (context().socket) {
QString errorStr = context().socket->errorString();
errorMsg += ": " + fromQString(errorStr);
}
logNetworkEvent(errorMsg, level);
context().lastError = errorMsg;
}
void resetSocket() {
if (context().socket) {
context().socket->disconnect();
context().socket.reset();
}
context().lastError.clear();
}
}
} // namespace sockAct

76
Modules/socketactions.h Normal file
View File

@@ -0,0 +1,76 @@
#ifndef SOCKETACTIONS_H
#define SOCKETACTIONS_H
#include <QObject>
#include <QTcpSocket>
#include <QTimer>
#include <QMutex>
#include <QWaitCondition>
#include <QElapsedTimer>
#include <QThread>
#include <QDateTime>
#include <QHostAddress>
#include <memory>
#include <string>
namespace sockAct {
// 日志级别枚举与Logger.h保持一致
enum LogLevel {
DEBUG = 0,
INFO = 1,
WARNING = 2,
ERROR = 3,
FATAL = 4
};
/**
* @brief 初始化Socket模块
*
* 初始化Qt网络模块必须在使用其他socket函数前调用
* @return 初始化是否成功
*/
bool sockInit();
/**
* @brief 连接到TCP服务器
*
* @param host 服务器地址
* @param port 服务器端口
* @param timeoutMs 连接超时时间(毫秒)
* @return 连接是否成功
*/
bool connectToHost(const std::string& host, quint16 port, int timeoutMs = 3000);
/**
* @brief 发送TCP数据并接收响应
*
* 发送数据到已连接的服务器并等待最多3秒接收响应
* 一旦收到数据立即返回否则等待3秒后返回空字符串
*
* @param data 要发送的数据
* @param timeoutMs 接收超时时间(毫秒)
* @return 接收到的数据,如果超时或出错则返回空字符串
*/
std::string tcpSend(const std::string& data, int timeoutMs = 3000);
/**
* @brief 断开连接并清理Socket资源
*/
void clearSocket();
/**
* @brief 检查是否已连接到服务器
* @return 连接状态
*/
bool isConnected();
/**
* @brief 获取最后一次的错误信息
* @return 错误描述
*/
std::string getLastError();
} // namespace sockAct
#endif // SOCKETACTIONS_H