mirror of
https://gitee.com/spark-store-project/spark-store
synced 2026-06-22 22:23:49 +08:00
Temporary commit
This commit is contained in:
+71
-31
@@ -8,15 +8,19 @@
|
||||
|
||||
SpkDownloadMgr::SpkDownloadMgr(QObject *parent)
|
||||
{
|
||||
mDestFolder = CFG->value("download/dir", QDir::homePath() + "/.local/spark-store/downloads")
|
||||
.toString();
|
||||
mDestFolder = CFG->value("dirs/download", "%1/.local/spark-store/downloads")
|
||||
.toString().arg(QDir::homePath());
|
||||
|
||||
QDir dest(mDestFolder);
|
||||
if(!dest.exists())
|
||||
QDir().mkdir(mDestFolder);
|
||||
|
||||
// Distribution servers
|
||||
QString srvPaths = CFG->value("download/servers", "https://d.store.deepinos.org/").toString();
|
||||
QString srvPaths = CFG->value("download/servers", "https://d1.store.deepinos.org.cn/;;"
|
||||
"https://d2.store.deepinos.org.cn/;;"
|
||||
"https://d3.store.deepinos.org.cn/;;"
|
||||
"https://d4.store.deepinos.org.cn/;;"
|
||||
"https://d5.store.deepinos.org.cn/").toString();
|
||||
mServers = srvPaths.split(";;");
|
||||
|
||||
mCurrentDownloadId = -1;
|
||||
@@ -76,7 +80,7 @@ void SpkDownloadMgr::SetDestinationFolder(QString path)
|
||||
}
|
||||
|
||||
bool SpkDownloadMgr::StartNewDownload(QString path, int downloadId)
|
||||
{
|
||||
{
|
||||
if(mCurrentDownloadId != -1)
|
||||
return false; // Already downloading something
|
||||
|
||||
@@ -87,16 +91,34 @@ bool SpkDownloadMgr::StartNewDownload(QString path, int downloadId)
|
||||
info = GetRemoteFileInfo(mServers[i] + path);
|
||||
// TODO: Mark dead servers as unusable so they don't get scheduled first?
|
||||
}
|
||||
if(info.Size == -1) return false; // If all servers failed then we say it's a failure
|
||||
if(info.Size == -1)
|
||||
{
|
||||
sNotify(tr("Server request failure, %1 cannot be downloaded.").arg(SpkUtils::CutFileName(path)));
|
||||
sErr(tr("SpkDownloadMgr: all start requests failed for %1.").arg(path));
|
||||
return false; // If all servers failed then we say it's a failure
|
||||
}
|
||||
|
||||
mCurrentRemoteFileInfo = info;
|
||||
mActiveWorkerCount = 0;
|
||||
|
||||
// Create the destination file.
|
||||
mDestFile.close();
|
||||
if(mDestFile.isOpen())
|
||||
mDestFile.close();
|
||||
if(!SpkUtils::EnsureDirExists(mDestFolder))
|
||||
{
|
||||
sNotify(tr("Cannot create download destination folder, download cannot start."));
|
||||
sErr(tr("SpkDownloadMgr: Download directory %1 cannot be created.").arg(mDestFolder));
|
||||
return false;
|
||||
}
|
||||
mDestFile.setFileName(mDestFolder + '/' + SpkUtils::CutFileName(path));
|
||||
if(!mDestFile.open(QFile::ReadWrite))
|
||||
{
|
||||
sNotify(tr("Cannot write to destination file, download cannot start."));
|
||||
sErr(tr("SpkDownloadMgr: Download destination file %1 cannot be opened with mode %2.")
|
||||
.arg(mDestFile.fileName())
|
||||
.arg(mDestFile.openMode()));
|
||||
return false;
|
||||
}
|
||||
|
||||
mCurrentRemotePath = path;
|
||||
|
||||
@@ -150,6 +172,8 @@ bool SpkDownloadMgr::StartNewDownload(QString path, int downloadId)
|
||||
|
||||
mProgressEmitterTimer.start();
|
||||
|
||||
mCurrentDownloadId = downloadId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -180,9 +204,9 @@ bool SpkDownloadMgr::CancelCurrentDownload()
|
||||
{
|
||||
sErr(tr("SpkDownloadMgr: Cannot remove destination file %1 of a cancelled task")
|
||||
.arg(mDestFile.fileName()));
|
||||
SpkUi::Popup->Show(tr("The destination file of the cancelled task can't be deleted!"));
|
||||
sNotify(tr("The destination file of the cancelled task can't be deleted!"));
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpkDownloadMgr::WorkerFinish()
|
||||
@@ -216,29 +240,7 @@ void SpkDownloadMgr::WorkerFinish()
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed here! Update our offset and required bytes count etc.
|
||||
worker.BeginOffset += worker.BytesRecvd;
|
||||
worker.BytesNeeded -= worker.BytesRecvd;
|
||||
worker.BytesRecvd = 0;
|
||||
|
||||
if(reply->property("failCount").toInt() > MaximumThreadRetryCount)
|
||||
{
|
||||
// Failed too many times, this server is probably down or really bad condition.
|
||||
// Schedule it on other servers.
|
||||
reply->deleteLater();
|
||||
worker.Reply = nullptr;
|
||||
mFailureRetryQueue.enqueue(worker);
|
||||
return;
|
||||
}
|
||||
|
||||
// We can still retry.
|
||||
worker.Reply =
|
||||
STORE->SendDownloadRequest(mServers[id] + mCurrentRemotePath,
|
||||
worker.BeginOffset,
|
||||
worker.BeginOffset + worker.BytesNeeded);
|
||||
LinkReplyWithMe(worker.Reply);
|
||||
worker.Reply->setProperty("failCount", reply->property("failCount").toInt() + 1);
|
||||
reply->deleteLater();
|
||||
ProcessWorkerError(worker, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,11 +256,49 @@ void SpkDownloadMgr::WorkerDownloadProgress()
|
||||
mDownloadedBytes += replyData.size();
|
||||
}
|
||||
|
||||
void SpkDownloadMgr::WorkerError(QNetworkReply::NetworkError)
|
||||
{
|
||||
QNetworkReply *reply = static_cast<QNetworkReply*>(sender());
|
||||
int id = reply->property("workerId").toInt();
|
||||
DownloadWorker &worker = mScheduledWorkers[id];
|
||||
|
||||
ProcessWorkerError(worker, id);
|
||||
}
|
||||
|
||||
void SpkDownloadMgr::ProgressTimer()
|
||||
{
|
||||
emit DownloadProgressed(mDownloadedBytes, mCurrentRemoteFileInfo.Size, mCurrentDownloadId);
|
||||
}
|
||||
|
||||
void SpkDownloadMgr::ProcessWorkerError(DownloadWorker &worker, int id)
|
||||
{
|
||||
auto reply = worker.Reply;
|
||||
|
||||
// Update our offset and required bytes count etc.
|
||||
worker.BeginOffset += worker.BytesRecvd;
|
||||
worker.BytesNeeded -= worker.BytesRecvd;
|
||||
worker.BytesRecvd = 0;
|
||||
|
||||
if(reply->property("failCount").toInt() > MaximumThreadRetryCount)
|
||||
{
|
||||
// Failed too many times, this server is probably down or really bad condition.
|
||||
// Schedule it on other servers.
|
||||
reply->deleteLater();
|
||||
worker.Reply = nullptr;
|
||||
mFailureRetryQueue.enqueue(worker);
|
||||
return;
|
||||
}
|
||||
|
||||
// We can still retry.
|
||||
worker.Reply =
|
||||
STORE->SendDownloadRequest(reply->url(),
|
||||
worker.BeginOffset,
|
||||
worker.BeginOffset + worker.BytesNeeded);
|
||||
LinkReplyWithMe(worker.Reply);
|
||||
worker.Reply->setProperty("failCount", reply->property("failCount").toInt() + 1);
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void SpkDownloadMgr::LinkReplyWithMe(QNetworkReply *reply)
|
||||
{
|
||||
mActiveWorkerCount++; // Each time you spin up a request you must do this so it's ok to do it here
|
||||
|
||||
+6
-6
@@ -7,6 +7,7 @@
|
||||
#include "spklogging.h"
|
||||
#include "spkmsgbox.h"
|
||||
#include "spkuimsg.h"
|
||||
#include "spkutils.h"
|
||||
|
||||
SpkLogger *SpkLogger::Instance = nullptr;
|
||||
|
||||
@@ -42,12 +43,11 @@ void SpkLogger::Initialize(QString suggestPath)
|
||||
}
|
||||
mLogPath = QDir::homePath() + "/.local/share/spark-store/logs/default.log";
|
||||
QString path = mLogPath.section('/', 1, -2, QString::SectionIncludeLeadingSep);
|
||||
if(!QDir().exists(path))
|
||||
if(!QDir().mkpath(path))
|
||||
{
|
||||
SpkLogger::Error(QObject::tr("Log directory \"%1\" cannot be created.").arg(path));
|
||||
return;
|
||||
}
|
||||
if(!SpkUtils::EnsureDirExists(path))
|
||||
{
|
||||
SpkLogger::Error(QObject::tr("Log directory \"%1\" cannot be created.").arg(path));
|
||||
return;
|
||||
}
|
||||
|
||||
mLogFile.setFileName(mLogPath);
|
||||
mLogFile.open(QFile::WriteOnly | QFile::Append);
|
||||
|
||||
+2
-2
@@ -12,8 +12,8 @@ SpkResource* SpkResource::Instance = nullptr;
|
||||
// clazy:excludeall=container-anti-pattern
|
||||
|
||||
SpkResource::SpkResource(QObject *parent) : QObject(parent),
|
||||
mMaximumConcurrent(CFG->value("download/resource_concurrent_count", 5).toInt()),
|
||||
mCacheDirectory(CFG->value("cache_directory", "%1/.cache/spark-store/res/")
|
||||
mMaximumConcurrent(CFG->value("resource/concurrent", 5).toInt()),
|
||||
mCacheDirectory(CFG->value("dirs/cache", "%1/.cache/spark-store/res/")
|
||||
.toString()
|
||||
.arg(QDir::homePath()))
|
||||
{
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ SpkStore::SpkStore(bool aCli, QString &aLogPath)
|
||||
|
||||
// Initialize URL
|
||||
mApiRequestUrl = mCfg->value("url/api", "https://store.deepinos.org/api/").toString();
|
||||
mResourceRequestUrl = mCfg->value("url/res", "http://d.deepinos.org.cn/").toString();
|
||||
mResourceRequestUrl = mCfg->value("url/res", "http://img.store.deepinos.org.cn/").toString();
|
||||
|
||||
|
||||
mUserAgentStr = QString("Spark-Store/%1 Distro/%2")
|
||||
|
||||
+20
-10
@@ -2,6 +2,7 @@
|
||||
#include <QDebug>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QDir>
|
||||
#include "spkutils.h"
|
||||
|
||||
void SpkUtils::VerifySingleRequest(QPointer<QNetworkReply> aReply)
|
||||
@@ -20,7 +21,7 @@ QString SpkUtils::GetDistroName()
|
||||
osRelease.value("BUILD_ID", "Unknown Build").toString();
|
||||
}
|
||||
|
||||
bool SpkUtils::VerifyReplyJson(QNetworkReply *aReply, QJsonValue &aRetDoc)
|
||||
int SpkUtils::VerifyReplyJson(QNetworkReply *aReply, QJsonValue &aRetDoc)
|
||||
{
|
||||
QJsonParseError err;
|
||||
QByteArray rawjson = aReply->readAll();
|
||||
@@ -29,17 +30,15 @@ bool SpkUtils::VerifyReplyJson(QNetworkReply *aReply, QJsonValue &aRetDoc)
|
||||
QJsonObject replyObject;
|
||||
if(err.error != QJsonParseError::NoError)
|
||||
{
|
||||
sNotify(QObject::tr("Failed to parse server reply! Error %1.").arg(err.error));
|
||||
sErr(QObject::tr("VerifyReplyJson: returned JSON of request to %1 is unreadable.")
|
||||
.arg(aReply->url().toString()));
|
||||
return false;
|
||||
return err.error;
|
||||
}
|
||||
if(!ret.isObject())
|
||||
{
|
||||
sNotify(QObject::tr("Server sent back an invalid response."));
|
||||
sErr(QObject::tr("VerifyReplyJson: returned JSON of request to %1 is not an Object.")
|
||||
.arg(aReply->url().toString()));
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
replyObject = ret.object();
|
||||
if(!replyObject.contains("code"))
|
||||
@@ -57,22 +56,22 @@ bool SpkUtils::VerifyReplyJson(QNetworkReply *aReply, QJsonValue &aRetDoc)
|
||||
}
|
||||
else if(OpRetCode.toInt() != 0)
|
||||
{
|
||||
sNotify(QObject::tr("Server sent back an failure message; code: %1.")
|
||||
sNotify(QObject::tr("VerifyReplyJson: Server sent back an failure message; code: %1.")
|
||||
.arg(OpRetCode.toInt()));
|
||||
sErr(QObject::tr("VerifyReplyJson: Request to %1 failed with code %2.")
|
||||
.arg(aReply->url().toString()).arg(OpRetCode.toInt()));
|
||||
return false;
|
||||
return OpRetCode.toInt();
|
||||
}
|
||||
}
|
||||
if(!replyObject.contains("data"))
|
||||
{
|
||||
sNotify(QObject::tr("Server did not reply with any data."));
|
||||
sNotify(QObject::tr("VerifyReplyJson: Server did not reply with any data."));
|
||||
sErr(QObject::tr("VerifyReplyJson: Reply of request to %1 didn't include any data.")
|
||||
.arg(aReply->url().toString()));
|
||||
return false;
|
||||
return -2;
|
||||
}
|
||||
aRetDoc = replyObject.value("data");
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SpkUtils::DeleteReplyLater(QNetworkReply *aReply)
|
||||
@@ -100,3 +99,14 @@ QString SpkUtils::BytesToSize(size_t s, int prec)
|
||||
return QString::number(double (s) / (1 << 10), 'f', prec) + " KB";
|
||||
return QString::number(s) + " B";
|
||||
}
|
||||
|
||||
bool SpkUtils::EnsureDirExists(QString path)
|
||||
{
|
||||
QDir dir;
|
||||
|
||||
if(!dir.exists(path))
|
||||
if(!dir.mkpath(path))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user