-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChinaHolidayManager.cpp
More file actions
178 lines (146 loc) · 4.9 KB
/
Copy pathChinaHolidayManager.cpp
File metadata and controls
178 lines (146 loc) · 4.9 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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include "ChinaHolidayManager.hpp"
#include "ConfigStore.hpp"
#include "Logger.hpp"
#include <QDate>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QSslSocket>
#include <QTimer>
#include <QUrl>
// CDN 镜像源列表
static const QStringList cdnUrls = {
"https://cdn.jsdelivr.net/npm/chinese-days/dist/years/%1.json",
"https://fastly.jsdelivr.net/npm/chinese-days/dist/years/%1.json",
"https://registry.npmmirror.com/chinese-days/latest/files/dist/years/"
"%1.json"};
ChinaHolidayManager *ChinaHolidayManager::get() {
static ChinaHolidayManager instance;
return &instance;
}
ChinaHolidayManager::ChinaHolidayManager(QObject *parent)
: QObject(parent), _networkManagerPtr(new QNetworkAccessManager(this)) {}
void ChinaHolidayManager::updateChinaHolidayData() {
// 先尝试从缓存加载
tryLoadFromCache();
// 缓存命中则直接返回
if (!_holidayDates.isEmpty()) {
return;
}
// 缓存未命中,走网络下载
_urls.clear();
_result.clear();
const int currentYear = QDate::currentDate().year();
for (const QString &tpl : cdnUrls) {
const QString url = tpl.arg(currentYear);
_urls.append(url);
}
fetchHolidayData();
}
void ChinaHolidayManager::fetchHolidayData() {
// 如果本年度已下载完成,解析数据并结束
if (!_result.isEmpty()) {
QJsonDocument doc = QJsonDocument::fromJson(_result.toUtf8());
if (doc.isNull()) {
emit signalSyncError("节假日数据解析失败:JSON 无效");
return;
}
handleHolidayData();
return;
}
if (_urls.isEmpty()) {
emit signalSyncError("节假日数据下载失败:所有镜像源均不可用");
return;
}
QString url = _urls.takeFirst();
QUrl q_url = QUrl(url);
QNetworkRequest request(q_url);
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
QNetworkRequest::NoLessSafeRedirectPolicy);
QNetworkReply *reply = _networkManagerPtr->get(request);
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
reply->deleteLater();
auto errorCode = reply->error();
if (errorCode != QNetworkReply::NoError) {
Logger::Tag("ChinaHolidayManager")
.eFmt("Network error: %s",
reply->errorString().toStdString().c_str());
#ifndef Q_OS_WIN
if (errorCode == QNetworkReply::SslHandshakeFailedError) {
emit signalSslNotFound();
return; // SSL 彻底不可用,停止重试
}
#endif
fetchHolidayData();
return;
}
QByteArray data = reply->readAll();
QJsonDocument doc = QJsonDocument::fromJson(data);
if (doc.isNull()) {
Logger::Tag("ChinaHolidayManager").i("Invalid JSON from network reply");
fetchHolidayData();
return;
}
_result = QString::fromUtf8(data);
fetchHolidayData();
});
}
void ChinaHolidayManager::handleHolidayData() {
QJsonDocument doc = QJsonDocument::fromJson(_result.toUtf8());
if (doc.isNull() || !doc.isObject()) {
emit signalSyncError("节假日数据解析失败:JSON 无效");
return;
}
QJsonObject root = doc.object();
parseJsonToMemory(root);
QJsonObject cache;
cache["year"] = QDate::currentDate().year();
cache["holidays"] = root.value("holidays");
cache["workdays"] = root.value("workdays");
ConfigStore::get().save("holidayConfig", cache);
emit signalSyncSuccess("节假日数据同步完成(网络)");
}
void ChinaHolidayManager::parseJsonToMemory(const QJsonObject &root) {
_holidayDates.clear();
QJsonObject holidays = root.value("holidays").toObject();
for (auto it = holidays.begin(); it != holidays.end(); ++it) {
QDate date = QDate::fromString(it.key(), "yyyy-MM-dd");
if (date.isValid()) {
_holidayDates.insert(date);
}
}
_workdayDates.clear();
QJsonObject workdays = root.value("workdays").toObject();
for (auto it = workdays.begin(); it != workdays.end(); ++it) {
QDate date = QDate::fromString(it.key(), "yyyy-MM-dd");
if (date.isValid()) {
_workdayDates.insert(date);
}
}
Logger::Tag("ChinaHolidayManager")
.dFmt("Parsed %d holidays, %d workdays", _holidayDates.size(),
_workdayDates.size());
}
void ChinaHolidayManager::tryLoadFromCache() {
QJsonObject cache = ConfigStore::get().load("holidayConfig");
if (cache.isEmpty()) {
return;
}
int cachedYear = cache.value("year").toInt();
int currentYear = QDate::currentDate().year();
if (cachedYear != currentYear) {
Logger::Tag("ChinaHolidayManager")
.dFmt("Cache year %d != current %d, will re-fetch", cachedYear,
currentYear);
return;
}
parseJsonToMemory(cache);
emit signalSyncSuccess("节假日数据同步完成(缓存)");
}
bool ChinaHolidayManager::isHoliday(const QDate &date) const {
return _holidayDates.contains(date);
}
bool ChinaHolidayManager::isWorkday(const QDate &date) const {
return _workdayDates.contains(date);
}