diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c9cf983..f8f76c8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,6 +184,7 @@ logic/ModList.h # network stuffs logic/net/DownloadJob.h logic/net/NetWorker.h +logic/net/HttpMetaCache.h # legacy instances logic/LegacyInstance.h @@ -251,6 +252,7 @@ logic/ModList.cpp # network stuffs - to be moved into a depend lib ~_~ logic/net/NetWorker.cpp logic/net/DownloadJob.cpp +logic/net/HttpMetaCache.cpp # legacy instances logic/LegacyInstance.cpp diff --git a/logic/net/DownloadJob.cpp b/logic/net/DownloadJob.cpp index 5c8ed4b9..b87d3dc9 100644 --- a/logic/net/DownloadJob.cpp +++ b/logic/net/DownloadJob.cpp @@ -143,10 +143,12 @@ void DownloadJob::partSucceeded ( int index ) { if(num_failed) { + qDebug() << "Download JOB failed: " << this; emit failed(); } else { + qDebug() << "Download JOB succeeded: " << this; emit succeeded(); } } @@ -157,14 +159,8 @@ void DownloadJob::partFailed ( int index ) num_failed++; if(num_failed + num_succeeded == downloads.size()) { - if(num_failed) - { - emit failed(); - } - else - { - emit succeeded(); - } + qDebug() << "Download JOB failed: " << this; + emit failed(); } } @@ -176,6 +172,7 @@ void DownloadJob::partProgress ( int index, qint64 bytesReceived, qint64 bytesTo void DownloadJob::start() { + qDebug() << "Download JOB started: " << this; for(auto iter: downloads) { connect(iter.data(), SIGNAL(succeeded(int)), SLOT(partSucceeded(int))); diff --git a/logic/net/HttpMetaCache.cpp b/logic/net/HttpMetaCache.cpp new file mode 100644 index 00000000..87741dc9 --- /dev/null +++ b/logic/net/HttpMetaCache.cpp @@ -0,0 +1,131 @@ +#include "HttpMetaCache.h" +#include +#include +#include +#include +#include +#include +#include +#include + +HttpMetaCache::HttpMetaCache(QString path) +{ + m_index_file = path; +} +HttpMetaCache::~HttpMetaCache() +{ + Save(); +} + +void HttpMetaCache::addEntry ( QString base, QString resource_path, QString etag ) +{ + // no base. no base path. can't store + if(!m_entries.contains(base)) + return; + QString real_path = PathCombine(m_entries[base].base_path, resource_path); + QFileInfo finfo(real_path); + + // just ignore it, it's garbage if it's not a proper file + if(!finfo.isFile() || !finfo.isReadable()) + { + // TODO: log problem + return; + } + + Save(); +} + +void HttpMetaCache::addBase ( QString base, QString base_root ) +{ + // TODO: report error + if(m_entries.contains(base)) + return; + // TODO: check if the base path is valid + EntryMap foo; + foo.base_path = base_root; + m_entries[base] = foo; +} + +void HttpMetaCache::Load() +{ + QFile index(m_index_file); + if(!index.open(QIODevice::ReadOnly)) + return; + + QJsonDocument json = QJsonDocument::fromJson(index.readAll()); + if(!json.isObject()) + return; + auto root = json.object(); + // check file version first + auto version_val =root.value("version"); + if(!version_val.isString()) + return; + if(version_val.toString() != "1") + return; + + // read the entry array + auto entries_val =root.value("entries"); + if(!version_val.isArray()) + return; + QJsonArray array = json.array(); + for(auto element: array) + { + if(!element.isObject()); + return; + auto element_obj = element.toObject(); + QString base = element_obj.value("base").toString(); + if(!m_entries.contains(base)) + continue; + auto & entrymap = m_entries[base]; + auto foo = new MetaEntry; + foo->base = base; + QString path = foo->path = element_obj.value("path").toString(); + foo->md5sum = element_obj.value("md5sum").toString(); + foo->etag = element_obj.value("etag").toString(); + foo->last_changed_timestamp = element_obj.value("last_changed_timestamp").toDouble(); + entrymap.entry_list[path] = MetaEntryPtr( foo ); + } +} + +void HttpMetaCache::Save() +{ + QSaveFile tfile(m_index_file); + if(!tfile.open(QIODevice::WriteOnly | QIODevice::Truncate)) + return; + QJsonObject toplevel; + toplevel.insert("version",QJsonValue(QString("1"))); + QJsonArray entriesArr; + for(auto group : m_entries) + { + for(auto entry : group.entry_list) + { + QJsonObject entryObj; + entryObj.insert("base", QJsonValue(entry->base)); + entryObj.insert("path", QJsonValue(entry->path)); + entryObj.insert("md5sum", QJsonValue(entry->md5sum)); + entryObj.insert("etag", QJsonValue(entry->etag)); + entryObj.insert("last_changed_timestamp", QJsonValue(double(entry->last_changed_timestamp))); + entriesArr.append(entryObj); + } + } + toplevel.insert("entries",entriesArr); + QJsonDocument doc(toplevel); + QByteArray jsonData = doc.toJson(); + qint64 result = tfile.write(jsonData); + if(result == -1) + return; + if(result != jsonData.size()) + return; + tfile.commit(); +} + + +MetaEntryPtr HttpMetaCache::getEntryForResource ( QString base, QString resource_path ) +{ + if(!m_entries.contains(base)) + return MetaEntryPtr(); + auto & entrymap = m_entries[base]; + if(!entrymap.entry_list.contains(resource_path)) + return MetaEntryPtr(); + return entrymap.entry_list[resource_path]; +} diff --git a/logic/net/HttpMetaCache.h b/logic/net/HttpMetaCache.h new file mode 100644 index 00000000..161483ad --- /dev/null +++ b/logic/net/HttpMetaCache.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include + +struct MetaEntry +{ + QString base; + QString path; + QString md5sum; + QString etag; + quint64 last_changed_timestamp = 0; +}; + +typedef QSharedPointer MetaEntryPtr; + +class HttpMetaCache +{ +public: + // supply path to the cache index file + HttpMetaCache(QString path); + ~HttpMetaCache(); + MetaEntryPtr getEntryForResource(QString base, QString resource_path); + void addEntry(QString base, QString resource_path, QString etag); + void addBase(QString base, QString base_root); +private: + void Save(); + void Load(); + struct EntryMap + { + QString base_path; + QMap entry_list; + }; + QMap m_entries; + QString m_index_file; +}; \ No newline at end of file