user_msg_monitor.cpp
4.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include "stdafx.h"
#include "etradeclient/browser/user_msg_monitor.h"
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "etradeclient/browser/session.h"
#include "etradeclient/browser/url_request_proxy.h"
#include "etradeclient/utility/logging.h"
#include "etradeclient/utility/application_config.h"
#include "etradeclient/utility/url_config.h"
#include "etradeclient/utility/win_msg_define.h"
#include "etradeclient/utility/string_converter.h"
namespace
{
static const std::string JSON_TAG_CODE = "code";
static const std::string JSON_TAG_MSG = "message";
static const std::string JSON_TAG_AMOUNT = "amount";
static const std::string JSON_VAL_SUCC = "0"/*"success"*/;
}
UserMsgMonitor::UserMsgMonitor() : m_continue(false), m_timer(m_io)
{
m_interval = ApplicationConfig::Instance().MsgCountQueryInterval();
const uint32_t kIntervalMin = 60, kIntervalMax = 300;
if (m_interval < kIntervalMin)
m_interval = kIntervalMin;
else if (m_interval > kIntervalMax)
m_interval = kIntervalMax;
}
UserMsgMonitor::~UserMsgMonitor()
{
Stop();
m_io.stop(); // Stop io service before destruction.
}
void UserMsgMonitor::Start()
{
m_continue = true;
m_thread = std::thread(&UserMsgMonitor::GetMsgCountProc, this);
}
void UserMsgMonitor::Stop()
{
m_continue = false; // Make sure set flag first and then cancel the timer, this can prevent the chance of entering the loop again.
m_timer.cancel();
if (m_thread.joinable())
m_thread.join();
}
void UserMsgMonitor::CheckOnce(WinHttp::Request& request)
{
uint32_t msg_count = 0; // First initialize the value of msg count, this value will be updated only if no error happens.
do
{
std::stringstream ss;
const int kDelayMS = 500;
const int kRequestTimes = 2; // 2 is enough.
int index = 0;
for (int index = 0; index < kRequestTimes; ++index)
{
try
{
const uint32_t kHTTPOK = 200;
request.Send();
uint32_t status_code = request.GetResponseStatus();
if (kHTTPOK != status_code)
{
std::string err_msg = "网络请求错误! 错误码: " + std::to_string(status_code);
throw std::exception(err_msg.c_str());
}
std::string response_body = request.ReadResponseBody();
if (response_body.empty())
throw std::exception("获取服务器响应数据失败,请确保网络连接正常");
ss << response_body;
break;
}
catch (std::exception& ex)
{
LOG_ERROR(gbk_2_wstr(ex.what()));
std::this_thread::sleep_for(std::chrono::milliseconds(kDelayMS));
continue;
}
}
if (kRequestTimes == index)
{
LOG_ERROR(L"从服务器获取未读通知消息数量失败!");
break;
}
namespace PT = boost::property_tree;
bool login_res = false;
try //Parse the configuration file
{
PT::ptree ptree;
PT::read_json(ss, ptree);
std::string res = ptree.get<std::string>(JSON_TAG_CODE);
login_res = res.compare(JSON_VAL_SUCC) == 0 ? true : false;
if (!login_res)
{
LOG_ERROR(L"服务器处理失败,返回信息:" + str_2_wstr(res) + str_2_wstr(ptree.get<std::string>(JSON_TAG_MSG)));
return;
}
else
#if _DEBUG
msg_count = 1; // @TODO remove
#else
msg_count = ptree.get<uint32_t>(JSON_TAG_AMOUNT);
#endif
}
catch (...)
{
LOG_ERROR(L"解析服务器返回的未读通知消息数量时出错!请确认返回数据不为空,返回的数据格式为正确的Json格式!");
return;
}
} while (0);
// Post message to CMainFrame to update msg count.
// AfxGetMainWnd() will return NULL if called from an other thread (has to do with thread local storage).
// That's why we use AfxGetApp()->GetMainWnd() instead of AfxGetMainWnd().
PostMessageW(AfxGetApp()->GetMainWnd()->GetSafeHwnd(), WM_UPDATE_USER_MSG_COUNT, (WPARAM)msg_count, NULL);
}
void UserMsgMonitor::GetMsgCountProc()
{
try
{
const uint32_t kHTTPOK = 200;
std::wstring err_msg = L"";
auto& url_cfg = URLConfig::Instance();
WinHttp win_http;
win_http.ConnectHost(url_cfg.Host(), url_cfg.Port(), url_cfg.IsHttps());
auto request = win_http.OpenRequest(WinHttp::Method::GET, url_cfg.UserMsgCountPath());
if (url_cfg.IsHttps())
{
auto& app_cfg = ApplicationConfig::Instance();
request.SetClientCertificate(app_cfg.ClientCertStore(), app_cfg.ClientCertSubject());
}
request.SetCookies(Session::Instance().Cookies());
CheckOnce(request); // Check once before waiting.
while (m_continue)
{
m_timer.expires_from_now(boost::posix_time::seconds(m_interval));
m_timer.async_wait(
[&](const boost::system::error_code& ec)
{
if (!ec)
CheckOnce(request);
});
m_io.run_one();
m_io.reset();
}
}
catch (std::exception& ex)
{
LOG_ERROR(gbk_2_wstr(ex.what()));
}
}