diff --git a/platform/apple_download.h b/platform/apple_download.h deleted file mode 100644 index b67aa8c8a7..0000000000 --- a/platform/apple_download.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#import - -#include "download_manager.hpp" -#include "url_generator.hpp" -#include "../std/string.hpp" - -@interface AppleDownload : NSObject -{ - HttpStartParams m_params; - - string m_currentUrl; - UrlGenerator m_urlGenerator; - - FILE * m_file; - /// stores information from the server, can be zero - int64_t m_projectedFileSize; - NSURLConnection * m_connection; - - string m_receivedBuffer; -} - -- (void) dealloc; -- (std::string const &) Url; -- (BOOL) StartDownload: (HttpStartParams const &)params; -// Added because release from manager doesn't destroy it immediately... -- (void) Cancel; -@end diff --git a/platform/apple_download.mm b/platform/apple_download.mm deleted file mode 100644 index 14fbedd24c..0000000000 --- a/platform/apple_download.mm +++ /dev/null @@ -1,301 +0,0 @@ -#import "apple_download.h" - -#include "../base/logging.hpp" - -#include "../std/target_os.hpp" - -#ifdef OMIM_OS_IPHONE - #import -#endif - -#include "download_manager.hpp" -#include "platform.hpp" - -#define TIMEOUT_IN_SECONDS 15.0 - -static bool NeedToGenerateUrl(string const & url) -{ - return url.find("http://") != 0 && url.find("https://") != 0; -} - -@implementation AppleDownload - -- (string const &) Url -{ - return m_params.m_url; -} - -- (void) Cancel -{ - if (m_connection) - [m_connection cancel]; -} - -- (void) dealloc -{ - LOG(LDEBUG, ("destructor for url", m_params.m_url)); - if (m_connection) - { - [m_connection cancel]; - [m_connection release]; - } - // Non-zero means that download is canceled - if (m_file) - { - fclose(m_file); - if (!m_params.m_fileToSave.empty()) - remove((m_params.m_fileToSave + DOWNLOADING_FILE_EXTENSION).c_str()); - } - [super dealloc]; -} - -- (NSMutableURLRequest *) CreateRequest -{ - // Create the request. - NSMutableURLRequest * request = - [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithUTF8String:m_currentUrl.c_str()]] - cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:TIMEOUT_IN_SECONDS]; - if (m_file) - { - long long fileSize = ftello(m_file); - if (fileSize > 0) - { - LOG(LDEBUG, ("Resuming download for file", m_params.m_fileToSave + DOWNLOADING_FILE_EXTENSION, - "from position", fileSize)); - NSString * val = [[NSString alloc] initWithFormat: @"bytes=%qi-", fileSize]; - [request addValue:val forHTTPHeaderField:@"Range"]; - [val release]; - } - } - if (!m_params.m_contentType.empty()) - { - [request addValue:[NSString stringWithUTF8String: m_params.m_contentType.c_str()] forHTTPHeaderField:@"Content-Type"]; - } - if (!m_params.m_postData.empty()) - { - NSData * postData = [NSData dataWithBytes:m_params.m_postData.data() length:m_params.m_postData.size()]; - [request setHTTPBody:postData]; - [request setHTTPMethod:@"POST"]; - } - // set user-agent with unique client id only for mapswithme requests - if (m_currentUrl.find("mapswithme.com") != string::npos) - { - static string const uid = GetPlatform().UniqueClientId(); - [request addValue:[NSString stringWithUTF8String: uid.c_str()] forHTTPHeaderField:@"User-Agent"]; - } - return request; -} - -- (BOOL) StartDownload: (HttpStartParams const &)params -{ - m_params = params; - - if (!params.m_fileToSave.empty()) - { - // try to create file first - string const tmpFile = m_params.m_fileToSave + DOWNLOADING_FILE_EXTENSION; - m_file = fopen(tmpFile.c_str(), "ab"); - if (m_file == 0) - { - LOG(LERROR, ("Error opening file for download", tmpFile, strerror(errno))); - // notify observer about error and exit - if (m_params.m_finish) - { - HttpFinishedParams result; - result.m_url = m_params.m_url; - result.m_file = m_params.m_fileToSave; - result.m_error = EHttpDownloadCantCreateFile; - m_params.m_finish(result); - } - return NO; - } - } - - if (NeedToGenerateUrl(m_params.m_url)) - m_currentUrl = m_urlGenerator.PopNextUrl() + m_params.m_url; - else - m_currentUrl = m_params.m_url; - - // create the connection with the request and start loading the data - m_connection = [[NSURLConnection alloc] initWithRequest:[self CreateRequest] delegate:self]; - - if (m_connection == 0) - { - LOG(LERROR, ("Can't create connection for url", m_currentUrl)); - // notify observer about error and exit - if (m_params.m_finish) - { - HttpFinishedParams result; - result.m_url = m_params.m_url; - result.m_file = m_params.m_fileToSave; - result.m_error = EHttpDownloadNoConnectionAvailable; - m_params.m_finish(result); - } - return NO; - } - - return YES; -} - -- (void) connection: (NSURLConnection *)connection didReceiveResponse: (NSURLResponse *)response -{ - // This method is called when the server has determined that it - // has enough information to create the NSURLResponse. - - // check if this is OK (not a 404 or the like) - if ([response respondsToSelector:@selector(statusCode)]) - { - NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; - if (statusCode < 200 || statusCode > 299) - { - LOG(LWARNING, ("Received HTTP error, canceling download", statusCode)); - if (m_file) - { - long long fileSize = ftello(m_file); - fclose(m_file); - m_file = 0; - // delete file only if it's size is zero to resume download later - if (fileSize == 0) - remove((m_params.m_fileToSave + DOWNLOADING_FILE_EXTENSION).c_str()); - } - // notify user - if (m_params.m_finish) - { - HttpFinishedParams result; - result.m_url = m_params.m_url; - result.m_file = m_params.m_fileToSave; - result.m_error = statusCode == 404 ? EHttpDownloadFileNotFound : EHttpDownloadFailed; - m_params.m_finish(result); - } - // and selfdestruct... - GetDownloadManager().CancelDownload(m_params.m_url); - return; - } - } - -#ifdef OMIM_OS_IPHONE - // enable network activity indicator in top system toolbar - [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; -#endif - - m_projectedFileSize = [response expectedContentLength]; - // if server doesn't support resume, make sure we're downloading file from scratch - if (!m_params.m_fileToSave.empty() && m_projectedFileSize < 0) - { - fclose(m_file); - m_file = fopen((m_params.m_fileToSave + DOWNLOADING_FILE_EXTENSION).c_str(), "wb"); - } - LOG(LDEBUG, ("Projected download file size", m_projectedFileSize)); -} - -- (void) connection: (NSURLConnection *)connection didReceiveData: (NSData *)data -{ - // Append the new data - int64_t size = -1; - if (m_file) - { - fwrite([data bytes], 1, [data length], m_file); - size = ftello(m_file); - } - else - { - m_receivedBuffer.append(static_cast([data bytes]), [data length]); - size = m_receivedBuffer.size(); - } - if (m_params.m_progress) - { - HttpProgressT progress; - progress.m_url = m_params.m_url; - progress.m_current = size; - progress.m_total = m_projectedFileSize; - m_params.m_progress(progress); - } -} - -- (BOOL) shouldRetry: (NSError *)error -{ - NSInteger const code = [error code]; - return (code < 0 || code == 401 || code == 403 || code == 404) && NeedToGenerateUrl(m_params.m_url); -} - -- (void) connection: (NSURLConnection *)connection didFailWithError: (NSError *)error -{ - // inform the user - LOG(LWARNING, ("Connection failed for", m_currentUrl, [[error localizedDescription] cStringUsingEncoding:NSUTF8StringEncoding])); - - // retry connection if it's network-specific error - if ([self shouldRetry:error]) - { - string const newUrl = m_urlGenerator.PopNextUrl(); - if (!newUrl.empty()) - { - m_currentUrl = newUrl + m_params.m_url; - [m_connection release]; - // create the connection with the request and start loading the data - m_connection = [[NSURLConnection alloc] initWithRequest:[self CreateRequest] delegate:self]; - - if (m_connection) - return; // successfully restarted connection - - LOG(LWARNING, ("Can't retry connection")); - // notify observer about error and exit after this if-block - } - } - - if (m_file) - { - long long fileSize = ftello(m_file); - fclose(m_file); - m_file = 0; - // delete file only if it's size is zero to resume download later - if (fileSize == 0) - remove((m_params.m_fileToSave + DOWNLOADING_FILE_EXTENSION).c_str()); - } - - if (m_params.m_finish) - { - HttpFinishedParams result; - result.m_url = m_params.m_url; - result.m_file = m_params.m_fileToSave; - result.m_error = EHttpDownloadFailed; - m_params.m_finish(result); - } - - // and selfdestruct... - GetDownloadManager().CancelDownload(m_params.m_url); -} - -- (void) connectionDidFinishLoading: (NSURLConnection *)connection -{ - bool isLocked = false; - if (m_file) - { - // close file - fclose(m_file); - m_file = 0; - // remove temporary extension from downloaded file - remove(m_params.m_fileToSave.c_str()); - if (rename((m_params.m_fileToSave + DOWNLOADING_FILE_EXTENSION).c_str(), m_params.m_fileToSave.c_str())) - { - isLocked = true; - LOG(LERROR, ("Can't rename to file", m_params.m_fileToSave)); - // delete downloaded file - remove((m_params.m_fileToSave + DOWNLOADING_FILE_EXTENSION).c_str()); - } - else - LOG(LDEBUG, ("Successfully downloaded", m_params.m_url)); - } - if (m_params.m_finish) - { - HttpFinishedParams result; - result.m_url = m_params.m_url; - result.m_file = m_params.m_fileToSave; - result.m_data.swap(m_receivedBuffer); - result.m_error = isLocked ? EHttpDownloadFileIsLocked : EHttpDownloadOk; - m_params.m_finish(result); - } - // and selfdestruct... - GetDownloadManager().CancelDownload(m_params.m_url); -} - -@end diff --git a/platform/apple_download_manager.mm b/platform/apple_download_manager.mm deleted file mode 100644 index fd05256c08..0000000000 --- a/platform/apple_download_manager.mm +++ /dev/null @@ -1,110 +0,0 @@ -#include "download_manager.hpp" - -#include "../std/target_os.hpp" - -#include "../base/logging.hpp" - -#import "apple_download.h" -#ifdef OMIM_OS_IPHONE - #import "../iphone/Maps/Classes/MapsAppDelegate.h" - #import -#endif - -class AppleDownloadManager : public DownloadManager -{ - NSMutableArray * activeDownloads; - -public: - AppleDownloadManager() - { - activeDownloads = [[NSMutableArray alloc] init]; - } - - virtual ~AppleDownloadManager() - { - for (NSUInteger i = 0; i < [activeDownloads count]; ++i) - [[activeDownloads objectAtIndex:i] release]; - - [activeDownloads removeAllObjects]; - [activeDownloads release]; - } - - virtual void HttpRequest(HttpStartParams const & params) - { - // check if download is already active - for (NSUInteger i = 0; i < [activeDownloads count]; ++i) - { - AppleDownload * download = [activeDownloads objectAtIndex:i]; - if ([download Url] == params.m_url) - { - LOG(LWARNING, ("Download is already active for url %s", params.m_url)); - return; - } - } - - AppleDownload * download = [[AppleDownload alloc] init]; - if ([download StartDownload:params]) - { - // save download in array to cancel it later if necessary - [activeDownloads addObject:download]; -#ifdef OMIM_OS_IPHONE - // prevent device from going to standby - [[MapsAppDelegate theApp] disableStandby]; -#endif - } - else - { - // free memory - [download release]; - } - } - - /// @note Doesn't notify clients on canceling! - virtual void CancelDownload(string const & url) - { -#ifdef OMIM_OS_IPHONE - // disable network activity indicator in top system toolbar - // note that this method is called also from successful/failed download to "selfdestruct" below - [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; -#endif - - for (NSUInteger i = 0; i < [activeDownloads count]; ++i) - { - AppleDownload * download = [activeDownloads objectAtIndex:i]; - if ([download Url] == url) - { - [activeDownloads removeObjectAtIndex:i]; - [download Cancel]; - [download release]; - break; - } - } - -#ifdef OMIM_OS_IPHONE - // enable standby if no more downloads are left - if ([activeDownloads count] == 0) - [[MapsAppDelegate theApp] enableStandby]; -#endif - } - - virtual void CancelAllDownloads() - { -#ifdef OMIM_OS_IPHONE - // disable network activity indicator in top system toolbar - [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; -#endif - - for (NSUInteger i = 0; i < [activeDownloads count]; ++i) { - AppleDownload * download = [activeDownloads objectAtIndex:i]; - [download Cancel]; - [download release]; - } - [activeDownloads removeAllObjects]; - } -}; - -DownloadManager & GetDownloadManager() -{ - static AppleDownloadManager downloadManager; - return downloadManager; -} diff --git a/platform/download_manager.hpp b/platform/download_manager.hpp deleted file mode 100644 index 89dd3c79cc..0000000000 --- a/platform/download_manager.hpp +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "../std/stdint.hpp" -#include "../std/utility.hpp" -#include "../std/string.hpp" -#include "../std/function.hpp" - -/// Appended to all downloading files and removed after successful download -#define DOWNLOADING_FILE_EXTENSION ".downloading" - -/// Notifies client about donwload progress -struct HttpProgressT -{ - string m_url; - int64_t m_current; - int64_t m_total; - int64_t m_bytesPerSec; -}; -typedef function HttpProgressCallbackT; - -enum DownloadResultT -{ - EHttpDownloadOk, - EHttpDownloadFileNotFound, //!< HTTP 404 - EHttpDownloadFailed, - EHttpDownloadFileIsLocked, //!< downloaded file can't replace existing locked file - EHttpDownloadCantCreateFile, //!< file for downloading can't be created - EHttpDownloadNoConnectionAvailable -}; - -struct HttpFinishedParams -{ - string m_url; - string m_file; //!< if not empty, contains file with retrieved data - string m_data; //!< if not empty, contains received data - DownloadResultT m_error; -}; -typedef function HttpFinishedCallbackT; - -struct HttpStartParams -{ - string m_url; - string m_fileToSave; - HttpFinishedCallbackT m_finish; - HttpProgressCallbackT m_progress; - string m_contentType; - string m_postData; //!< if not empty, send POST instead of GET -}; - -/// Platform-dependent implementations should derive it -/// and implement pure virtual methods -class DownloadManager -{ -public: - virtual ~DownloadManager() {} - - /// By default, http resume feature is used for requests which contains out file - /// If url doesn't contain http:// or https:// Url_Generator is used for base server url - virtual void HttpRequest(HttpStartParams const & params) = 0; - /// @note Doesn't notifies clients on canceling! - virtual void CancelDownload(string const & url) = 0; - virtual void CancelAllDownloads() = 0; -}; - -extern "C" DownloadManager & GetDownloadManager(); diff --git a/platform/platform.pro b/platform/platform.pro index 253fdf56e5..17b9fbda2d 100644 --- a/platform/platform.pro +++ b/platform/platform.pro @@ -20,6 +20,7 @@ include($$ROOT_DIR/common.pri) HEADERS += wifi_info.hpp \ location_service.hpp !macx* { + QT *= network SOURCES += http_thread_qt.cpp HEADERS += http_thread_qt.hpp } @@ -44,33 +45,20 @@ include($$ROOT_DIR/common.pri) } macx*|iphone* { - HEADERS += apple_download.h \ - http_thread_apple.h - OBJECTIVE_SOURCES += apple_download.mm \ - apple_download_manager.mm \ - http_thread_apple.mm -} - -win32*|linux* { - QT *= network - HEADERS += qt_download_manager.hpp \ - qt_download.hpp - SOURCES += qt_download_manager.cpp \ - qt_download.cpp + HEADERS += http_thread_apple.h + OBJECTIVE_SOURCES += http_thread_apple.mm } # common sources for all platforms HEADERS += \ platform.hpp \ - download_manager.hpp \ location.hpp \ concurrent_runner.hpp \ preferred_languages.hpp \ settings.hpp \ video_timer.hpp \ languages.hpp \ - url_generator.hpp \ http_request.hpp \ http_thread_callback.hpp \ chunks_download_strategy.hpp \ @@ -80,6 +68,5 @@ SOURCES += \ settings.cpp \ video_timer.cpp \ languages.cpp \ - url_generator.cpp \ http_request.cpp \ chunks_download_strategy.cpp \ diff --git a/platform/platform_tests/download_test.cpp b/platform/platform_tests/download_test.cpp deleted file mode 100644 index e68988c251..0000000000 --- a/platform/platform_tests/download_test.cpp +++ /dev/null @@ -1,374 +0,0 @@ -#include "../../testing/testing.hpp" - -#include "../platform.hpp" -#include "../download_manager.hpp" - -#include "../../coding/file_writer.hpp" -#include "../../coding/file_reader.hpp" - -#include "../../std/bind.hpp" - -#include - -// file on the server contains "Test1" -#define TEST_FILE_URL1 "http://melnichek.ath.cx:34568/unit_tests/1.txt" -#define TEST_FILE_NAME1 "unit_test1.tmp" -// file on the server contains "Test2" -#define TEST_FILE_URL2 "http://melnichek.ath.cx:34568/unit_tests/2.txt" -#define TEST_FILE_NAME2 "unit_test2.tmp" -// file on the server contains "Test3" -#define TEST_FILE_URL3 "http://melnichek.ath.cx:34568/unit_tests/3.txt" -#define TEST_FILE_NAME3 "unit_test3.tmp" - -#define TEST_INVALID_URL "http://very_invalid_url.kotorogo.net/okak.test" - -#define TEST_ABSENT_FILE_URL "http://melnichek.ath.cx:34568/unit_tests/not_existing_file" -#define TEST_ABSENT_FILE_NAME "not_existing_file" - -#define TEST_LOCKED_FILE_URL "http://melnichek.ath.cx:34568/unit_tests/1.txt" -#define TEST_LOCKED_FILE_NAME "locked_file.tmp" - -#define TEST_BIG_FILE_URL "http://melnichek.ath.cx:34568/unit_tests/47kb.file" - -Platform & gPlatform = GetPlatform(); -DownloadManager & gMgr = GetDownloadManager(); - -template -struct DlObserver -{ - size_t m_downloadsProcessed; - HttpFinishedParams m_result[TMaxDownloadsNum]; - - string m_progressUrl; - - DlObserver() : m_downloadsProcessed(0) - { - for (size_t i = 0; i < TMaxDownloadsNum; ++i) - m_result[i].m_error = EHttpDownloadFailed; - } - - void OnDownloadFinished(HttpFinishedParams const & result) - { - m_result[m_downloadsProcessed++] = result; - if (m_downloadsProcessed >= TMaxDownloadsNum) - QCoreApplication::quit(); // return control to test function body - } - - void OnDownloadProgress(HttpProgressT const & progress) - { - m_progressUrl = progress.m_url; - if (progress.m_total < 0) - { - cerr << "Your hosting doesn't support total file size or invalid resume range was given for " - << m_progressUrl << endl; - } - // for big file - cancel downloading after 40Kb were transferred - if (progress.m_current > 40 * 1024) - gMgr.CancelDownload(progress.m_url); - } -}; - -int gArgc = 1; -char * gArgv[] = { 0 }; - -UNIT_TEST(SingleDownload) -{ - size_t const NUM = 1; - DlObserver observer; - - FileWriter::DeleteFileX(TEST_FILE_NAME1); - HttpStartParams params; - params.m_url = TEST_FILE_URL1; - params.m_fileToSave = TEST_FILE_NAME1; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer, _1); - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_EQUAL( observer.m_result[0].m_error, EHttpDownloadOk, ("Do you have internet connection?") ); - TEST( gPlatform.IsFileExists(TEST_FILE_NAME1), () ); - FileWriter::DeleteFileX(TEST_FILE_NAME1); -} - -UNIT_TEST(MultiDownload) -{ - size_t const NUM = 3; - DlObserver observer; - - FileWriter::DeleteFileX(TEST_FILE_NAME1); - FileWriter::DeleteFileX(TEST_FILE_NAME2); - FileWriter::DeleteFileX(TEST_FILE_NAME3); - HttpStartParams params; - params.m_url = TEST_FILE_URL1; - params.m_fileToSave = TEST_FILE_NAME1; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer, _1); - gMgr.HttpRequest(params); - params.m_url = TEST_FILE_URL2; - params.m_fileToSave = TEST_FILE_NAME2; - gMgr.HttpRequest(params); - params.m_url = TEST_FILE_URL3; - params.m_fileToSave = TEST_FILE_NAME3; - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_EQUAL( observer.m_result[0].m_error, EHttpDownloadOk, ("Do you have internet connection?") ); - TEST( gPlatform.IsFileExists(TEST_FILE_NAME1), () ); - FileWriter::DeleteFileX(TEST_FILE_NAME1); - - TEST_EQUAL( observer.m_result[1].m_error, EHttpDownloadOk, ("Do you have internet connection?") ); - TEST( gPlatform.IsFileExists(TEST_FILE_NAME2), () ); - FileWriter::DeleteFileX(TEST_FILE_NAME2); - - TEST_EQUAL( observer.m_result[2].m_error, EHttpDownloadOk, ("Do you have internet connection?") ); - TEST( gPlatform.IsFileExists(TEST_FILE_NAME3), () ); - FileWriter::DeleteFileX(TEST_FILE_NAME3); -} - -UNIT_TEST(InvalidUrl) -{ - size_t const NUM = 1; - DlObserver observer; - // this should be set to error after executing - observer.m_result[0].m_error = EHttpDownloadOk; - - HttpStartParams params; - params.m_url = TEST_INVALID_URL; - params.m_fileToSave = TEST_FILE_NAME1; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer, _1); - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_EQUAL( observer.m_result[0].m_error, EHttpDownloadFailed, () ); - - FileWriter::DeleteFileX(TEST_FILE_NAME1); -} - -namespace -{ - void ReadFileToString(char const * fName, string & str) - { - FileReader f(fName); - vector buf; - buf.resize(f.Size()); - f.Read(0, &buf[0], f.Size()); - str.assign(buf.begin(), buf.end()); - } -} - -UNIT_TEST(DownloadFileExists) -{ - size_t const NUM = 1; - DlObserver observer; - - string const fileContent("Some Contents"); - - { - FileWriter f(TEST_FILE_NAME1); - f.Write(fileContent.c_str(), fileContent.size()); - } - - { - string str; - ReadFileToString(TEST_FILE_NAME1, str); - TEST_EQUAL(fileContent, str, ("Writer or Reader don't work?..")); - } - - HttpStartParams params; - params.m_url = TEST_FILE_URL1; - params.m_fileToSave = TEST_FILE_NAME1; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer, _1); - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_EQUAL( observer.m_result[0].m_error, EHttpDownloadOk, () ); - - { - string str; - ReadFileToString(TEST_FILE_NAME1, str); - TEST_NOT_EQUAL(fileContent, str, ("File should be overwritten by download manager")); - } - - FileWriter::DeleteFileX(TEST_FILE_NAME1); -} - -UNIT_TEST(DownloadResume) -{ - size_t const NUM = 1; - - string const fileContent("aLeX"); - - { - FileWriter f(TEST_FILE_NAME1 DOWNLOADING_FILE_EXTENSION); - f.Write(fileContent.c_str(), fileContent.size()); - } - - DlObserver observer1; - HttpStartParams params; - params.m_url = TEST_FILE_URL1; - params.m_fileToSave = TEST_FILE_NAME1; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer1, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer1, _1); - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_EQUAL( observer1.m_result[0].m_error, EHttpDownloadOk, () ); - - DlObserver observer2; - params.m_url = TEST_FILE_URL1; - params.m_fileToSave = TEST_FILE_NAME2; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer2, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer2, _1); - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_EQUAL( observer2.m_result[0].m_error, EHttpDownloadOk, () ); - - uint64_t size1 = 4, size2 = 5; - TEST( GetPlatform().GetFileSize(TEST_FILE_NAME1, size1), ()); - TEST( GetPlatform().GetFileSize(TEST_FILE_NAME2, size2), ()); - - TEST_EQUAL(size1, size2, ("Sizes should be equal - no resume was enabled")); - - // resume should append content to 1st file - { - FileWriter f(TEST_FILE_NAME1 DOWNLOADING_FILE_EXTENSION); - f.Write(fileContent.c_str(), fileContent.size()); - } - DlObserver observer3; - params.m_url = TEST_FILE_URL1; - params.m_fileToSave = TEST_FILE_NAME1; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer3, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer3, _1); - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_EQUAL( observer3.m_result[0].m_error, EHttpDownloadOk, () ); - - TEST( GetPlatform().GetFileSize(TEST_FILE_NAME1, size1), ()); - TEST_EQUAL( size1, size2, () ); - - { - string str; - ReadFileToString(TEST_FILE_NAME1, str); - TEST_EQUAL(fileContent, str.substr(0, fileContent.size()), ()); - TEST_NOT_EQUAL(fileContent, str, ()); - } - - FileWriter::DeleteFileX(TEST_FILE_NAME1); - FileWriter::DeleteFileX(TEST_FILE_NAME2); -} - -UNIT_TEST(DownloadAbsentFile) -{ - size_t const NUM = 1; - DlObserver observer; - - HttpStartParams params; - params.m_url = TEST_ABSENT_FILE_URL; - params.m_fileToSave = TEST_ABSENT_FILE_NAME; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer, _1); - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_EQUAL( observer.m_result[0].m_error, EHttpDownloadFileNotFound, () ); - TEST( !GetPlatform().IsFileExists(TEST_ABSENT_FILE_NAME), () ); - - FileWriter::DeleteFileX(TEST_ABSENT_FILE_NAME); -} - -UNIT_TEST(DownloadUsingUrlGenerator) -{ - size_t const NUM = 1; - DlObserver observer; - - string const LOCAL_FILE = "unit_test.txt"; - - HttpStartParams params; - params.m_url = LOCAL_FILE; - params.m_fileToSave = LOCAL_FILE; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer, _1); - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_NOT_EQUAL( observer.m_result[0].m_error, EHttpDownloadFileNotFound, () ); - TEST( GetPlatform().IsFileExists(LOCAL_FILE), () ); - - FileWriter::DeleteFileX(LOCAL_FILE); -} - -// only on Windows files are actually locked by system -#ifdef OMIM_OS_WINDOWS -UNIT_TEST(DownloadLockedFile) -{ - { - size_t const NUM = 1; - DlObserver observer; - - FileWriter lockedFile(TEST_LOCKED_FILE_NAME); - // check that file is actually exists - { - bool exists = true; - try { FileReader f(TEST_LOCKED_FILE_NAME); } - catch (Reader::OpenException const &) { exists = false; } - TEST(exists, ("Locked file wasn't created")); - } - - HttpStartParams params; - params.m_url = TEST_LOCKED_FILE_URL; - params.m_fileToSave = TEST_LOCKED_FILE_NAME; - params.m_finish = bind(&DlObserver::OnDownloadFinished, &observer, _1); - params.m_progress = bind(&DlObserver::OnDownloadProgress, &observer, _1); - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST_EQUAL( observer.m_result[0].m_error, EHttpDownloadFileIsLocked, () ); - } - FileWriter::DeleteFileX(GetPlatform().WritablePathForFile(TEST_LOCKED_FILE_NAME)); -} -#endif - -struct HttpPostCallbackHolder -{ - HttpFinishedParams * m_pResult; - HttpPostCallbackHolder() : m_pResult(NULL) {} - ~HttpPostCallbackHolder() { delete m_pResult; } - void OnHttpPost(HttpFinishedParams const & result) - { - m_pResult = new HttpFinishedParams(result); - QCoreApplication::quit(); - } -}; - -UNIT_TEST(HttpPost) -{ - HttpPostCallbackHolder cbHolder; - HttpStartParams params; - params.m_finish = bind(&HttpPostCallbackHolder::OnHttpPost, &cbHolder, _1); - params.m_contentType = "application/json"; - params.m_postData = "{\"version\":\"1.1.0\",\"request_address\":true}"; - params.m_url = "http://melnichek.ath.cx:34568/unit_tests/post.php"; - gMgr.HttpRequest(params); - - QCoreApplication::exec(); - - TEST( cbHolder.m_pResult, () ); - TEST_EQUAL(cbHolder.m_pResult->m_error, EHttpDownloadOk, - ("HTTP POST failed with error", cbHolder.m_pResult->m_error)); - TEST_EQUAL(cbHolder.m_pResult->m_data, "HTTP POST is OK", - ("Server sent invalid POST reply")); -} diff --git a/platform/platform_tests/platform_tests.pro b/platform/platform_tests/platform_tests.pro index 9056cbd2f8..26ebf49ea6 100644 --- a/platform/platform_tests/platform_tests.pro +++ b/platform/platform_tests/platform_tests.pro @@ -26,13 +26,11 @@ win32*|linux* { QT *= network } -# download_test.cpp \ - SOURCES += \ ../../testing/testingmain.cpp \ platform_test.cpp \ jansson_test.cpp \ concurrent_runner_test.cpp \ language_test.cpp \ - url_generator_test.cpp \ downloader_test.cpp \ + diff --git a/platform/platform_tests/url_generator_test.cpp b/platform/platform_tests/url_generator_test.cpp deleted file mode 100644 index d8cc0989c8..0000000000 --- a/platform/platform_tests/url_generator_test.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "../../testing/testing.hpp" - -#include "../url_generator.hpp" - -#include "../../std/algorithm.hpp" - -void VectorContains(vector & v, string const & s) -{ - vector::iterator found = find(v.begin(), v.end(), s); - TEST(found != v.end(), (s, "was not found in", v)); - v.erase(found); -} - -UNIT_TEST(UrlGenerator) -{ - vector first; - first.push_back("A"); - first.push_back("B"); - first.push_back("C"); - first.push_back("D"); - first.push_back("E"); - - vector second; - second.push_back("F"); - second.push_back("G"); - second.push_back("H"); - - UrlGenerator g(first, second); - - { - size_t const count = first.size(); - for (size_t i = 0; i < count; ++i) - VectorContains(first, g.PopNextUrl()); - } - { - size_t const count = second.size(); - for (size_t i = 0; i < count; ++i) - VectorContains(second, g.PopNextUrl()); - } - { - for (size_t i = 0; i < 10; ++i) - TEST_EQUAL(g.PopNextUrl(), string(), ()); - } -} diff --git a/platform/qt_download.cpp b/platform/qt_download.cpp deleted file mode 100644 index 05b05b5034..0000000000 --- a/platform/qt_download.cpp +++ /dev/null @@ -1,324 +0,0 @@ -#include "qt_download.hpp" -#include "qt_download_manager.hpp" - -#include "../base/logging.hpp" -#include "../base/assert.hpp" - -#include "../coding/sha2.hpp" -#include "../coding/base64.hpp" - -#include "../std/target_os.hpp" - -#include -#include -#include - -// How many times we try to automatically reconnect in the case of network errors -#define MAX_AUTOMATIC_RETRIES 2 - -#ifdef OMIM_OS_WINDOWS - #define LOGIN_VAR "USERNAME" -#else - #define LOGIN_VAR "USER" -#endif -/// @return login name for active user and local machine hostname -static QString UserLoginAndHostname() -{ - char const * login = getenv(LOGIN_VAR); - QString result(login ? login : ""); - result += QHostInfo::localHostName(); - return result; -} - -/// @return mac address of active interface or empty string if not found -static QString MacAddress() -{ - QList interfaces = QNetworkInterface::allInterfaces(); - for (int i = 0; i < interfaces.size(); ++i) - { - QNetworkInterface const & iface = interfaces.at(i); - QString hwAddr = iface.hardwareAddress(); - if (!iface.addressEntries().empty() - && (iface.flags() & (QNetworkInterface::IsUp | QNetworkInterface::IsRunning - | QNetworkInterface::CanBroadcast | QNetworkInterface::CanMulticast)) == iface.flags()) - { - return hwAddr; - } - } - // no valid interface was found - return QString(); -} - -/// @return creation time of the root file system or empty string -static QString FsCreationTime() -{ - QFileInfoList drives = QFSFileEngine::drives(); - for (int i = 0; i < drives.size(); ++i) - { - QFileInfo const & info = drives.at(i); - QString const path = info.absolutePath(); - if (path == "/" || path.startsWith("C:")) - return QString("%1").arg(info.created().toTime_t()); - } - return QString(); -} - -static QString UniqueClientId() -{ - QString result = MacAddress(); - if (result.size() == 0) - { - result = FsCreationTime(); - if (result.size() == 0) - result = QString("------------"); - } - // add salt - login user name and local hostname - result += UserLoginAndHostname(); - // calculate one-way hash - QByteArray const original = QByteArray::fromHex(result.toLocal8Bit()); - string const hash = sha2::digest256(original.constData(), original.size(), false); - // xor hash - size_t const offset = hash.size() / 4; - string xoredHash; - for (size_t i = 0; i < offset; ++i) - xoredHash.push_back(hash[i] ^ hash[i + offset] ^ hash[i + offset * 2] ^ hash[i + offset * 3]); - return base64::encode(xoredHash).c_str(); -} - -static QString UserAgent() -{ - static QString userAgent = UniqueClientId(); - return userAgent; -} - -static bool NeedToUseUrlGenerator(string const & url) -{ - return url.find("http://") != 0 && url.find("https://") != 0; -} - -QtDownload::QtDownload(QtDownloadManager & manager, HttpStartParams const & params) - : QObject(&manager), m_currentUrl(params.m_url.c_str()), m_reply(0), - m_params(params) -{ - // if we need to save server response to the file... - if (!m_params.m_fileToSave.empty()) - { - // use temporary file for download - m_file.setFileName((m_params.m_fileToSave + DOWNLOADING_FILE_EXTENSION).c_str()); - if (!m_file.open(QIODevice::Append)) - { - QString const err = m_file.errorString(); - LOG(LERROR, ("Can't open file while downloading", qPrintable(m_file.fileName()), qPrintable(err))); - if (m_params.m_finish) - { - HttpFinishedParams result; - result.m_error = EHttpDownloadCantCreateFile; - result.m_file = m_params.m_fileToSave; - result.m_url = m_params.m_url; - m_params.m_finish(result); - } - // mark itself to delete - deleteLater(); - return; - } - } - // url acts as a key to find this download by QtDownloadManager::findChild(url) - setObjectName(m_params.m_url.c_str()); - - // if url doesn't contain valid http:// or https:// we use UrlGenerator - if (NeedToUseUrlGenerator(m_params.m_url)) - m_currentUrl = (m_urlGenerator.PopNextUrl() + m_params.m_url).c_str(); - - StartRequest(); -} - -QtDownload::~QtDownload() -{ - if (m_reply) - { - // don't notify client when aborted - disconnect(m_reply, SIGNAL(finished()), this, SLOT(OnHttpFinished())); - disconnect(m_reply, SIGNAL(readyRead()), this, SLOT(OnHttpReadyRead())); - disconnect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), - this, SLOT(OnUpdateDataReadProgress(qint64, qint64))); - m_reply->abort(); - delete m_reply; - - if (m_file.isOpen()) - { - m_file.close(); - m_file.remove(); - } - } - LOG(LDEBUG, (m_currentUrl.toString().toLocal8Bit().data())); -} - -void QtDownload::StartRequest() -{ - QNetworkRequest httpRequest(m_currentUrl); - // set user-agent with unique client id only for mapswithme requests - if (m_currentUrl.host().contains("mapswithme.com")) - httpRequest.setRawHeader("User-Agent", UserAgent().toAscii()); - if (m_file.isOpen()) - { - qint64 const fileSize = m_file.size(); - if (fileSize > 0) // need resume - httpRequest.setRawHeader("Range", QString("bytes=%1-").arg(fileSize).toAscii()); - } - if (!m_params.m_contentType.empty()) - httpRequest.setHeader(QNetworkRequest::ContentTypeHeader, m_params.m_contentType.c_str()); - if (m_params.m_postData.empty()) - m_reply = static_cast(parent())->NetAccessManager().get(httpRequest); - else - { - m_reply = static_cast(parent())->NetAccessManager().post( - httpRequest, m_params.m_postData.c_str()); - } - m_reply->ignoreSslErrors(); - connect(m_reply, SIGNAL(finished()), this, SLOT(OnHttpFinished())); - connect(m_reply, SIGNAL(readyRead()), this, SLOT(OnHttpReadyRead())); - connect(m_reply, SIGNAL(downloadProgress(qint64, qint64)), - this, SLOT(OnUpdateDataReadProgress(qint64, qint64))); -} - -static DownloadResultT TranslateError(QNetworkReply::NetworkError err) -{ - switch (err) - { - case QNetworkReply::NoError: return EHttpDownloadOk; - case QNetworkReply::ContentNotFoundError: return EHttpDownloadFileNotFound; - case QNetworkReply::HostNotFoundError: return EHttpDownloadFailed; - default: return EHttpDownloadFailed; - } -} - -void QtDownload::OnHttpFinished() -{ - QVariant const redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - QNetworkReply::NetworkError const netError = m_reply->error(); - if (netError) - { - if (netError <= QNetworkReply::UnknownNetworkError && NeedToUseUrlGenerator(m_params.m_url)) - { - string const nextUrl = m_urlGenerator.PopNextUrl(); - if (!nextUrl.empty()) - { - // try one more time - m_reply->deleteLater(); - m_currentUrl = (nextUrl + m_params.m_url).c_str(); - StartRequest(); - return; - } - } - // do not delete file if we can resume it's downloading later - if (m_file.isOpen()) - { - m_file.close(); - if (m_file.size() == 0) - m_file.remove(); - } - - QString const err = m_reply->errorString(); - LOG(LWARNING, ("Download failed", qPrintable(err))); - - m_reply->deleteLater(); - m_reply = 0; - - if (m_params.m_finish) - { - HttpFinishedParams result; - result.m_file = m_params.m_fileToSave; - result.m_url = m_params.m_url; - result.m_error = TranslateError(netError); - m_params.m_finish(result); - } - // selfdestruct - deleteLater(); - } - else if (!redirectionTarget.isNull()) - { - m_currentUrl = m_currentUrl.resolved(redirectionTarget.toUrl()); - LOG(LINFO, ("HTTP redirect", m_currentUrl.toEncoded().data())); - if (m_file.isOpen()) - { - m_file.close(); - m_file.open(QIODevice::WriteOnly); - m_file.resize(0); - } - - m_reply->deleteLater(); - m_reply = 0; - StartRequest(); - return; - } - else - { // download succeeded - bool fileIsLocked = false; - if (m_file.isOpen()) - { - m_file.close(); - // delete original file if it exists - QFile::remove(m_params.m_fileToSave.c_str()); - if (!m_file.rename(m_params.m_fileToSave.c_str())) - { // sh*t... file is locked and can't be removed - m_file.remove(); - // report error to GUI - LOG(LWARNING, ("File exists and can't be replaced by downloaded one:", m_params.m_fileToSave)); - fileIsLocked = true; - } - } - - if (m_params.m_finish) - { - HttpFinishedParams result; - result.m_url = m_params.m_url; - result.m_file = m_params.m_fileToSave; - QByteArray data = m_reply->readAll(); - if (!data.isEmpty()) - result.m_data.assign(data.constData(), data.size()); - result.m_error = fileIsLocked ? EHttpDownloadFileIsLocked : EHttpDownloadOk; - m_params.m_finish(result); - } - - m_reply->deleteLater(); - m_reply = 0; - // selfdestruct - deleteLater(); - } -} - -void QtDownload::OnHttpReadyRead() -{ - // this slot gets called everytime the QNetworkReply has new data. - // We read all of its new data and write it into the file. - // That way we use less RAM than when reading it at the finished() - // signal of the QNetworkReply - if (m_file.isOpen() && m_reply) - m_file.write(m_reply->readAll()); - - // @note that for requests where m_file is not used, data accumulates - // and m_reply->readAll() should be called in finish() slot handler -} - -void QtDownload::OnUpdateDataReadProgress(qint64 bytesRead, qint64 totalBytes) -{ - m_urlGenerator.UpdateSpeed(bytesRead); - if (m_params.m_progress) - { - HttpProgressT p; - p.m_current = bytesRead; - p.m_total = totalBytes; - p.m_url = m_params.m_url; - p.m_bytesPerSec = m_urlGenerator.CurrentSpeed(); - m_params.m_progress(p); - } - // if download speed is slow, use next server - string const fasterUrl = m_urlGenerator.GetFasterUrl(); - if (!fasterUrl.empty()) - { - m_reply->abort(); - m_reply->deleteLater(); - m_currentUrl.setUrl(fasterUrl.c_str()); - StartRequest(); - } -} diff --git a/platform/qt_download.hpp b/platform/qt_download.hpp deleted file mode 100644 index ae1adf16ba..0000000000 --- a/platform/qt_download.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "download_manager.hpp" -#include "url_generator.hpp" - -#include - -class QtDownloadManager; - -class QtDownload : public QObject -{ - Q_OBJECT - - // can be changed during server redirections - QUrl m_currentUrl; - QNetworkReply * m_reply; - QFile m_file; - - HttpStartParams m_params; - - UrlGenerator m_urlGenerator; - - void StartRequest(); - -private slots: - void OnHttpFinished(); - void OnHttpReadyRead(); - void OnUpdateDataReadProgress(qint64 bytesRead, qint64 totalBytes); - -public: - /// Created instance is automanaged as a manager's child - /// and can be manipulated later by manager->findChild(url); - QtDownload(QtDownloadManager & manager, HttpStartParams const & params); - virtual ~QtDownload(); -}; diff --git a/platform/qt_download_manager.cpp b/platform/qt_download_manager.cpp deleted file mode 100644 index a0241230b0..0000000000 --- a/platform/qt_download_manager.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "qt_download_manager.hpp" -#include "qt_download.hpp" - -#include "../base/assert.hpp" -#include "../base/logging.hpp" - -void QtDownloadManager::CreateOnMainThreadSlot(HttpStartParams const & params) -{ - // manager is responsible for auto deleting - new QtDownload(*this, params); -} - -void QtDownloadManager::HttpRequest(HttpStartParams const & params) -{ - ASSERT(!params.m_url.empty(), ()); - QList downloads = findChildren(params.m_url.c_str()); - if (downloads.empty()) - { - // small trick so all connections will be created on the main thread - qRegisterMetaType("HttpStartParams"); - QMetaObject::invokeMethod(this, "CreateOnMainThreadSlot", Q_ARG(HttpStartParams const & , params)); - } - else - { - LOG(LWARNING, ("Download with the same url is already in progress, ignored", params.m_url)); - } -} - -void QtDownloadManager::CancelDownload(string const & url) -{ - QList downloads = findChildren(url.c_str()); - while (!downloads.isEmpty()) - delete downloads.takeFirst(); -} - -void QtDownloadManager::CancelAllDownloads() -{ - QList downloads = findChildren(); - while (!downloads.isEmpty()) - delete downloads.takeFirst(); -} - -extern "C" DownloadManager & GetDownloadManager() -{ - static QtDownloadManager dlMgr; - return dlMgr; -} diff --git a/platform/qt_download_manager.hpp b/platform/qt_download_manager.hpp deleted file mode 100644 index e62135515d..0000000000 --- a/platform/qt_download_manager.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "download_manager.hpp" - -#include - -class QtDownloadManager : public QObject, public DownloadManager -{ - Q_OBJECT - - QNetworkAccessManager m_netAccessManager; - - /// Should be called using inter-thread signal -private slots: - void CreateOnMainThreadSlot(HttpStartParams const & params); - -public: - virtual void HttpRequest(HttpStartParams const & params); - virtual void CancelDownload(string const & url); - virtual void CancelAllDownloads(); - - QNetworkAccessManager & NetAccessManager() { return m_netAccessManager; } -}; diff --git a/platform/url_generator.cpp b/platform/url_generator.cpp deleted file mode 100644 index de2e990646..0000000000 --- a/platform/url_generator.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "url_generator.hpp" - -#include "../base/macros.hpp" - -#include "../std/ctime.hpp" - -static char const * g_defaultFirstGroup[] = { -#ifdef OMIM_PRODUCTION - "http://a0.mapswithme.com/", - "http://a1.mapswithme.com/", - "http://a2.mapswithme.com/", - "http://a3.mapswithme.com/", - "http://a4.mapswithme.com/", - "http://a5.mapswithme.com/", - "http://a6.mapswithme.com/", - "http://a7.mapswithme.com/", - "http://a8.mapswithme.com/", - "http://a9.mapswithme.com/", - "http://a10.mapswithme.com/", - "http://a11.mapswithme.com/" -#else - "http://svobodu404popugajam.mapswithme.com:34568/maps/" -#endif -}; -static char const * g_defaultSecondGroup[] = { -#ifdef OMIM_PRODUCTION - "http://b0.mapswithme.com/", - "http://b1.mapswithme.com/", - "http://b2.mapswithme.com/", - "http://b3.mapswithme.com/", - "http://b4.mapswithme.com/", - "http://b5.mapswithme.com/" -#else - "http://svobodu404popugajam.mapswithme.com:34568/maps/" -#endif -}; - -UrlGenerator::UrlGenerator() - : m_randomGenerator(static_cast(time(NULL))), - m_firstGroup(&g_defaultFirstGroup[0], &g_defaultFirstGroup[0] + ARRAY_SIZE(g_defaultFirstGroup)), - m_secondGroup(&g_defaultSecondGroup[0], &g_defaultSecondGroup[0] + ARRAY_SIZE(g_defaultSecondGroup)), - m_lastSecond(0.) -{ -} - -UrlGenerator::UrlGenerator(vector const & firstGroup, vector const & secondGroup) - : m_randomGenerator(static_cast(time(NULL))), m_firstGroup(firstGroup), m_secondGroup(secondGroup), - m_lastSecond(0.) -{ -} - -string UrlGenerator::PopNextUrl() -{ - string s; - switch (m_firstGroup.size()) - { - case 1: - s = m_firstGroup.front(); - m_firstGroup.pop_back(); - break; - case 0: - switch (m_secondGroup.size()) - { - case 1: - s = m_secondGroup.front(); - m_secondGroup.pop_back(); - break; - case 0: // nothing left to return - break; - default: - { - vector::iterator const it = m_secondGroup.begin() - + static_cast::difference_type>(m_randomGenerator.Generate() % m_secondGroup.size()); - s = *it; - m_secondGroup.erase(it); - } - } - break; - default: - { - vector::iterator const it = m_firstGroup.begin() - + static_cast::difference_type>(m_randomGenerator.Generate() % m_firstGroup.size()); - s = *it; - m_firstGroup.erase(it); - } - } - return s; -} - -void UrlGenerator::UpdateSpeed(int64_t totalBytesRead) -{ - double const seconds = m_timer.ElapsedSeconds(); - if (static_cast(seconds) - static_cast(m_lastSecond) > 0) - { - m_lastSecond = seconds; - m_speeds.push_back(make_pair(seconds, totalBytesRead)); - if (m_speeds.size() > 6) - m_speeds.pop_front(); - } -} - -int64_t UrlGenerator::CurrentSpeed() const -{ - switch (m_speeds.size()) - { - case 0: - case 1: return -1; - default: return static_cast((m_speeds.back().second - m_speeds.front().second) - / (m_speeds.back().first - m_speeds.front().first)); - } -} - -string UrlGenerator::GetFasterUrl() -{ - return string(); -} diff --git a/platform/url_generator.hpp b/platform/url_generator.hpp deleted file mode 100644 index 65f61d68a7..0000000000 --- a/platform/url_generator.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "../base/pseudo_random.hpp" -#include "../base/timer.hpp" - -#include "../std/vector.hpp" -#include "../std/list.hpp" -#include "../std/string.hpp" -#include "../std/utility.hpp" - -class UrlGenerator -{ - LCG32 m_randomGenerator; - vector m_firstGroup; - vector m_secondGroup; - - /// For moving average speed calculations - my::Timer m_timer; - /// Stores time in seconds from start and downloaded amount at that moment - typedef pair MarkT; - list m_speeds; - double m_lastSecond; - -public: - UrlGenerator(); - explicit UrlGenerator(vector const & firstGroup, vector const & secondGroup); - - /// @return Always return empty string if all urls were already popped - string PopNextUrl(); - - /// @return -1 means speed is unknown - void UpdateSpeed(int64_t totalBytesRead); - int64_t CurrentSpeed() const; - string GetFasterUrl(); -};