tchttpservice.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. #include "tchttpservice.h"
  2. QScopedPointer<TCHttpService> TCHttpService::m_instance;
  3. TCHttpService *TCHttpService::getInstance()
  4. {
  5. if (m_instance.isNull()) {
  6. m_instance.reset(new TCHttpService);
  7. }
  8. return m_instance.data();
  9. }
  10. void TCHttpService::apiLogin()
  11. {
  12. QByteArray pwdMd5 = QCryptographicHash::hash(m_firstPwd.toUtf8(), QCryptographicHash::Md5);
  13. QString md5Hex = pwdMd5.toHex();
  14. QString urlStr;
  15. if (m_enableSsl)
  16. urlStr = "https://" + m_domain + "/api/login";
  17. else
  18. urlStr = "http://" + m_domain + "/api/login";
  19. QUrl url(urlStr);
  20. QJsonObject jsonObj;
  21. jsonObj["user"]=m_userName;
  22. jsonObj["pwd"]=md5Hex;
  23. QJsonDocument jsonDoc(jsonObj);
  24. QByteArray jsonData = jsonDoc.toJson();
  25. QMap<QString, QString> headers;
  26. headers.insert("Content-Type", "application/json");
  27. QNetworkReply* reply = nullptr;
  28. QNetworkRequest request(url);
  29. for (auto ite = headers.constBegin(); ite != headers.constEnd(); ite++){
  30. request.setRawHeader(ite.key().toUtf8(), ite.value().toUtf8());
  31. }
  32. reply = m_manager.post(request, jsonData);
  33. QObject::connect(reply, &QNetworkReply::finished, [this, reply]() {
  34. QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());
  35. if (jsonDoc.isEmpty())
  36. return;
  37. QJsonObject jsonObj = jsonDoc.object();
  38. int code = jsonObj["code"].toInt();
  39. if (code == 0) {
  40. this->m_token = jsonObj["token"].toString();
  41. qDebug() << this->m_token;
  42. m_isOnline = true;
  43. ImageManager::instance()->addDomainUser(m_domain, m_userName);
  44. QString stdPath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
  45. ImageManager::instance()->initialize(stdPath + "/picpanel.db");
  46. emit signal_loginSuc();
  47. }
  48. });
  49. }
  50. void TCHttpService::apiUpload(const QString &filePath)
  51. {
  52. QString urlStr;
  53. if (m_enableSsl)
  54. urlStr = "https://" + m_domain + "/api/upload";
  55. else
  56. urlStr = "http://" + m_domain + "/api/upload";
  57. QFile *file = new QFile(filePath);
  58. if (!file->open(QIODevice::ReadOnly)) {
  59. qDebug() << "无法打开文件:" << filePath;
  60. delete file;
  61. return;
  62. }
  63. // 计算文件 MD5
  64. QCryptographicHash hash(QCryptographicHash::Md5);
  65. hash.addData(file);
  66. QString md5 = hash.result().toHex();
  67. // 重置文件指针
  68. file->seek(0);
  69. // 获取文件大小
  70. qint64 fileSize = file->size();
  71. // 创建 multipart 请求
  72. #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
  73. QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
  74. #else
  75. QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormData);
  76. #endif
  77. // 添加文件部分
  78. QHttpPart filePart;
  79. filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
  80. filePart.setHeader(QNetworkRequest::ContentDispositionHeader,
  81. QVariant("form-data; name=\"file\"; filename=\"" + QFileInfo(filePath).fileName() + "\""));
  82. filePart.setBodyDevice(file);
  83. multiPart->append(filePart);
  84. // 添加用户信息部分
  85. QHttpPart userPart;
  86. userPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"user\""));
  87. userPart.setBody(m_userName.toUtf8());
  88. multiPart->append(userPart);
  89. // 添加 MD5 部分
  90. QHttpPart md5Part;
  91. md5Part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"md5\""));
  92. md5Part.setBody(md5.toUtf8());
  93. multiPart->append(md5Part);
  94. // 添加文件大小部分
  95. QHttpPart sizePart;
  96. sizePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"size\""));
  97. sizePart.setBody(QString::number(fileSize).toUtf8());
  98. multiPart->append(sizePart);
  99. // 创建网络请求
  100. QNetworkRequest request(urlStr); // 替换为实际的服务器地址
  101. request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + multiPart->boundary());
  102. // 发送请求
  103. // QNetworkAccessManager *manager = new QNetworkAccessManager(this);
  104. QNetworkReply *reply = m_manager.post(request, multiPart);
  105. // 连接信号槽
  106. connect(reply, &QNetworkReply::finished, this, [=]() {
  107. if (reply->error() == QNetworkReply::NoError) {
  108. qDebug() << "上传成功:";
  109. QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll());
  110. QJsonObject jsonObj = jsonDoc.object();
  111. QString fileUrl = jsonObj["url"].toString();
  112. ImageManager::instance()->addImageUrl(m_domain, m_userName, fileUrl);
  113. emit signal_uploadFileSec(fileUrl);
  114. } else {
  115. qDebug() << "上传失败:" << reply->errorString();
  116. }
  117. reply->deleteLater();
  118. multiPart->deleteLater();
  119. });
  120. connect(reply, &QNetworkReply::uploadProgress, this, [this](qint64 bytesSent, qint64 bytesTotal) {
  121. if (bytesTotal > 0) {
  122. int progress = (bytesSent * 100) / bytesTotal;
  123. emit signal_progressUpdate(progress);
  124. qDebug() << "上传进度:" << progress << "%";
  125. }
  126. });
  127. }
  128. void TCHttpService::setConfiguration(QString userName, QString firstPwd, QString domain)
  129. {
  130. this->m_domain = domain;
  131. this->m_userName = userName;
  132. this->m_firstPwd = firstPwd;
  133. apiLogin();
  134. }
  135. void TCHttpService::setSsl(bool enable)
  136. {
  137. this->m_enableSsl = enable;
  138. }
  139. bool TCHttpService::getOnlineState()
  140. {
  141. return m_isOnline;
  142. }
  143. void TCHttpService::setUploadNum(int nb)
  144. {
  145. this->m_uploadNum = nb;
  146. }
  147. void TCHttpService::downloadImage(const QString &requestId, const QUrl &imageUrl)
  148. {
  149. #if 1
  150. QPixmap cachedPixmap;
  151. if (QPixmapCache::find(imageUrl.toString(), &cachedPixmap)) {
  152. emit signal_imageDownloaded(requestId, cachedPixmap);
  153. return;
  154. }
  155. if (getCachedImage(imageUrl, cachedPixmap)) {
  156. QPixmapCache::insert(imageUrl.toString(), cachedPixmap);
  157. emit signal_imageDownloaded(requestId, cachedPixmap);
  158. return;
  159. }
  160. #endif
  161. QNetworkRequest request(imageUrl);
  162. request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork);
  163. QNetworkReply* reply = m_manager.get(request);
  164. m_pendingRequests[reply] = requestId;
  165. connect(reply, &QNetworkReply::finished, [this, reply](){
  166. QString requestId = m_pendingRequests.take(reply);
  167. if (reply->error() != QNetworkReply::NoError) {
  168. emit signal_downloadFailed(requestId, reply->errorString());
  169. }
  170. else {
  171. QPixmap pixmap;
  172. if (pixmap.loadFromData(reply->readAll())) {
  173. cacheImage(reply->url(), pixmap);
  174. emit signal_imageDownloaded(requestId, pixmap);
  175. }
  176. else {
  177. emit signal_downloadFailed(requestId, "Failed to load image data");
  178. }
  179. }
  180. reply->deleteLater();
  181. });
  182. // connect(reply, &QNetworkReply::finished, [this, reply, imageUrl](){
  183. // QString requestId = m_pendingRequests.take(reply);
  184. // if (reply->error() != QNetworkReply::NoError) {
  185. // emit signal_downloadFailed(requestId, reply->errorString());
  186. // }
  187. // else {
  188. // QPixmap pixmap;
  189. // if (pixmap.loadFromData(reply->readAll())) {
  190. // QPixmapCache::insert(imageUrl.toString(), pixmap);
  191. // emit signal_imageDownloaded(requestId, pixmap);
  192. // }
  193. // else {
  194. // emit signal_downloadFailed(requestId, "Failed to load image data");
  195. // }
  196. // }
  197. // reply->deleteLater();
  198. // });
  199. // connect(reply, &QNetworkReply::finished, this, &TCHttpService::slot_downloadFinished);
  200. }
  201. QUrl TCHttpService::encodeUrl(QString urlStr, QMap<QString, QString> params)
  202. {
  203. QUrlQuery query;
  204. for(auto ite = params.constBegin(); ite != params.constEnd(); ite++){
  205. query.addQueryItem(ite.key(), ite.value());
  206. }
  207. QUrl url(urlStr);
  208. url.setQuery(query);
  209. return url;
  210. }
  211. void TCHttpService::cleanOldCacheFiles()
  212. {
  213. QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
  214. cacheDir.setNameFilters(QStringList() << "*.png" << "*.jpg" << "*.jpeg" << "*.svg");
  215. cacheDir.setFilter(QDir::Files);
  216. foreach (QString dirFile, cacheDir.entryList()) {
  217. QFileInfo fileInfo(cacheDir.absoluteFilePath(dirFile));
  218. if (fileInfo.lastModified().daysTo(QDateTime::currentDateTime()) > m_max_cache_days) {
  219. cacheDir.remove(dirFile);
  220. }
  221. }
  222. qint64 totalSize = 0;
  223. QFileInfoList files = cacheDir.entryInfoList(QDir::Files, QDir::Time | QDir::Reversed);
  224. foreach(QFileInfo file, files) {
  225. totalSize += file.size();
  226. }
  227. if (totalSize > m_disk_cache_size_mb * 1024 * 1024) {
  228. foreach (QFileInfo file, files) {
  229. if (totalSize <= m_disk_cache_size_mb * 1024 * 1024 * 0.9)
  230. break;
  231. totalSize -= file.size();
  232. QFile::remove(file.absoluteFilePath());
  233. }
  234. }
  235. }
  236. bool TCHttpService::getCachedImage(const QUrl &imageUrl, QPixmap &pixmap)
  237. {
  238. QString filePath = getCacheFilePath(imageUrl);
  239. if (QFile::exists(filePath)) {
  240. QFileInfo info(filePath);
  241. if (info.lastModified().daysTo(QDateTime::currentDateTime()) > m_max_cache_days) {
  242. QFile::remove(filePath);
  243. return false;
  244. }
  245. if (pixmap.load(filePath)) {
  246. return true;
  247. }
  248. }
  249. return false;
  250. }
  251. QString TCHttpService::getCacheFilePath(const QUrl &imageUrl)
  252. {
  253. QCryptographicHash hash(QCryptographicHash::Md5);
  254. hash.addData(imageUrl.toString().toUtf8());
  255. QString fileName = hash.result().toHex() + ".png";
  256. return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + fileName;
  257. }
  258. void TCHttpService::cacheImage(const QUrl &imageUrl, const QPixmap &pixmap)
  259. {
  260. QPixmapCache::insert(imageUrl.toString(), pixmap);
  261. QString filePath = getCacheFilePath(imageUrl);
  262. pixmap.save(filePath, "PNG");
  263. cleanOldCacheFiles();
  264. }
  265. TCHttpService::TCHttpService(QObject *parent) : QObject(parent)
  266. {
  267. }
  268. void TCHttpService::slot_downloadFinished(QNetworkReply *reply)
  269. {
  270. QString requestId = m_pendingRequests.take(reply);
  271. if (reply->error() != QNetworkReply::NoError) {
  272. emit signal_downloadFailed(requestId, reply->errorString());
  273. }
  274. else {
  275. QPixmap pixmap;
  276. if (pixmap.loadFromData(reply->readAll())) {
  277. cacheImage(reply->url(), pixmap);
  278. emit signal_imageDownloaded(requestId, pixmap);
  279. }
  280. else {
  281. emit signal_downloadFailed(requestId, "Failed to load image data");
  282. }
  283. }
  284. reply->deleteLater();
  285. }