#include "tchttpservice.h" QScopedPointer TCHttpService::m_instance; TCHttpService *TCHttpService::getInstance() { if (m_instance.isNull()) { m_instance.reset(new TCHttpService); } return m_instance.data(); } void TCHttpService::apiLogin() { QByteArray pwdMd5 = QCryptographicHash::hash(m_firstPwd.toUtf8(), QCryptographicHash::Md5); QString md5Hex = pwdMd5.toHex(); QString urlStr; if (m_enableSsl) urlStr = "https://" + m_domain + "/api/login"; else urlStr = "http://" + m_domain + "/api/login"; QUrl url(urlStr); QJsonObject jsonObj; jsonObj["user"]=m_userName; jsonObj["pwd"]=md5Hex; QJsonDocument jsonDoc(jsonObj); QByteArray jsonData = jsonDoc.toJson(); QMap headers; headers.insert("Content-Type", "application/json"); QNetworkReply* reply = nullptr; QNetworkRequest request(url); for (auto ite = headers.constBegin(); ite != headers.constEnd(); ite++){ request.setRawHeader(ite.key().toUtf8(), ite.value().toUtf8()); } reply = m_manager.post(request, jsonData); QObject::connect(reply, &QNetworkReply::finished, [this, reply]() { QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll()); if (jsonDoc.isEmpty()) return; QJsonObject jsonObj = jsonDoc.object(); int code = jsonObj["code"].toInt(); if (code == 0) { this->m_token = jsonObj["token"].toString(); qDebug() << this->m_token; m_isOnline = true; ImageManager::instance()->addDomainUser(m_domain, m_userName); QString stdPath = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); ImageManager::instance()->initialize(stdPath + "/picpanel.db"); emit signal_loginSuc(); } }); } void TCHttpService::apiUpload(const QString &filePath) { QString urlStr; if (m_enableSsl) urlStr = "https://" + m_domain + "/api/upload"; else urlStr = "http://" + m_domain + "/api/upload"; QFile *file = new QFile(filePath); if (!file->open(QIODevice::ReadOnly)) { qDebug() << "无法打开文件:" << filePath; delete file; return; } // 计算文件 MD5 QCryptographicHash hash(QCryptographicHash::Md5); hash.addData(file); QString md5 = hash.result().toHex(); // 重置文件指针 file->seek(0); // 获取文件大小 qint64 fileSize = file->size(); // 创建 multipart 请求 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); #else QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormData); #endif // 添加文件部分 QHttpPart filePart; filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\"; filename=\"" + QFileInfo(filePath).fileName() + "\"")); filePart.setBodyDevice(file); multiPart->append(filePart); // 添加用户信息部分 QHttpPart userPart; userPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"user\"")); userPart.setBody(m_userName.toUtf8()); multiPart->append(userPart); // 添加 MD5 部分 QHttpPart md5Part; md5Part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"md5\"")); md5Part.setBody(md5.toUtf8()); multiPart->append(md5Part); // 添加文件大小部分 QHttpPart sizePart; sizePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"size\"")); sizePart.setBody(QString::number(fileSize).toUtf8()); multiPart->append(sizePart); // 创建网络请求 QNetworkRequest request(urlStr); // 替换为实际的服务器地址 request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + multiPart->boundary()); // 发送请求 // QNetworkAccessManager *manager = new QNetworkAccessManager(this); QNetworkReply *reply = m_manager.post(request, multiPart); // 连接信号槽 connect(reply, &QNetworkReply::finished, this, [=]() { if (reply->error() == QNetworkReply::NoError) { qDebug() << "上传成功:"; QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll()); QJsonObject jsonObj = jsonDoc.object(); QString fileUrl = jsonObj["url"].toString(); ImageManager::instance()->addImageUrl(m_domain, m_userName, fileUrl); emit signal_uploadFileSec(fileUrl); } else { qDebug() << "上传失败:" << reply->errorString(); } reply->deleteLater(); multiPart->deleteLater(); }); connect(reply, &QNetworkReply::uploadProgress, this, [this](qint64 bytesSent, qint64 bytesTotal) { if (bytesTotal > 0) { int progress = (bytesSent * 100) / bytesTotal; emit signal_progressUpdate(progress); qDebug() << "上传进度:" << progress << "%"; } }); } void TCHttpService::apiSharePicShare(const QString &fileName, const QString &md5) { QString urlStr; if (m_enableSsl) urlStr = "https://" + m_domain + "/api/sharepic"; else urlStr = "http://" + m_domain + "/api/sharepic"; QMap headers; QMap body; QMap params; headers.insert("Content-Type", "application/json"); QString bodyStr = QString("\"%1\":\"%2\",\"%3\":\"%4\",\"%5\":\"%6\",\"%7\":\"%8\"").arg("token").arg(m_token). arg("user").arg(m_userName).arg("md5").arg(md5).arg("filename").arg(fileName); params.insert("cmd", "share"); } void TCHttpService::setConfiguration(QString userName, QString firstPwd, QString domain) { this->m_domain = domain; this->m_userName = userName; this->m_firstPwd = firstPwd; apiLogin(); } void TCHttpService::setSsl(bool enable) { this->m_enableSsl = enable; } bool TCHttpService::getOnlineState() { return m_isOnline; } void TCHttpService::setUploadNum(int nb) { this->m_uploadNum = nb; } void TCHttpService::downloadImage(const QString &requestId, const QUrl &imageUrl) { #if 0 QPixmap cachedPixmap; if (QPixmapCache::find(imageUrl.toString(), &cachedPixmap)) { emit signal_imageDownloaded(requestId, cachedPixmap); return; } if (getCachedImage(imageUrl, cachedPixmap)) { QPixmapCache::insert(imageUrl.toString(), cachedPixmap); emit signal_imageDownloaded(requestId, cachedPixmap); return; } #endif QNetworkRequest request(imageUrl); QNetworkReply* reply = m_manager.get(request); connect(reply, &QNetworkReply::finished, [this, reply](){ QString requestId = m_pendingRequests.take(reply); if (reply->error() != QNetworkReply::NoError) { emit signal_downloadFailed(requestId, reply->errorString()); } else { QPixmap pixmap; if (pixmap.loadFromData(reply->readAll())) { emit signal_imageDownloaded(requestId, pixmap); } else { emit signal_downloadFailed(requestId, "Failed to load image data"); } } reply->deleteLater(); }); m_pendingRequests[reply] = requestId; } QUrl TCHttpService::encodeUrl(QString urlStr, QMap params) { QUrlQuery query; for(auto ite = params.constBegin(); ite != params.constEnd(); ite++){ query.addQueryItem(ite.key(), ite.value()); } QUrl url(urlStr); url.setQuery(query); return url; } void TCHttpService::cleanOldCacheFiles() { QDir cacheDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)); cacheDir.setNameFilters(QStringList() << "*.png" << "*.jpg" << "*.jpeg" << "*.svg"); cacheDir.setFilter(QDir::Files); foreach (QString dirFile, cacheDir.entryList()) { QFileInfo fileInfo(cacheDir.absoluteFilePath(dirFile)); if (fileInfo.lastModified().daysTo(QDateTime::currentDateTime()) > m_max_cache_days) { cacheDir.remove(dirFile); } } qint64 totalSize = 0; QFileInfoList files = cacheDir.entryInfoList(QDir::Files, QDir::Time | QDir::Reversed); foreach(QFileInfo file, files) { totalSize += file.size(); } if (totalSize > m_disk_cache_size_mb * 1024 * 1024) { foreach (QFileInfo file, files) { if (totalSize <= m_disk_cache_size_mb * 1024 * 1024 * 0.9) break; totalSize -= file.size(); QFile::remove(file.absoluteFilePath()); } } } bool TCHttpService::getCachedImage(const QUrl &imageUrl, QPixmap &pixmap) { QString filePath = getCacheFilePath(imageUrl); if (QFile::exists(filePath)) { QFileInfo info(filePath); if (info.lastModified().daysTo(QDateTime::currentDateTime()) > m_max_cache_days) { QFile::remove(filePath); return false; } if (pixmap.load(filePath)) { return true; } } return false; } QString TCHttpService::getCacheFilePath(const QUrl &imageUrl) { QCryptographicHash hash(QCryptographicHash::Md5); hash.addData(imageUrl.toString().toUtf8()); QString fileName = hash.result().toHex() + ".png"; return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/" + fileName; } TCHttpService::TCHttpService(QObject *parent) : QObject(parent) { } void TCHttpService::slot_downloadFinished(QNetworkReply *reply) { QString requestId = m_pendingRequests.take(reply); if (reply->error() != QNetworkReply::NoError) { emit signal_downloadFailed(requestId, reply->errorString()); } else { QPixmap pixmap; if (pixmap.loadFromData(reply->readAll())) { emit signal_imageDownloaded(requestId, pixmap); } else { emit signal_downloadFailed(requestId, "Failed to load image data"); } } reply->deleteLater(); }