- Fix bug with resume downloading - truncate "downloading" file if resume info is invalid;

- Reserve size for "downloading" file;
- Process FileWriter exceptions in download initializing;
This commit is contained in:
vng 2012-10-29 21:24:17 +03:00 committed by Alex Zolotarev
parent 4ebdce7bb3
commit 74f36cfc00
2 changed files with 52 additions and 31 deletions

View file

@ -212,17 +212,7 @@ class FileHttpRequest : public HttpRequest, public IHttpThreadCallback
if (m_status != EInProgress)
{
try
{
m_writer.reset();
}
catch (Writer::Exception const & ex)
{
LOG(LWARNING, ("Can't close file correctly. There is not enough space, possibly."));
ASSERT_EQUAL ( m_status, EFailed, () );
m_status = EFailed;
}
CloseWriter();
// clean up resume file with chunks range on success
if (m_status == ECompleted)
@ -242,6 +232,20 @@ class FileHttpRequest : public HttpRequest, public IHttpThreadCallback
}
}
void CloseWriter()
{
try
{
m_writer.reset();
}
catch (Writer::Exception const & ex)
{
LOG(LWARNING, ("Can't close file correctly. There is not enough space, possibly."));
m_status = EFailed;
}
}
public:
FileHttpRequest(vector<string> const & urls, string const & filePath, int64_t fileSize,
CallbackT const & onFinish, CallbackT const & onProgress,
@ -251,13 +255,29 @@ public:
{
ASSERT ( !urls.empty(), () );
// Open file here. Avoid throwing exceptions from constructor's initialization list.
m_writer.reset(new FileWriter(filePath + DOWNLOADING_FILE_EXTENSION, FileWriter::OP_WRITE_EXISTING));
// Load resume downloading information.
m_progress.first = m_strategy.LoadOrInitChunks(m_filePath + RESUME_FILE_EXTENSION,
fileSize, chunkSize);
m_progress.second = fileSize;
FileWriter::Op openMode = FileWriter::OP_WRITE_TRUNCATE;
if (m_progress.first != 0)
{
// Check that resume information is correct with existing file.
uint64_t size;
if (my::GetFileSize(filePath + DOWNLOADING_FILE_EXTENSION, size) && size == fileSize)
openMode = FileWriter::OP_WRITE_EXISTING;
else
m_strategy.InitChunks(fileSize, chunkSize);
}
// Create file and reserve needed size.
scoped_ptr<FileWriter> writer(new FileWriter(filePath + DOWNLOADING_FILE_EXTENSION, openMode));
writer->Reserve(fileSize);
// Assign here, because previous functions can throw an exception.
m_writer.swap(writer);
#ifdef OMIM_OS_IPHONE
m_writer->Flush();
DisableBackupForFile(filePath + DOWNLOADING_FILE_EXTENSION);
@ -274,12 +294,12 @@ public:
if (m_status == EInProgress)
{
// means that client canceled download process, so delete all temporary files
m_writer.reset();
CloseWriter();
if (m_doCleanProgressFiles)
{
my::DeleteFileX(m_filePath + DOWNLOADING_FILE_EXTENSION);
my::DeleteFileX(m_filePath + RESUME_FILE_EXTENSION);
(void)my::DeleteFileX(m_filePath + DOWNLOADING_FILE_EXTENSION);
(void)my::DeleteFileX(m_filePath + RESUME_FILE_EXTENSION);
}
}
}
@ -328,29 +348,26 @@ namespace
};
}
HttpRequest * HttpRequest::GetFile(vector<string> const & urls, string const & filePath, int64_t fileSize,
HttpRequest * HttpRequest::GetFile(vector<string> const & urls,
string const & filePath, int64_t fileSize,
CallbackT const & onFinish, CallbackT const & onProgress,
int64_t chunkSize, bool doCleanProgressFiles)
int64_t chunkSize, bool doCleanOnCancel)
{
FileHttpRequest * p = 0;
try
{
p = new FileHttpRequest(urls, filePath, fileSize, onFinish, onProgress, chunkSize, doCleanProgressFiles);
return new FileHttpRequest(urls, filePath, fileSize, onFinish, onProgress, chunkSize, doCleanOnCancel);
}
catch (FileWriter::Exception const & e)
{
// Can't create file for writing.
// Can't create or open file for writing.
LOG(LERROR, ("Can't create FileHttpRequest for", filePath, e.what()));
delete p;
p = 0;
// Mark the end of download with error.
ErrorHttpRequest error(filePath);
onFinish(error);
}
return p;
return 0;
}
}
} // namespace downloader

View file

@ -22,7 +22,7 @@ public:
/// <current, total>, total can be -1 if size is unknown
typedef pair<int64_t, int64_t> ProgressT;
typedef function<void(HttpRequest &)> CallbackT;
typedef function<void (HttpRequest &)> CallbackT;
protected:
StatusT m_status;
@ -44,16 +44,20 @@ public:
static HttpRequest * Get(string const & url,
CallbackT const & onFinish,
CallbackT const & onProgress = CallbackT());
/// Content-type for request is always "application/json"
static HttpRequest * PostJson(string const & url, string const & postData,
CallbackT const & onFinish,
CallbackT const & onProgress = CallbackT());
static HttpRequest * GetFile(vector<string> const & urls, string const & filePath,
int64_t projectedFileSize,
/// Download file to filePath.
/// @param[in] fileSize Correct file size (needed for resuming and reserving).
static HttpRequest * GetFile(vector<string> const & urls,
string const & filePath, int64_t fileSize,
CallbackT const & onFinish,
CallbackT const & onProgress = CallbackT(),
int64_t chunkSize = 512 * 1024,
bool doCleanProgressFiles = true);
bool doCleanOnCancel = true);
};
} // namespace downloader