Kylin/Universal/ApplicationSettings.h

90 lines
3.7 KiB
C++

#ifndef __APPLICATIONSETTINGS_H__
#define __APPLICATIONSETTINGS_H__
#include "BoostLog.h"
#include <boost/asio/steady_timer.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/tuple/to_seq.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <filesystem>
template <typename Child>
class ApplicationSettings {
#define BUILD_SETTING_FIELD(Category, Type, Name, DefaultValue) \
inline void set##Name(const Type &value) { \
std::lock_guard locker(m_mutex); \
m_ptree.put(#Category "." #Name, value); \
m_needSave = true; \
} \
inline Type get##Name() const { \
std::lock_guard locker(m_mutex); \
return m_ptree.get<Type>(#Category "." #Name, DefaultValue); \
}
#define BUILD_STATUS(Type, Name, DefaultValue) BUILD_SETTING_FIELD(Status, Type, Name, DefaultValue)
#define BUILD_SETTING(Type, Name, DefaultValue) BUILD_SETTING_FIELD(Settings, Type, Name, DefaultValue)
#define INITIALIZE_FIELD(Name) set##Name(get##Name());
#define MACRO(r, data, elem) INITIALIZE_FIELD(elem)
#define INITIALIZE_FIELDS(...) \
inline void initializeFileds() final { \
BOOST_PP_SEQ_FOR_EACH(MACRO, _, BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))) \
}
public:
ApplicationSettings(const std::string &path) : m_path(path) {
if (std::filesystem::exists(path)) {
try {
boost::property_tree::read_ini(path, m_ptree);
} catch (const boost::property_tree::ini_parser_error &e) {
LOG(error) << e.what();
}
} else {
static_cast<Child *>(this)->initializeFileds();
save();
}
}
void startCheckInterval(boost::asio::io_context &ioContext, uint32_t seconds) {
m_timer = std::make_unique<boost::asio::steady_timer>(ioContext);
m_interval = seconds;
run();
}
protected:
void save() {
if (!m_needSave) return;
try {
std::lock_guard locker(m_mutex);
boost::property_tree::write_ini(m_path, m_ptree);
m_needSave = false;
} catch (const boost::property_tree::ini_parser_error &e) {
LOG(error) << e.what();
}
}
void run() {
m_timer->expires_after(std::chrono::seconds(m_interval));
m_timer->async_wait([this](const boost::system::error_code &error) {
if (error) {
LOG(error) << error.message();
return;
}
save();
run();
});
}
virtual void initializeFileds() {
}
boost::property_tree::ptree m_ptree;
bool m_needSave = false;
mutable std::mutex m_mutex;
private:
std::string m_path;
std::unique_ptr<boost::asio::steady_timer> m_timer;
uint32_t m_interval;
};
#endif // __APPLICATIONSETTINGS_H__