#include "stdafx.h" #include "TriggerSettingsDlg.h" #include "2015RemoteDlg.h" #include "jsoncpp/json.h" #include #include #ifndef _WIN64 #ifdef _DEBUG #pragma comment(lib, "jsoncpp/jsoncppd.lib") #else #pragma comment(lib, "jsoncpp/jsoncpp.lib") #endif #else #ifdef _DEBUG #pragma comment(lib, "jsoncpp/jsoncpp_x64d.lib") #else #pragma comment(lib, "jsoncpp/jsoncpp_x64.lib") #endif #endif // GBK (CP_ACP) -> UTF-8 编码转换 static std::string GbkToUtf8(const std::string& gbkStr) { if (gbkStr.empty()) return ""; // GBK -> WideChar int wideLen = MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, NULL, 0); if (wideLen <= 0) return gbkStr; std::wstring wideStr(wideLen, 0); MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, &wideStr[0], wideLen); // WideChar -> UTF-8 int utf8Len = WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, NULL, 0, NULL, NULL); if (utf8Len <= 0) return gbkStr; std::string utf8Str(utf8Len, 0); WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, &utf8Str[0], utf8Len, NULL, NULL); // 移除末尾的 null 字符 if (!utf8Str.empty() && utf8Str.back() == '\0') { utf8Str.pop_back(); } return utf8Str; } // UTF-8 -> GBK (CP_ACP) 编码转换 static std::string Utf8ToGbk(const std::string& utf8Str) { if (utf8Str.empty()) return ""; // UTF-8 -> WideChar int wideLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, NULL, 0); if (wideLen <= 0) return utf8Str; std::wstring wideStr(wideLen, 0); MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &wideStr[0], wideLen); // WideChar -> GBK int gbkLen = WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, NULL, 0, NULL, NULL); if (gbkLen <= 0) return utf8Str; std::string gbkStr(gbkLen, 0); WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, &gbkStr[0], gbkLen, NULL, NULL); // 移除末尾的 null 字符 if (!gbkStr.empty() && gbkStr.back() == '\0') { gbkStr.pop_back(); } return gbkStr; } BEGIN_MESSAGE_MAP(CTriggerSettingsDlg, CDialogLangEx) ON_BN_CLICKED(IDC_BTN_SAVE, &CTriggerSettingsDlg::OnBnClickedBtnSave) ON_BN_CLICKED(IDC_BTN_TRIGGER_ADD, &CTriggerSettingsDlg::OnBnClickedBtnTriggerAdd) ON_BN_CLICKED(IDC_BTN_TRIGGER_REMOVE, &CTriggerSettingsDlg::OnBnClickedBtnTriggerRemove) ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_TRIGGERS, &CTriggerSettingsDlg::OnLvnItemchangedListTriggers) END_MESSAGE_MAP() CTriggerSettingsDlg::CTriggerSettingsDlg(std::vector& dllList, CWnd* pParent) : CDialogLangEx(IDD_DIALOG_TRIGGER_SETTINGS, pParent) , m_DllList(dllList) { } CTriggerSettingsDlg::~CTriggerSettingsDlg() { } void CTriggerSettingsDlg::DoDataExchange(CDataExchange* pDX) { CDialogLangEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_COMBO_TRIGGER_TYPE, m_comboTriggerType); DDX_Control(pDX, IDC_LIST_TRIGGER_PLUGINS, m_listPlugins); DDX_Control(pDX, IDC_LIST_TRIGGERS, m_listTriggers); } BOOL CTriggerSettingsDlg::OnInitDialog() { CDialogLangEx::OnInitDialog(); InitControls(); // 加载配置 m_Configs = LoadTriggerConfigs(); // 加载插件列表 LoadPluginsToList(); // 加载已配置的触发器 LoadTriggersToList(); return TRUE; } void CTriggerSettingsDlg::InitControls() { // 初始化触发类型下拉框 m_comboTriggerType.InsertString(TRIGGER_HOST_ONLINE, _TR("主机上线")); m_comboTriggerType.SetCurSel(TRIGGER_HOST_ONLINE); // 初始化插件列表 m_listPlugins.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_CHECKBOXES); m_listPlugins.InsertColumn(0, _TR("插件名称"), LVCFMT_LEFT, 160); // 初始化已配置触发器列表 m_listTriggers.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); m_listTriggers.InsertColumn(0, _TR("触发器"), LVCFMT_LEFT, 160); // 设置静态文本 SetWindowText(_TR("触发器设置")); GetDlgItem(IDC_STATIC_TRIGGER_TYPE)->SetWindowText(_TR("触发类型:")); GetDlgItem(IDC_STATIC_TRIGGER_ACTION)->SetWindowText(_TR("执行动作:")); } void CTriggerSettingsDlg::LoadPluginsToList() { m_listPlugins.DeleteAllItems(); int index = 0; for (const auto& dll : m_DllList) { if (!dll || !dll->Data) continue; m_listPlugins.InsertItem(index, CString(dll->Name.c_str())); m_listPlugins.SetItemData(index, (DWORD_PTR)dll); index++; } // 如果有已配置的主机上线触发器,勾选对应的插件 TriggerConfig* onlineTrigger = GetOnlineTrigger(m_Configs); if (onlineTrigger) { for (int i = 0; i < m_listPlugins.GetItemCount(); i++) { DllInfo* dll = reinterpret_cast(m_listPlugins.GetItemData(i)); if (!dll) continue; for (const auto& pluginName : onlineTrigger->PluginNames) { if (pluginName == dll->Name) { m_listPlugins.SetCheck(i, TRUE); break; } } } } } void CTriggerSettingsDlg::LoadTriggersToList() { m_listTriggers.DeleteAllItems(); const char* typeNames[] = { "主机上线" }; int index = 0; for (const auto& cfg : m_Configs) { if (!cfg.PluginNames.empty()) { // 显示触发器类型和插件数量 CString text; text.Format(_T("%s (%d)"), _TR(typeNames[cfg.Type]), (int)cfg.PluginNames.size()); m_listTriggers.InsertItem(index, text); m_listTriggers.SetItemData(index, cfg.Type); index++; } } } void CTriggerSettingsDlg::OnBnClickedBtnTriggerAdd() { // 获取选中的触发类型 int triggerType = m_comboTriggerType.GetCurSel(); if (triggerType < 0) return; // 获取勾选的插件(直接从 DllInfo 获取名称,避免编码转换问题) std::vector selectedPlugins; for (int i = 0; i < m_listPlugins.GetItemCount(); i++) { if (m_listPlugins.GetCheck(i)) { DllInfo* dll = reinterpret_cast(m_listPlugins.GetItemData(i)); if (dll) { selectedPlugins.push_back(dll->Name); } } } if (selectedPlugins.empty()) { MessageBoxL(_TR("请先选择至少一个插件"), _TR("提示"), MB_ICONINFORMATION); return; } // 查找或创建该类型的触发器 TriggerConfig* cfg = nullptr; for (auto& c : m_Configs) { if (c.Type == (TriggerType)triggerType) { cfg = &c; break; } } if (!cfg) { TriggerConfig newCfg; newCfg.Type = (TriggerType)triggerType; m_Configs.push_back(newCfg); cfg = &m_Configs.back(); } cfg->PluginNames = selectedPlugins; // 刷新显示 LoadTriggersToList(); } void CTriggerSettingsDlg::OnBnClickedBtnTriggerRemove() { POSITION pos = m_listTriggers.GetFirstSelectedItemPosition(); if (!pos) return; int nItem = m_listTriggers.GetNextSelectedItem(pos); TriggerType type = (TriggerType)m_listTriggers.GetItemData(nItem); // 从配置中移除 for (auto it = m_Configs.begin(); it != m_Configs.end(); ++it) { if (it->Type == type) { m_Configs.erase(it); break; } } // 取消插件列表的勾选 for (int i = 0; i < m_listPlugins.GetItemCount(); i++) { m_listPlugins.SetCheck(i, FALSE); } // 刷新显示 LoadTriggersToList(); } void CTriggerSettingsDlg::OnLvnItemchangedListTriggers(NMHDR* pNMHDR, LRESULT* pResult) { LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); *pResult = 0; // 只处理选中状态变化 if (!(pNMLV->uNewState & LVIS_SELECTED)) return; int nItem = pNMLV->iItem; if (nItem < 0) return; TriggerType type = (TriggerType)m_listTriggers.GetItemData(nItem); // 查找对应的触发器配置 TriggerConfig* cfg = nullptr; for (auto& c : m_Configs) { if (c.Type == type) { cfg = &c; break; } } // 先取消所有勾选 for (int i = 0; i < m_listPlugins.GetItemCount(); i++) { m_listPlugins.SetCheck(i, FALSE); } // 勾选该触发器配置的插件 if (cfg) { for (int i = 0; i < m_listPlugins.GetItemCount(); i++) { DllInfo* dll = reinterpret_cast(m_listPlugins.GetItemData(i)); if (!dll) continue; for (const auto& pluginName : cfg->PluginNames) { if (pluginName == dll->Name) { m_listPlugins.SetCheck(i, TRUE); break; } } } } // 同步下拉框选择 m_comboTriggerType.SetCurSel(type); } void CTriggerSettingsDlg::OnBnClickedBtnSave() { // 先从界面收集当前选择 int triggerType = m_comboTriggerType.GetCurSel(); if (triggerType >= 0) { std::vector selectedPlugins; for (int i = 0; i < m_listPlugins.GetItemCount(); i++) { if (m_listPlugins.GetCheck(i)) { DllInfo* dll = reinterpret_cast(m_listPlugins.GetItemData(i)); if (dll) { selectedPlugins.push_back(dll->Name); } } } // 更新或创建触发器配置 TriggerConfig* cfg = nullptr; for (auto& c : m_Configs) { if (c.Type == (TriggerType)triggerType) { cfg = &c; break; } } if (!selectedPlugins.empty()) { if (!cfg) { TriggerConfig newCfg; newCfg.Type = (TriggerType)triggerType; m_Configs.push_back(newCfg); cfg = &m_Configs.back(); } cfg->PluginNames = selectedPlugins; } else if (cfg) { // 如果没有选中插件,删除该触发器 for (auto it = m_Configs.begin(); it != m_Configs.end(); ++it) { if (it->Type == (TriggerType)triggerType) { m_Configs.erase(it); break; } } } } SaveTriggerConfigs(m_Configs); LoadTriggersToList(); MessageBoxL(_TR("配置已保存"), _TR("提示"), MB_ICONINFORMATION); } std::string CTriggerSettingsDlg::GetTriggerConfigPath() { std::string dbPath = GetDbPath(); size_t pos = dbPath.find_last_of("\\/"); std::string dir = (pos != std::string::npos) ? dbPath.substr(0, pos + 1) : ""; return dir + "triggers.json"; } std::vector CTriggerSettingsDlg::LoadTriggerConfigs() { std::vector configs; std::string path = GetTriggerConfigPath(); std::ifstream file(path); if (!file.is_open()) { return configs; } Json::Value root; Json::CharReaderBuilder builder; std::string errors; if (!Json::parseFromStream(builder, file, &root, &errors)) { return configs; } if (!root.isArray()) { return configs; } for (const auto& item : root) { TriggerConfig cfg; cfg.Type = (TriggerType)item.get("type", TRIGGER_HOST_ONLINE).asInt(); const Json::Value& plugins = item["plugins"]; if (plugins.isArray()) { for (const auto& p : plugins) { cfg.PluginNames.push_back(Utf8ToGbk(p.asString())); // UTF-8 -> GBK } } if (!cfg.PluginNames.empty()) { configs.push_back(cfg); } } return configs; } void CTriggerSettingsDlg::SaveTriggerConfigs(const std::vector& configs) { std::string path = GetTriggerConfigPath(); Json::Value root(Json::arrayValue); for (const auto& cfg : configs) { Json::Value item; item["type"] = cfg.Type; Json::Value plugins(Json::arrayValue); for (const auto& name : cfg.PluginNames) { plugins.append(GbkToUtf8(name)); // GBK -> UTF-8 } item["plugins"] = plugins; root.append(item); } std::ofstream file(path); if (file.is_open()) { Json::StreamWriterBuilder builder; builder["indentation"] = " "; builder["emitUTF8"] = true; // 输出可读的 UTF-8 字符,而非 \uXXXX std::unique_ptr writer(builder.newStreamWriter()); writer->write(root, &file); file.close(); // 确保文件完全写入并关闭 } // 通知 TriggerManager 重新加载缓存 TriggerManager::Instance().Reload(); } TriggerConfig* CTriggerSettingsDlg::GetOnlineTrigger(std::vector& configs) { for (auto& cfg : configs) { if (cfg.Type == TRIGGER_HOST_ONLINE && !cfg.PluginNames.empty()) { return &cfg; } } return nullptr; } // ============================================ // TriggerManager 实现 // ============================================ TriggerManager::TriggerManager() : m_bLoaded(false) { InitializeCriticalSection(&m_cs); } TriggerManager::~TriggerManager() { DeleteCriticalSection(&m_cs); } void TriggerManager::LoadFromDisk() { // 不加锁,由调用者保证线程安全 m_OnlinePlugins.clear(); auto configs = CTriggerSettingsDlg::LoadTriggerConfigs(); for (const auto& cfg : configs) { if (cfg.Type == TRIGGER_HOST_ONLINE) { for (const auto& name : cfg.PluginNames) { m_OnlinePlugins.insert(name); } } } m_bLoaded = true; } void TriggerManager::Reload() { EnterCriticalSection(&m_cs); LoadFromDisk(); LeaveCriticalSection(&m_cs); } bool TriggerManager::HasOnlineTrigger() { EnterCriticalSection(&m_cs); if (!m_bLoaded) { LoadFromDisk(); } bool has = !m_OnlinePlugins.empty(); LeaveCriticalSection(&m_cs); return has; } std::set TriggerManager::GetOnlinePlugins() { EnterCriticalSection(&m_cs); if (!m_bLoaded) { LoadFromDisk(); } std::set result = m_OnlinePlugins; // 复制一份返回 LeaveCriticalSection(&m_cs); return result; }