#include "downloadworker.h" #include #include #include #include DownloadController::DownloadController(QObject *parent) { Q_UNUSED(parent) // 初始化默认域名 domains.clear(); domains.append("d.store.deepinos.org.cn"); /* domains = { "d1.store.deepinos.org.cn", "d2.store.deepinos.org.cn", "d3.store.deepinos.org.cn", "d4.store.deepinos.org.cn", "d5.store.deepinos.org.cn" }; */ this->threadNum = domains.size(); } void DownloadController::setFilename(QString filename) { this->filename = filename; } bool checkMeatlink(QString metaUrl) { QFile metaStatus("/tmp/spark-store/metaStatus.txt"); if (metaStatus.exists()) { metaStatus.remove(); } system("curl -I -s --connect-timeout 5 " + metaUrl.toUtf8() + " -w %{http_code} |tail -n1 > /tmp/spark-store/metaStatus.txt"); if (metaStatus.open(QFile::ReadOnly) && QString(metaStatus.readAll()).toUtf8() == "200") { metaStatus.remove(); return true; } return false; } void gennerateDomain(QVector &domains) { QFile serverList(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/server.list"); if (serverList.open(QFile::ReadOnly)) { QStringList list = QString(serverList.readAll()).trimmed().split("\n"); qDebug() << list << list.size(); domains.clear(); for (int i = 0; i < list.size(); i++) { if (list.at(i).contains("镜像源 Download only") && i + 1 < list.size()) { for (int j = i + 1; j < list.size(); j++) { domains.append(list.at(j)); } break; } } if (domains.size() == 0) { domains.append("d.store.deepinos.org.cn"); } } } /** * @brief 开始下载 */ void DownloadController::startDownload(const QString &url) { // 获取下载任务信息 fileSize = getFileSize(url); if (fileSize == 0) { emit errorOccur("文件大小获取失败"); return; } QtConcurrent::run([=]() { QString metaUrl = url + ".metalink"; qDebug() << "metalink" << metaUrl; bool useMetalink = false; if (checkMeatlink(metaUrl)) { useMetalink = true; qDebug() << "useMetalink:" << useMetalink; } else { gennerateDomain(domains); // qDebug() << domains << domains.size(); } QString aria2Command = "-d"; QString aria2Urls = ""; QString aria2Verbose = "--summary-interval=1"; QString aria2SizePerThreads = "--min-split-size=1M"; QString aria2NoConfig = "--no-conf"; QString aria2NoSeeds = "--seed-time=0"; QStringList command; QString downloadDir = "/tmp/spark-store/"; QString aria2ConnectionPerServer = "--max-connection-per-server=1"; QString aria2ConnectionMax = "--max-concurrent-downloads=16"; QString aria2DNSCommand = "--async-dns-server=119.29.29.29,223.5.5.5"; if (useMetalink) { command.append(metaUrl.toUtf8()); } else { for (int i = 0; i < domains.size(); i++) { command.append(replaceDomain(url, domains.at(i)).replace("+","%2B").toUtf8()); //对+进行转译,避免oss出错 } } qint64 downloadSizeRecord = 0; QString speedInfo = ""; QString percentInfo = ""; command.append(aria2Command.toUtf8()); command.append(downloadDir.toUtf8()); command.append(aria2Verbose.toUtf8()); command.append(aria2NoConfig.toUtf8()); command.append(aria2SizePerThreads.toUtf8()); command.append(aria2ConnectionPerServer.toUtf8()); command.append(aria2ConnectionMax.toUtf8()); command.append(aria2DNSCommand.toUtf8()); if (useMetalink) { command.append(aria2NoSeeds.toUtf8()); } qDebug() << command; bool downloadSuccess = true; QProcess cmd; cmd.setProcessChannelMode(QProcess::MergedChannels); cmd.setProgram("aria2c"); cmd.setArguments(command); cmd.start(); cmd.waitForStarted(-1); //等待启动完成 connect(&cmd, &QProcess::readyReadStandardOutput, [&]() { //通过读取输出计算下载速度 QString message = cmd.readAllStandardOutput().data(); // qDebug() << message; message = message.replace(" ", ""); QStringList list; qint64 downloadSize = 0; int downloadSizePlace1 = message.indexOf("("); int downloadSizePlace2 = message.indexOf(")"); int speedPlace1 = message.indexOf("DL:"); int speedPlace2 = message.indexOf("ETA"); if (downloadSizePlace1 != -1 && downloadSizePlace2 != -1) { percentInfo = message.mid(downloadSizePlace1 + 1, downloadSizePlace2 - downloadSizePlace1 - 1).replace("%", ""); if (percentInfo != "s") { int percentInfoNumber = percentInfo.toUInt(); downloadSize = percentInfoNumber * fileSize / 100; } } if (speedPlace1 != -1 && speedPlace2 != -1 && speedPlace2 - speedPlace1 <= 15) { speedInfo = message.mid(speedPlace1 + 3, speedPlace2 - speedPlace1 - 3); speedInfo += "/s"; } // qDebug() << percentInfo << speedInfo; if (downloadSize >= downloadSizeRecord) { downloadSizeRecord = downloadSize; } if (percentInfo == "OK") { finished = true; emit downloadProcess("", fileSize, fileSize); qDebug() << "finished:" << finished; } else { emit downloadProcess(speedInfo, downloadSizeRecord, fileSize); } }); connect(&cmd, &QProcess::readyReadStandardError, [&]() { emit errorOccur(cmd.readAllStandardError().data()); downloadSuccess = false; cmd.close(); }); pidNumber = cmd.processId(); cmd.waitForFinished(-1); cmd.close(); if(!downloadSuccess) { return; } // 统计下载量 QString SenderdPath = "/opt/durapps/spark-store/bin/ss-feedback/sender-d"; /* * https://en.wikipedia.org/wiki/HD_70642 * HD 70642 is a star with an exoplanetary companion in the southern constellation of Puppis. */ QProcess mailProcess; mailProcess.start(SenderdPath.toUtf8(), QStringList() << metaUrl << "HD70642"); mailProcess.waitForStarted(); mailProcess.waitForFinished(3000); mailProcess.close(); emit downloadFinished(); }); } /** * @brief 停止下载 */ void DownloadController::stopDownload() { if (pidNumber < 0) { return; } // 实现下载进程退出 QString killCmd = QString("kill -9 %1").arg(pidNumber); system(killCmd.toUtf8()); qDebug() << "kill aria2!"; pidNumber = -1; } qint64 DownloadController::getFileSize(const QString &url) { // 已经无需使用 qtnetwork 再获取 filesize,完全交给 aria2 来计算进度。 为保证兼容性,故保留此函数。 qDebug() << "Begin download:" << url; qint64 fileSize = 10000; return fileSize; } QString DownloadController::replaceDomain(const QString &url, const QString domain) { QRegularExpression regex(R"((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9])"); if (regex.match(url).hasMatch()) { return QString(url).replace(regex.match(url).captured(), domain); } return url; }