Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Zolotarev <deathbaba@gmail.com>2011-11-09 20:09:35 +0400
committerAlex Zolotarev <alex@maps.me>2015-09-23 01:27:32 +0300
commit2dc0ca689c0ea24b5e8b28e89cabbf2bbe945fb5 (patch)
treefb7499f1538ce1e32e237456d247d1d75abef9ab /platform/http_request.cpp
parent710aa71023fe23a8b7f3d7f2e578438155eee15c (diff)
[downloader] Added resume support for chunked downloads
Diffstat (limited to 'platform/http_request.cpp')
-rw-r--r--platform/http_request.cpp69
1 files changed, 65 insertions, 4 deletions
diff --git a/platform/http_request.cpp b/platform/http_request.cpp
index 63174a80a8..b1af6b8a80 100644
--- a/platform/http_request.cpp
+++ b/platform/http_request.cpp
@@ -6,7 +6,10 @@
#include "../base/thread.hpp"
#endif
-#include "../coding/file_writer.hpp"
+#include "../base/std_serialization.hpp"
+
+#include "../coding/file_writer_stream.hpp"
+#include "../coding/file_reader_stream.hpp"
#include "../std/scoped_ptr.hpp"
@@ -102,6 +105,9 @@ class FileHttpRequest : public HttpRequest, public IHttpThreadCallback
string m_filePath;
scoped_ptr<FileWriter> m_writer;
+ /// Used to save not downloaded chunks for later resume not so often
+ size_t m_goodChunksCount;
+
ChunksDownloadStrategy::ResultT StartThreads()
{
string url;
@@ -150,7 +156,7 @@ class FileHttpRequest : public HttpRequest, public IHttpThreadCallback
if (result == ChunksDownloadStrategy::EDownloadSucceeded
|| result == ChunksDownloadStrategy::ENoFreeServers)
{
- m_progress.first += m_strategy.ChunkSize();
+ m_progress.first += (endRange - begRange);
if (m_onProgress)
m_onProgress(*this);
}
@@ -158,7 +164,17 @@ class FileHttpRequest : public HttpRequest, public IHttpThreadCallback
if (result == ChunksDownloadStrategy::EDownloadFailed)
m_status = EFailed;
else if (result == ChunksDownloadStrategy::EDownloadSucceeded)
+ {
m_status = ECompleted;
+ ++m_goodChunksCount;
+ if (m_strategy.ChunksLeft().empty())
+ FileWriter::DeleteFileX(m_filePath + ".resume");
+ else
+ {
+ if (m_goodChunksCount % 10 == 0)
+ SaveRanges(m_filePath + ".resume", m_strategy.ChunksLeft());
+ }
+ }
if (m_status != EInProgress)
{
@@ -167,15 +183,60 @@ class FileHttpRequest : public HttpRequest, public IHttpThreadCallback
}
}
+ /// @return true if ranges are present and loaded
+ static bool LoadRanges(string const & file, ChunksDownloadStrategy::RangesContainerT & ranges)
+ {
+ ranges.clear();
+ try
+ {
+ FileReaderStream frs(file);
+ frs >> ranges;
+ }
+ catch (std::exception const &)
+ {
+ return false;
+ }
+ return !ranges.empty();
+ }
+
+ static void SaveRanges(string const & file, ChunksDownloadStrategy::RangesContainerT const & ranges)
+ {
+ FileWriterStream fws(file);
+ fws << ranges;
+ }
+
+ struct CalcRanges
+ {
+ int64_t & m_summ;
+ CalcRanges(int64_t & summ) : m_summ(summ) {}
+ void operator()(ChunksDownloadStrategy::RangeT const & range)
+ {
+ m_summ += (range.second - range.first);
+ }
+ };
+
public:
FileHttpRequest(vector<string> const & urls, string const & filePath, int64_t fileSize,
CallbackT onFinish, CallbackT onProgress, int64_t chunkSize)
: HttpRequest(onFinish, onProgress), m_strategy(urls, fileSize, chunkSize),
- m_filePath(filePath), m_writer(new FileWriter(filePath, FileWriter::OP_WRITE_EXISTING))
+ m_filePath(filePath), m_writer(new FileWriter(filePath, FileWriter::OP_WRITE_EXISTING)),
+ m_goodChunksCount(0)
{
+ ASSERT_GREATER(fileSize, 0, ("At the moment only known file sizes are supported"));
ASSERT(!urls.empty(), ("Urls list shouldn't be empty"));
- // store expected file size for future checks
m_progress.second = fileSize;
+
+ // Resume support - load chunks which should be downloaded (if they're present)
+ ChunksDownloadStrategy::RangesContainerT ranges;
+ if (LoadRanges(filePath + ".resume", ranges))
+ {
+ // fix progress
+ int64_t sizeLeft = 0;
+ for_each(ranges.begin(), ranges.end(), CalcRanges(sizeLeft));
+ m_progress.first = fileSize - sizeLeft;
+ m_strategy.SetChunksToDownload(ranges);
+ }
+
StartThreads();
}