diff options
Diffstat (limited to 'Src/Components/wac_downloadManager')
25 files changed, 2895 insertions, 0 deletions
diff --git a/Src/Components/wac_downloadManager/BackgroundDownloader.cpp b/Src/Components/wac_downloadManager/BackgroundDownloader.cpp new file mode 100644 index 00000000..a0731ebc --- /dev/null +++ b/Src/Components/wac_downloadManager/BackgroundDownloader.cpp @@ -0,0 +1,128 @@ +#include "BackgroundDownloader.h" +#include "../../Components\wac_network/wac_network_http_receiver_api.h" + +#include "api__wac_downloadManager.h" + +#include "api/service/waservicefactory.h" + +#include "../nu/AutoChar.h" + +#include <strsafe.h> + +#define HTTP_BUFFER_SIZE 32768 +// {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C} +static const GUID internetConfigGroupGUID = +{ 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c } }; + + +static void SetUserAgent( api_httpreceiver *http ) +{ + char agent[ 256 ]; + StringCchPrintfA( agent, 256, "User-Agent: %S/%S", WASABI_API_APP->main_getAppName(), WASABI_API_APP->main_getVersionNumString() ); + http->addheader( agent ); +} + +static int FeedHTTP( api_httpreceiver *http, Downloader::DownloadCallback &callback, void *userData, bool *noData ) +{ + char downloadedData[ HTTP_BUFFER_SIZE ]; + int result = 0; + int downloadSize = http->get_bytes( downloadedData, HTTP_BUFFER_SIZE ); + if ( downloadSize ) + { + result = callback( userData, downloadedData, downloadSize ); + *noData = false; + } + else + *noData = true; + + return result; +} + +static void RunDownload( api_httpreceiver *http, Downloader::DownloadCallback &callback, void *userData ) +{ + int ret; + bool noData; + do + { + Sleep( 50 ); + ret = http->run(); + if ( FeedHTTP( http, callback, userData, &noData ) != 0 ) + return; + } while ( ret == HTTPRECEIVER_RUN_OK ); + + // finish off the data + do + { + if ( FeedHTTP( http, callback, userData, &noData ) != 0 ) + return; + } while ( !noData ); +} + + +bool Downloader::Download( const char *url, Downloader::DownloadCallback &callback, void *userdata, uint64_t startPosition ) +{ + api_httpreceiver *http = 0; + + waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( httpreceiverGUID ); + if ( sf ) + http = (api_httpreceiver *)sf->getInterface(); + + if ( !http ) + return false; + + int use_proxy = 1; + bool proxy80 = AGAVE_API_CONFIG->GetBool( internetConfigGroupGUID, L"proxy80", false ); + if ( proxy80 && strstr( url, ":" ) && ( !strstr( url, ":80/" ) && strstr( url, ":80" ) != ( url + strlen( url ) - 3 ) ) ) + use_proxy = 0; + + const wchar_t *proxy = use_proxy ? AGAVE_API_CONFIG->GetString( internetConfigGroupGUID, L"proxy", 0 ) : 0; + + http->AllowCompression(); + http->open( API_DNS_AUTODNS, HTTP_BUFFER_SIZE, ( proxy && proxy[ 0 ] ) ? (const char *)AutoChar( proxy ) : NULL ); + + if ( startPosition > 0 ) + { + char temp[ 128 ]; + StringCchPrintfA( temp, 128, "Range: bytes=%d-", startPosition ); + http->addheader( temp ); + } + + SetUserAgent( http ); + http->connect( url ); + + int ret; + + do + { + Sleep( 10 ); + + ret = http->run(); + if ( ret == -1 ) // connection failed + break; + + // ---- check our reply code ---- + int replycode = http->getreplycode(); + switch ( replycode ) + { + case 0: + case 100: + break; + case 200: + { + RunDownload( http, callback, userdata ); + + sf->releaseInterface( http ); + + return true; + } + break; + default: + sf->releaseInterface( http ); + return false; + } + } while ( ret == HTTPRECEIVER_RUN_OK ); + + sf->releaseInterface( http ); + + return false; +} diff --git a/Src/Components/wac_downloadManager/BackgroundDownloader.h b/Src/Components/wac_downloadManager/BackgroundDownloader.h new file mode 100644 index 00000000..9a1a3f48 --- /dev/null +++ b/Src/Components/wac_downloadManager/BackgroundDownloader.h @@ -0,0 +1,14 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_BACKGROUND_DOWNLOADER_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_BACKGROUND_DOWNLOADER_H + +#include "bfc/platform/types.h" + +class Downloader +{ +public: + typedef int ( *DownloadCallback )( void *userdata, void *buffer, size_t bufferSize ); + bool Download( const char *url, DownloadCallback &callback, void *userdata, uint64_t startPosition = 0 ); + +}; + +#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_BACKGROUND_DOWNLOADER_H diff --git a/Src/Components/wac_downloadManager/DownloadCallbackT.h b/Src/Components/wac_downloadManager/DownloadCallbackT.h new file mode 100644 index 00000000..f0d46f6a --- /dev/null +++ b/Src/Components/wac_downloadManager/DownloadCallbackT.h @@ -0,0 +1,71 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOADCALLBACKT_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOADCALLBACKT_H + +#include "wac_downloadManager_api.h" + +#define WIN32_LEAN_AND_MEAN + +//#include <windows.h> // for InterlockedIncrememt/Decrement +#include <atomic> + +/* DownloadCallbackT is reference counted for you. if you don't like that, inherit from ifc_downloadManagerCallback yourself */ +template <class T> +class DownloadCallbackT : public ifc_downloadManagerCallback +{ +public: + size_t AddRef() + { + return _ref_count.fetch_add( 1 ); + } + + size_t Release() + { + if (_ref_count.load() == 0 ) + return _ref_count.load(); + + LONG l_ref_count = _ref_count.fetch_sub( 1 ); + if ( !l_ref_count ) + delete( static_cast<T *>( this ) ); + + return l_ref_count; + } + +protected: + DownloadCallbackT() {} + + void OnFinish( DownloadToken token ) { Release(); } + void OnTick( DownloadToken token ) {} + void OnError( DownloadToken token, int error ) { Release(); } + void OnCancel( DownloadToken token ) { Release(); } + void OnConnect( DownloadToken token ) {} + void OnInit( DownloadToken token ) {} + void OnData( DownloadToken token, void *data, size_t datalen ) {} + + int GetSource(wchar_t *source, size_t source_cch) { return 1;} + int GetTitle(wchar_t *title, size_t title_cch) { return 1;} + int GetLocation(wchar_t *location, size_t location_cch) { return 1;} + +#define CBCLASS T +#define CBCLASST DownloadCallbackT<T> + START_DISPATCH_INLINE; + CBT(ADDREF, AddRef); + CBT(RELEASE, Release); + VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish); + VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONTICK, OnTick); + VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError); + VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel); + VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect); + VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit); + VCBT(IFC_DOWNLOADMANAGERCALLBACK_ONDATA, OnData); + CBT( IFC_DOWNLOADMANAGERCALLBACK_GETSOURCE, GetSource); + CBT( IFC_DOWNLOADMANAGERCALLBACK_GETTITLE, GetTitle); + CBT( IFC_DOWNLOADMANAGERCALLBACK_GETLOCATION, GetLocation); + END_DISPATCH; +#undef CBCLASS +#undef CBCLASST + +private: + std::atomic<std::size_t> _ref_count; +}; + +#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOADCALLBACKT_H diff --git a/Src/Components/wac_downloadManager/api__wac_downloadManager.h b/Src/Components/wac_downloadManager/api__wac_downloadManager.h new file mode 100644 index 00000000..241b148c --- /dev/null +++ b/Src/Components/wac_downloadManager/api__wac_downloadManager.h @@ -0,0 +1,40 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_API_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_API_H + +#include "api/service/api_service.h" + +#include "api/application/api_application.h" +#define WASABI_API_APP applicationApi + +#include "../Agave/Config/api_config.h" + +#include "../nu/threadpool/api_threadpool.h" +extern api_threadpool *threadPoolApi; +#define WASABI_API_THREADPOOL threadPoolApi + + +template <class api_T> +static void ServiceBuild( api_T *&api_t, GUID factoryGUID_t ) +{ + if ( WASABI_API_SVC ) + { + waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid( factoryGUID_t ); + if ( factory ) + api_t = reinterpret_cast<api_T *>( factory->getInterface() ); + } +} + +template <class api_T> +static void ServiceRelease( api_T *api_t, GUID factoryGUID_t ) +{ + if ( WASABI_API_SVC && api_t ) + { + waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid( factoryGUID_t ); + if ( factory ) + factory->releaseInterface( api_t ); + } + + api_t = NULL; +} + +#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_API_H
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/main.cpp b/Src/Components/wac_downloadManager/main.cpp new file mode 100644 index 00000000..7038b540 --- /dev/null +++ b/Src/Components/wac_downloadManager/main.cpp @@ -0,0 +1,69 @@ +#include "main.h" + +//#include "wac_download_http_receiver_factory.h" + +#include "wac_downloadManager.h" + +#include "bfc/platform/export.h" + +static Singleton2<api_downloadManager, DownloadManager> dlMgrFactory; +static DownloadManager dlMgr; + +//static wa::Components::WAC_DownloadsFactory _wac_download_factory; +static wa::Components::WAC_DownloadManager_Component _wac_downloadManager_Component; + +//wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory _wac_downloadManager_http_receiver_service; + +api_service *WASABI_API_SVC = 0; +api_application *WASABI_API_APP = 0; +api_config *AGAVE_API_CONFIG = 0; +api_threadpool *WASABI_API_THREADPOOL = 0; + + +void wa::Components::WAC_DownloadManager_Component::RegisterServices( api_service *p_service ) +{ + WASABI_API_SVC = p_service; + + ServiceBuild( WASABI_API_APP, applicationApiServiceGuid ); + ServiceBuild( AGAVE_API_CONFIG, AgaveConfigGUID ); + ServiceBuild( WASABI_API_THREADPOOL, ThreadPoolGUID ); + + + dlMgrFactory.Register( &dlMgr ); + + //WASABI_API_SVC->service_register( &_wac_downloadManager_http_receiver_service ); +} + +void wa::Components::WAC_DownloadManager_Component::DeregisterServices( api_service *p_service ) +{ + Q_UNUSED( p_service ) + + ServiceRelease( WASABI_API_APP, applicationApiServiceGuid ); + ServiceRelease( AGAVE_API_CONFIG, AgaveConfigGUID ); + + dlMgr.Kill(); + dlMgrFactory.Deregister(); + + ServiceRelease( WASABI_API_THREADPOOL, ThreadPoolGUID ); + + //p_service->service_deregister( &_wac_downloadManager_http_receiver_service ); +} + + +extern "C" WAC_DOWNLOAD_MANAGER_EXPORT ifc_wa5component * GetWinamp5SystemComponent() +{ + return &_wac_downloadManager_Component; +} + + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS wa::Components::WAC_DownloadManager_Component +START_DISPATCH; +VCB( API_WA5COMPONENT_REGISTERSERVICES, RegisterServices ) +CB( API_WA5COMPONENT_REGISTERSERVICES_SAFE_MODE, RegisterServicesSafeModeOk ) +VCB( API_WA5COMPONENT_DEREEGISTERSERVICES, DeregisterServices ) +END_DISPATCH; +#undef CBCLASS diff --git a/Src/Components/wac_downloadManager/main.h b/Src/Components/wac_downloadManager/main.h new file mode 100644 index 00000000..dc80f120 --- /dev/null +++ b/Src/Components/wac_downloadManager/main.h @@ -0,0 +1,37 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_MAIN_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_MAIN_H + +#include "wac_downloadManager_global.h" + +#include "api__wac_downloadManager.h" + +//#include "wac_downloadManager.h" +//#include "wac_download_http_receiver.h" + +#include "bfc/dispatch.h" + +#include "../../Winamp/Singleton.h" +#include "../../Agave/Component/ifc_wa5component.h" + + +namespace wa +{ + namespace Components + { + class WAC_DownloadManager_Component : public ifc_wa5component + { + public: + WAC_DownloadManager_Component() {} + + void RegisterServices( api_service *service ); + int RegisterServicesSafeModeOk() { return 1; } + + void DeregisterServices( api_service *service ); + + protected: + RECVS_DISPATCH; + }; + } +} + +#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_MAIN_H
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/resource.h b/Src/Components/wac_downloadManager/resource.h new file mode 100644 index 00000000..528c5d4a --- /dev/null +++ b/Src/Components/wac_downloadManager/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by wac_network.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Src/Components/wac_downloadManager/version.rc2 b/Src/Components/wac_downloadManager/version.rc2 new file mode 100644 index 00000000..b62ac19b --- /dev/null +++ b/Src/Components/wac_downloadManager/version.rc2 @@ -0,0 +1,39 @@ + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +#include "../../Winamp/buildType.h" +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,1,0,0 + PRODUCTVERSION WINAMP_PRODUCTVER + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Winamp SA" + VALUE "FileDescription", "Winamp 5.x System Component" + VALUE "FileVersion", STR_WINAMP_PRODUCTVER + VALUE "InternalName", "wac_downloadManager.w5s" + VALUE "LegalCopyright", "Copyright © 2007-2022 Winamp SA" + VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA" + VALUE "OriginalFilename", "wac_downloadManager.w5s" + VALUE "ProductName", "Winamp downloadManager Service" + VALUE "ProductVersion", STR_WINAMP_PRODUCTVER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.cpp b/Src/Components/wac_downloadManager/wac_downloadManager.cpp new file mode 100644 index 00000000..aa3e7ae9 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager.cpp @@ -0,0 +1,872 @@ +#include <string.h> +#include <strsafe.h> + +#include <iostream> +#include <cstdio> + +#include <QtCore/qglobal.h> + +#include <QWebEngineProfile> +#include <QtWebEngineWidgets/QtWebEngineWidgets> +#include <QWebEnginePage> +#include <QWebEngineSettings> + +#include "api__wac_downloadManager.h" + +#include "wac_downloadManager.h" +#include "wac_download_http_receiver_api.h" + +#include "..\wac_network\wac_network_http_receiver_api.h" + +#include "api/service/waservicefactory.h" + +#include "../nu/threadname.h" +#include "../nu/AutoChar.h" +#include "../nu/threadpool/timerhandle.hpp" + +#include "..\WAT\WAT.h" + +#include "..\Winamp\buildType.h" + +static const GUID internetConfigGroupGUID = +{ + 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c } +}; + +#define DOWNLOAD_TIMEOUT_MS 60000 // 60 second timeout +#define DOWNLOAD_SLEEP_MS 50 +#define DOWNLOAD_BUFFER_SIZE 1310720 // gives a maximum download rate of 25 mb/sec per file + + +/********************************************************************************** + **********************************************************************************/ + + +/********************************************************************************** + * PUBLIC * + **********************************************************************************/ +wa::Components::WAC_DownloadData::WAC_DownloadData( api_wac_download_manager_http_receiver *p_http, const char *p_url, int p_flags, ifc_downloadManagerCallback *p_callback ) +{ + _http = p_http; + + strcpy_s( this->_url, 1024, p_url ); + + _flags = p_flags; + _callback = p_callback; + + if ( _callback ) + _callback->AddRef(); + + _hFile = INVALID_HANDLE_VALUE; + _filepath[ 0 ] = 0; + _fileext = 0; + + int download_method = ( api_downloadManager::DOWNLOADEX_MASK_DOWNLOADMETHOD & _flags ); + switch ( download_method ) + { + case api_downloadManager::DOWNLOADEX_TEMPFILE: + { + wchar_t temppath[ MAX_PATH - 14 ] = { 0 }; // MAX_PATH-14 'cause MSDN said so + GetTempPathW( MAX_PATH - 14, temppath ); + GetTempFileNameW( temppath, L"wdl", 0, _filepath ); + _hFile = CreateFileW( _filepath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0 ); + } + break; + case api_downloadManager::DOWNLOADEX_CALLBACK: + if ( _callback ) + _callback->GetLocation( _filepath, MAX_PATH ); + break; + } + + + + _source[ 0 ] = 0; + _title[ 0 ] = 0; + + if ( _flags & api_downloadManager::DOWNLOADEX_CALLBACK ) + { + if ( _callback ) + { + _callback->GetSource( _source, 1024 ); + _callback->GetTitle( _title, 1024 ); + } + } + + _connectionStart = _lastDownloadTick = GetTickCount(); + _last_status = HTTP_RECEIVER_STATUS_ERROR; + _pending = ( _flags & api_downloadManager::DOWNLOADEX_PENDING ) > 0; +} + +wa::Components::WAC_DownloadData::~WAC_DownloadData() +{ + ServiceRelease( _http, httpreceiverGUID2 ); + + _http = NULL; + + if ( _fileext ) + delete _fileext; + + int download_method = ( api_downloadManager::DOWNLOADEX_MASK_DOWNLOADMETHOD & _flags ); + if ( download_method == api_downloadManager::DOWNLOADEX_TEMPFILE && _filepath[ 0 ] ) + DeleteFileW( _filepath ); + + if ( _callback ) + _callback->Release(); + + _callback = NULL; +} + + +void wa::Components::WAC_DownloadData::Retain() +{ + this->_refCount.fetch_add( 1 ); +} + +void wa::Components::WAC_DownloadData::Release() +{ + if ( this->_refCount.fetch_sub( 1 ) == 0 ) + delete this; +} + + +void wa::Components::WAC_DownloadData::Close( ifc_downloadManagerCallback **callbackCopy ) +{ + if ( _hFile != INVALID_HANDLE_VALUE ) + CloseHandle( _hFile ); + + _hFile = INVALID_HANDLE_VALUE; + + if ( callbackCopy != NULL ) + { + *callbackCopy = _callback; + if ( _callback != NULL ) + _callback->AddRef(); + } + else if ( _callback != NULL ) + { + _callback->Release(); + _callback = NULL; + } + + // don't want to close http here, because someone might still want to get the headers out of it +} + +bool wa::Components::WAC_DownloadData::getExtention() +{ + if ( _fileext && *_fileext ) + return _fileext; + + char l_header_name_content_type[] = "Content-Type"; + + char *l_content_type = _http->getheader( l_header_name_content_type ); + if ( l_content_type && *l_content_type ) + { + if ( _CONTENT_TYPES_EXTENSIONS.count( l_content_type ) == 1 ) + _fileext = _strdup( _CONTENT_TYPES_EXTENSIONS.find( l_content_type )->second.c_str() ); + } + + return _fileext; +} + + + + +/********************************************************************************** + * PRIVATE * + **********************************************************************************/ + + + +/********************************************************************************** + **********************************************************************************/ + +/********************************************************************************** + * PUBLIC * + **********************************************************************************/ +wa::Components::WAC_DownloadManager::WAC_DownloadManager( QObject *parent ) : QNetworkAccessManager( parent ) +{ + this->setObjectName( "DownloadManagerService" ); + + this->init(); +} + +wa::Components::WAC_DownloadManager::~WAC_DownloadManager() +{ + disconnect( _connection_authentication_required ); +} + + +DownloadToken wa::Components::WAC_DownloadManager::Download( const char *p_url, ifc_downloadManagerCallback *p_callback ) +{ + return DownloadEx( p_url, p_callback, api_downloadManager::DOWNLOADEX_TEMPFILE ); +} + +DownloadToken wa::Components::WAC_DownloadManager::DownloadEx( const char *p_url, ifc_downloadManagerCallback *p_callback, int p_flags ) +{ + + + + return DownloadToken(); +} + + + + + +/********************************************************************************** + * PRIVATE * + **********************************************************************************/ +void wa::Components::WAC_DownloadManager::init() +{ + QString l_winamp_user_agent = QString( "%1 Winamp/%2" ).arg( QWebEngineProfile::defaultProfile()->httpUserAgent(), STR_WINAMP_PRODUCTVER ).replace( ",", "." ); + + QWebEngineProfile::defaultProfile()->setHttpUserAgent( l_winamp_user_agent ); + + + _connection_authentication_required = connect( this, &QNetworkAccessManager::authenticationRequired, this, &wa::Components::WAC_DownloadManager::on_s_authentication_required ); + + +} + + +QNetworkReply *wa::Components::WAC_DownloadManager::createRequest( Operation p_operation, const QNetworkRequest &p_request, QIODevice *p_outgoing_data ) +{ + return QNetworkAccessManager::createRequest( p_operation, p_request, p_outgoing_data ); +} + + + +/********************************************************************************** + * PRIVATE SLOTS * + **********************************************************************************/ +void wa::Components::WAC_DownloadManager::on_s_authentication_required( QNetworkReply *p_reply, QAuthenticator *p_authenticator ) +{ + Q_UNUSED( p_reply ); + Q_UNUSED( p_authenticator ); +} + + + + + +/********************************************************************************** + **********************************************************************************/ +DownloadData::DownloadData( api_httpreceiver *p_http, const char *p_url, int p_flags, ifc_downloadManagerCallback *p_callback ) +{ + flags = p_flags; + http = p_http; + callback = p_callback; + + if ( callback ) + callback->AddRef(); + + hFile = INVALID_HANDLE_VALUE; + filepath[ 0 ] = 0; + fileext = 0; + + int download_method = ( api_downloadManager::DOWNLOADEX_MASK_DOWNLOADMETHOD & flags ); + switch ( download_method ) + { + case api_downloadManager::DOWNLOADEX_TEMPFILE: + { + wchar_t temppath[ MAX_PATH - 14 ] = { 0 }; // MAX_PATH-14 'cause MSDN said so + GetTempPathW( MAX_PATH - 14, temppath ); + GetTempFileNameW( temppath, L"wdl", 0, filepath ); + hFile = CreateFileW( filepath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0 ); + } + break; + case api_downloadManager::DOWNLOADEX_CALLBACK: + if ( callback ) + callback->GetLocation( filepath, MAX_PATH ); + break; + } + + strcpy_s( this->url, 1024, p_url ); + source[ 0 ] = 0; + title[ 0 ] = 0; + if ( flags & api_downloadManager::DOWNLOADEX_CALLBACK ) + { + if ( callback ) + { + callback->GetSource( source, 1024 ); + callback->GetTitle( title, 1024 ); + } + } + + connectionStart = lastDownloadTick = GetTickCount(); + last_status = HTTPRECEIVER_STATUS_ERROR; + pending = ( flags & api_downloadManager::DOWNLOADEX_PENDING ) > 0; +} + +DownloadData::~DownloadData() +{ + ServiceRelease( http, httpreceiverGUID ); + + http = NULL; + + if ( fileext ) + delete fileext; + + int download_method = ( api_downloadManager::DOWNLOADEX_MASK_DOWNLOADMETHOD & flags ); + if ( download_method == api_downloadManager::DOWNLOADEX_TEMPFILE && filepath[ 0 ] ) + DeleteFileW( filepath ); + + if ( callback ) + callback->Release(); + + callback = NULL; +} + + +void DownloadData::Retain() +{ + this->_refCount.fetch_add( 1 ); +} + +void DownloadData::Release() +{ + if ( this->_refCount.fetch_sub( 1 ) == 0 ) + delete this; +} + + +void DownloadData::Close( ifc_downloadManagerCallback **callbackCopy ) +{ + if ( hFile != INVALID_HANDLE_VALUE ) + CloseHandle( hFile ); + + hFile = INVALID_HANDLE_VALUE; + + if ( callbackCopy != NULL ) + { + *callbackCopy = callback; + if ( callback != NULL ) + callback->AddRef(); + } + else if ( callback != NULL ) + { + callback->Release(); + callback = NULL; + } + + // don't want to close http here, because someone might still want to get the headers out of it +} + +bool DownloadData::getExtention() +{ + if ( fileext && *fileext ) + return fileext; + + char l_header_name_content_type[] = "Content-Type"; + char *l_content_type = http->getheader( l_header_name_content_type ); + if ( l_content_type && *l_content_type ) + { + if ( _CONTENT_TYPES_EXTENSIONS.count( l_content_type ) == 1 ) + fileext = _strdup( _CONTENT_TYPES_EXTENSIONS.find( l_content_type )->second.c_str() ); + } + + return fileext; +} + + + +/********************************************************************************** + **********************************************************************************/ + + /********************************************************************************** + * PUBLIC * + **********************************************************************************/ +DownloadManager::DownloadManager() +{ + download_thread = NULL; + killswitch = CreateEvent( NULL, TRUE, FALSE, NULL ); + + InitializeCriticalSection( &downloadsCS ); +} + + +void DownloadManager::Kill() +{ + SetEvent( killswitch ); + if ( download_thread ) + { + WaitForSingleObject( download_thread, 3000 ); + CloseHandle( download_thread ); + } + + DeleteCriticalSection( &downloadsCS ); + CloseHandle( killswitch ); +} + + +static void SetUserAgent( api_httpreceiver *p_http ) +{ + char agent[ 256 ] = { 0 }; + StringCchPrintfA( agent, 256, "User-Agent: %S/%S", WASABI_API_APP->main_getAppName(), WASABI_API_APP->main_getVersionNumString() ); + p_http->addheader( agent ); + + //QString l_winamp_user_agent = QString( "User-Agent: %1 Winamp/%2" ).arg( QWebEngineProfile::defaultProfile()->httpUserAgent(), STR_WINAMP_PRODUCTVER ).replace( ",", "." ); + + //http->addheader( l_winamp_user_agent.toStdString().c_str() ); +} + + +DownloadToken DownloadManager::Download( const char *url, ifc_downloadManagerCallback *callback ) +{ + return DownloadEx( url, callback, api_downloadManager::DOWNLOADEX_TEMPFILE ); +} + +DownloadToken DownloadManager::DownloadEx( const char *url, ifc_downloadManagerCallback *callback, int flags ) +{ + if ( InitDownloadThread() ) + { + api_httpreceiver *http = NULL; + + ServiceBuild( http, httpreceiverGUID ); + + if ( http ) + { + DownloadData *downloadData = new DownloadData( http, url, flags, callback ); + + int use_proxy = 1; + bool proxy80 = AGAVE_API_CONFIG->GetBool( internetConfigGroupGUID, L"proxy80", false ); + + if ( proxy80 && strstr( url, ":" ) && ( !strstr( url, ":80/" ) && strstr( url, ":80" ) != ( url + strlen( url ) - 3 ) ) ) + use_proxy = 0; + + const wchar_t *proxy = use_proxy ? AGAVE_API_CONFIG->GetString( internetConfigGroupGUID, L"proxy", 0 ) : 0; + + http->open( API_DNS_AUTODNS, DOWNLOAD_BUFFER_SIZE, ( proxy && proxy[ 0 ] ) ? (const char *)AutoChar( proxy ) : NULL ); + + SetUserAgent( http ); + + if ( callback ) + callback->OnInit( downloadData ); + + if ( downloadData->flags & api_downloadManager::DOWNLOADEX_UI ) + { + for ( ifc_downloadManagerCallback *l_status : status_callbacks ) + l_status->OnInit( downloadData ); + } + + //only call http->connect when it is not pending download request + if ( !( flags & DOWNLOADEX_PENDING ) ) + http->connect( url, 1 ); + + //http->run(); // let's get this party started + EnterCriticalSection( &downloadsCS ); + downloads.push_back( downloadData ); + LeaveCriticalSection( &downloadsCS ); + + return downloadData; + } + } + + return 0; +} + + +void DownloadManager::ResumePendingDownload( DownloadToken p_token ) +{ + if ( !p_token ) + return; + + DownloadData *data = (DownloadData *)p_token; + if ( data->pending ) + { + data->pending = false; + data->connectionStart = data->lastDownloadTick = GetTickCount(); + + data->http->connect( data->url ); + } +} + +void DownloadManager::CancelDownload( DownloadToken p_token ) +{ + if ( !p_token ) + return; + + DownloadData *data = (DownloadData *)p_token; + EnterCriticalSection( &downloadsCS ); + + if ( downloads.end() != std::find( downloads.begin(), downloads.end(), data ) ) + { + ifc_downloadManagerCallback *callback; + data->Close( &callback ); + + //downloads.eraseObject(p_data); + auto it = std::find( downloads.begin(), downloads.end(), data ); + if ( it != downloads.end() ) + { + downloads.erase( it ); + } + + LeaveCriticalSection( &downloadsCS ); + + if ( callback ) + { + callback->OnCancel( p_token ); + if ( data->flags & api_downloadManager::DOWNLOADEX_UI ) + { + for ( ifc_downloadManagerCallback *l_status : status_callbacks ) + l_status->OnCancel( p_token ); + } + + callback->Release(); + } + + data->Release(); + } + else + LeaveCriticalSection( &downloadsCS ); +} + +void DownloadManager::RetainDownload( DownloadToken p_token ) +{ + if ( !p_token ) + return; + + DownloadData *data = (DownloadData *)p_token; + if ( data ) + data->Retain(); +} + +void DownloadManager::ReleaseDownload( DownloadToken p_token ) +{ + if ( !p_token ) + return; + + DownloadData *data = (DownloadData *)p_token; + if ( data ) + data->Release(); +} + + +void DownloadManager::RegisterStatusCallback( ifc_downloadManagerCallback *callback ) +{ + EnterCriticalSection( &downloadsCS ); + status_callbacks.push_back( callback ); + LeaveCriticalSection( &downloadsCS ); +} + +void DownloadManager::UnregisterStatusCallback( ifc_downloadManagerCallback *callback ) +{ + EnterCriticalSection( &downloadsCS ); + + auto it = std::find( status_callbacks.begin(), status_callbacks.end(), callback ); + if ( it != status_callbacks.end() ) + status_callbacks.erase( it ); + + LeaveCriticalSection( &downloadsCS ); +} + + +bool DownloadManager::IsPending( DownloadToken token ) +{ + DownloadData *data = (DownloadData *)token; + if ( data ) + return data->pending; + else + return FALSE; +} + + +/********************************************************************************** + * PRIVATE * + **********************************************************************************/ +bool DownloadManager::DownloadThreadTick() +{ + unsigned int i = 0; + char *downloadBuffer = (char *)malloc( DOWNLOAD_BUFFER_SIZE ); + + while ( WaitForSingleObject( killswitch, 0 ) != WAIT_OBJECT_0 ) + { + EnterCriticalSection( &downloadsCS ); + if ( downloads.empty() ) + { + // TODO: might be nice to dynamically increase the sleep time if this happens + // (maybe to INFINITE and have Download() wake us?) + LeaveCriticalSection( &downloadsCS ); + + free( downloadBuffer ); + + return true; + } + + if ( i >= downloads.size() ) + { + LeaveCriticalSection( &downloadsCS ); + free( downloadBuffer ); + + return true; + } + + DownloadData *thisDownload = downloads[ i ]; + if ( thisDownload->pending ) + { + LeaveCriticalSection( &downloadsCS ); + } + else + { + thisDownload->Retain(); + LeaveCriticalSection( &downloadsCS ); + + + INT tick = Tick( thisDownload, downloadBuffer, DOWNLOAD_BUFFER_SIZE ); + switch ( tick ) + { + case TICK_NODATA: + // do nothing + break; + + case TICK_CONNECTING: + break; + + case TICK_CONNECTED: + if ( thisDownload->callback ) + thisDownload->callback->OnConnect( thisDownload ); + if ( thisDownload->flags & api_downloadManager::DOWNLOADEX_UI ) + { + for ( ifc_downloadManagerCallback *l_status : status_callbacks ) + l_status->OnConnect( thisDownload ); + } + break; + + case TICK_SUCCESS: + if ( thisDownload->callback ) + thisDownload->callback->OnTick( thisDownload ); + if ( thisDownload->flags & api_downloadManager::DOWNLOADEX_UI ) + { + for ( ifc_downloadManagerCallback *l_status : status_callbacks ) + l_status->OnTick( thisDownload ); + } + + // TODO: send out update l_callback + break; + + case TICK_FINISHED: + case TICK_FAILURE: + case TICK_TIMEOUT: + case TICK_CANT_CONNECT: + case TICK_WRITE_ERROR: + FinishDownload( thisDownload, tick ); + break; + } + thisDownload->Release(); + } + + i++; + } + + free( downloadBuffer ); + + return false; // we only get here when killswitch is set +} + +int DownloadManager::DownloadTickThreadPoolFunc( HANDLE handle, void *user_data, intptr_t id ) +{ + DownloadManager *dlmgr = (DownloadManager *)user_data; + if ( dlmgr->DownloadThreadTick() ) + { + TimerHandle t( handle ); + t.Wait( DOWNLOAD_SLEEP_MS ); + } + else + { + WASABI_API_THREADPOOL->RemoveHandle( 0, handle ); + SetEvent( dlmgr->download_thread ); + } + + return 0; +} + +bool DownloadManager::InitDownloadThread() +{ + if ( download_thread == NULL ) + { + download_thread = CreateEvent( 0, FALSE, FALSE, 0 ); + TimerHandle t; + WASABI_API_THREADPOOL->AddHandle( 0, t, DownloadTickThreadPoolFunc, this, 0, api_threadpool::FLAG_LONG_EXECUTION ); + t.Wait( DOWNLOAD_SLEEP_MS ); + } + + return ( download_thread != NULL ); +} + +void DownloadManager::FinishDownload( DownloadData *p_data, int code ) +{ + if ( p_data == NULL ) + return; + + ifc_downloadManagerCallback *l_callback = NULL; + + EnterCriticalSection( &downloadsCS ); + p_data->Close( &l_callback ); + LeaveCriticalSection( &downloadsCS ); + + if ( l_callback != NULL ) + { + if ( code == TICK_FINISHED ) + { + l_callback->OnFinish( p_data ); + if ( p_data->flags & api_downloadManager::DOWNLOADEX_UI ) + { + for ( ifc_downloadManagerCallback *l_data : status_callbacks ) + l_data->OnFinish( p_data ); + } + } + else + { + l_callback->OnError( p_data, code ); + if ( p_data->flags & api_downloadManager::DOWNLOADEX_UI ) + { + for ( ifc_downloadManagerCallback *l_data : status_callbacks ) + l_data->OnError( p_data, code ); + } + } + + l_callback->Release(); + } + + EnterCriticalSection( &downloadsCS ); + + auto it = std::find( downloads.begin(), downloads.end(), p_data ); + if ( it != downloads.end() ) + downloads.erase( it ); + + LeaveCriticalSection( &downloadsCS ); + + p_data->Release(); +} + +int DownloadManager::Tick( DownloadData *thisDownload, void *buffer, int bufferSize ) +{ + if ( !thisDownload ) + return api_downloadManager::TICK_FAILURE; + + int state = thisDownload->http->run(); + if ( state == HTTPRECEIVER_RUN_ERROR || thisDownload == NULL ) + return api_downloadManager::TICK_FAILURE; + + if ( !thisDownload->fileext ) + thisDownload->getExtention(); + + + int downloaded = thisDownload->http->get_bytes( buffer, bufferSize ); + if ( downloaded ) + { + switch ( thisDownload->flags & DOWNLOADEX_MASK_DOWNLOADMETHOD ) + { + case api_downloadManager::DOWNLOADEX_BUFFER: + { + thisDownload->buffer.reserve( thisDownload->http->content_length() ); + thisDownload->buffer.add( buffer, downloaded ); + } + break; + case api_downloadManager::DOWNLOADEX_TEMPFILE: + { + DWORD written = 0; + WriteFile( thisDownload->hFile, buffer, downloaded, &written, NULL ); + if ( written != downloaded ) + return api_downloadManager::TICK_WRITE_ERROR; + } + break; + case api_downloadManager::DOWNLOADEX_CALLBACK: + { + if ( thisDownload->flags & api_downloadManager::DOWNLOADEX_UI ) + { + for ( ifc_downloadManagerCallback *l_status : status_callbacks ) + l_status->OnData( thisDownload, buffer, downloaded ); + } + + if ( thisDownload->callback ) + thisDownload->callback->OnData( thisDownload, buffer, downloaded ); + } + } + + thisDownload->lastDownloadTick = GetTickCount(); + thisDownload->bytesDownloaded += downloaded; + + return api_downloadManager::TICK_SUCCESS; + } + else // nothing in the buffer + { + if ( state == HTTPRECEIVER_RUN_CONNECTION_CLOSED ) // see if the connection is closed + { + return api_downloadManager::TICK_FINISHED; // yay we're done + } + + if ( GetTickCount() - thisDownload->lastDownloadTick > DOWNLOAD_TIMEOUT_MS ) // check for timeout + return api_downloadManager::TICK_TIMEOUT; + + switch ( thisDownload->http->get_status() ) + { + case HTTPRECEIVER_STATUS_CONNECTING: + if ( thisDownload->last_status != HTTPRECEIVER_STATUS_CONNECTING ) + { + thisDownload->last_status = HTTPRECEIVER_STATUS_CONNECTING; + return api_downloadManager::TICK_CONNECTING; + } + else + { + return api_downloadManager::TICK_NODATA; + } + case HTTPRECEIVER_STATUS_READING_HEADERS: + if ( thisDownload->last_status != HTTPRECEIVER_STATUS_READING_HEADERS ) + { + thisDownload->last_status = HTTPRECEIVER_STATUS_READING_HEADERS; + return api_downloadManager::TICK_CONNECTED; + } + else + { + return api_downloadManager::TICK_NODATA; + } + } + + if ( !thisDownload->replyCode ) + thisDownload->replyCode = thisDownload->http->getreplycode(); + + switch ( thisDownload->replyCode ) + { + case 0: + case 100: + case 200: + case 201: + case 202: + case 203: + case 204: + case 205: + case 206: + return api_downloadManager::TICK_NODATA; + default: + return api_downloadManager::TICK_CANT_CONNECT; + } + } +} + + + + + +#define CBCLASS DownloadManager +START_DISPATCH; +CB( API_DOWNLOADMANAGER_DOWNLOAD, Download ) +CB( API_DOWNLOADMANAGER_DOWNLOADEX, DownloadEx ) +CB( API_DOWNLOADMANAGER_GETRECEIVER, GetReceiver ) +CB( API_DOWNLOADMANAGER_GETLOCATION, GetLocation ) +VCB( API_DOWNLOADMANAGER_SETLOCATION, SetLocation ) +CB( API_DOWNLOADMANAGER_GETEXTENTION, GetExtention ) +CB( API_DOWNLOADMANAGER_GETURL, GetUrl ) +CB( API_DOWNLOADMANAGER_GETBYTESDOWNLOADED, GetBytesDownloaded ); +CB( API_DOWNLOADMANAGER_GETBUFFER, GetBuffer ); +VCB( API_DOWNLOADMANAGER_RESUMEPENDINGDOWNLOAD, ResumePendingDownload ); +VCB( API_DOWNLOADMANAGER_CANCELDOWNLOAD, CancelDownload ); +VCB( API_DOWNLOADMANAGER_RETAINDOWNLOAD, RetainDownload ); +VCB( API_DOWNLOADMANAGER_RELEASEDOWNLOAD, ReleaseDownload ); +VCB( API_DOWNLOADMANAGER_REGISTERSTATUSCALLBACK, RegisterStatusCallback ); +VCB( API_DOWNLOADMANAGER_UNREGISTERSTATUSCALLBACK, UnregisterStatusCallback ); +CB( API_DOWNLOADMANAGER_GETSOURCE, GetSource ); +CB( API_DOWNLOADMANAGER_GETTITLE, GetTitle ); +CB( API_DOWNLOADMANAGER_ISPENDING, IsPending ); +END_DISPATCH; +#undef CBCLASS diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.h b/Src/Components/wac_downloadManager/wac_downloadManager.h new file mode 100644 index 00000000..aa06819c --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager.h @@ -0,0 +1,318 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOAD_MANAGER_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOAD_MANAGER_H + +#include <vector> +#include <map> +#include <string> // for string class +#include <atomic> + +#include <QtCore> +#include <QAuthenticator> +#include <QNetworkAccessManager> +#include <QNetworkRequest> +#include <QNetworkReply> + +#include <QUrl> +#include <QUrlQuery> + +#include "../nu/GrowBuf.h" + +//#include "main.h" + +//#include "wac_downloadManager_Headers.h" + +#include "wac_download_http_receiver.h" +//#include "wac_download_http_receiver_api.h" + +#include "wac_downloadManager_api.h" + +//#include "../wac_network/wac_network_http_receiver_api.h" + +#define MAX_SIMULTANEOUS_DOWNLOADS 2 + +static std::map<std::string, std::string> _CONTENT_TYPES_EXTENSIONS = { + { "audio/aac", "aac" }, + { "audio/mp4", "mp4" }, + { "audio/MPA", "MPA" }, + { "audio/mpeg", "mp3" }, + { "audio/opus", "opus" }, + { "audio/ogg", "ogg" }, + { "audio/vorbis", "vorbis" }, + { "audio/wav", "wav" }, + { "video/mp2t", "ts" }, + { "video/mp4", "mp4" }, + { "video/mpeg", "mpeg" }, + { "video/ogg", "ogv" }, + { "video/x-matroska", "mkv" }, + { "video/x-msvideo", "avi" } +}; + + + +namespace wa +{ + namespace Components + { + class WAC_DownloadData : public QObject + { + Q_OBJECT + + public: + WAC_DownloadData( api_wac_download_manager_http_receiver *p_http, const char *p_url, int p_flags, ifc_downloadManagerCallback *p_callback ); + ~WAC_DownloadData(); + + void Retain(); + void Release(); + + void Close( ifc_downloadManagerCallback **callbackCopy ); + + bool getExtention(); + + api_wac_download_manager_http_receiver *_http = Q_NULLPTR; + ifc_downloadManagerCallback *_callback = Q_NULLPTR; + + int _flags = 0; + + HANDLE _hFile; // handle to the open file where data is written to + + DWORD _lastDownloadTick; // last time we got data out of the connection. used for timeout + DWORD _connectionStart; // used for when the connection starts, to help us calculate a k/s download rate + + wchar_t _filepath[ MAX_PATH ]; // where file is downloaded to. probably a temp path + char *_fileext = 0; + char _url[ 1024 ]; + wchar_t _source[ 1024 ]; + wchar_t _title[ 1024 ]; + + int _replyCode = 0; // HTTP 200, 404, etc. + uint64_t _bytesDownloaded = 0; + int _last_status; // from http->get_status() + bool _pending; + + GrowBuf _buffer; + + + private: + std::atomic<std::size_t> _refCount = 1; + + + }; + + class WAC_DownloadManager : public QNetworkAccessManager, public api_downloadManager + { + Q_OBJECT + + public: + WAC_DownloadManager( QObject *parent = Q_NULLPTR ); + ~WAC_DownloadManager(); + + static const char *getServiceName() { return "Download Manager Service"; } + static GUID getServiceGuid() { return DownloadManagerGUID; } + + DownloadToken Download( const char *p_url, ifc_downloadManagerCallback *p_callback ); + DownloadToken DownloadEx( const char *p_url, ifc_downloadManagerCallback *p_callback, int p_flags ); + + + private: + void init(); + + QNetworkReply *createRequest( Operation p_operation, const QNetworkRequest &p_request, QIODevice *p_outgoing_data = Q_NULLPTR ); + + QMetaObject::Connection _connection_authentication_required; + + std::map<std::string, wa::Components::WAC_Download_HTTP_Receiver *> _runing_downloads; + std::map<std::string, wa::Components::WAC_Download_HTTP_Receiver *> _pending_downloads; + + + private Q_SLOTS: + void on_s_authentication_required( QNetworkReply *p_reply, QAuthenticator *p_authenticator ); + }; + } +} + + + + + + +#pragma region "DownloadData" +struct DownloadData +{ + DownloadData( api_httpreceiver *http, const char *url, int flags, ifc_downloadManagerCallback *callback ); + ~DownloadData(); + + void Retain(); + void Release(); + + void Close( ifc_downloadManagerCallback **callbackCopy ); + + bool getExtention(); + + api_httpreceiver *http = NULL; + ifc_downloadManagerCallback *callback = NULL; + + wchar_t filepath[ MAX_PATH ]; // where file is downloaded to. probably a temp path + char *fileext = 0; + char url[ 1024 ]; + wchar_t source[ 1024 ]; + wchar_t title[ 1024 ]; + + HANDLE hFile; // handle to the open file where data is written to + DWORD lastDownloadTick; // last time we got data out of the connection. used for timeout + DWORD connectionStart; // used for when the connection starts, to help us calculate a k/s download rate + + int replyCode = 0; // HTTP 200, 404, etc. + uint64_t bytesDownloaded = 0; + int last_status; // from http->get_status() + bool pending; + + int flags; + GrowBuf buffer; + +private: + std::atomic<std::size_t> _refCount = 1; +}; +#pragma endregion + + +/* method ideas + +Download(url, owner_token, callback, user_data) +Lock() - call before enumerating and doing anything +Unlock() +CancelDownload() +Enum(owner_token) + +*/ + +class DownloadManager : public api_downloadManager +{ +public: + static const char *getServiceName() { return "Download Manager"; } + static GUID getServiceGuid() { return DownloadManagerGUID; } + + DownloadManager(); + + void Kill(); + + DownloadToken Download( const char *url, ifc_downloadManagerCallback *callback ); + DownloadToken DownloadEx( const char *url, ifc_downloadManagerCallback *callback, int flags ); + + void ResumePendingDownload( DownloadToken token ); + void CancelDownload( DownloadToken token ); + void RetainDownload( DownloadToken token ); + void ReleaseDownload( DownloadToken token ); + + void RegisterStatusCallback( ifc_downloadManagerCallback *callback ); + void UnregisterStatusCallback( ifc_downloadManagerCallback *callback ); + + bool IsPending( DownloadToken token ); + + /* + only call these during a callback! + */ + api_httpreceiver *GetReceiver( DownloadToken token ) + { + if ( token ) + return ( (DownloadData *)token )->http; + else + return 0; + } + + const wchar_t *GetLocation( DownloadToken token ) + { + if ( token ) + return ( (DownloadData *)token )->filepath; + else + return 0; + } + + const wchar_t *GetSource( DownloadToken p_token ) + { + if ( !p_token ) + return 0; + + DownloadData *data = (DownloadData *)p_token; + if ( data ) + return data->source; + else + return 0; + } + + const wchar_t *GetTitle( DownloadToken p_token ) + { + if ( !p_token ) + return 0; + + DownloadData *data = (DownloadData *)p_token; + if ( data ) + return data->title; + else + return 0; + } + + void SetLocation( DownloadToken token, const wchar_t *p_location ) + { + if ( token ) + wcscpy( ( (DownloadData *)token )->filepath, p_location ); + } + + const char *GetExtention( DownloadToken token ) + { + if ( token ) + return ( (DownloadData *)token )->fileext; + else + return 0; + } + + const char *GetUrl( DownloadToken token ) + { + if ( token ) + return ( (DownloadData *)token )->url; + else + return 0; + } + + int GetBuffer( DownloadToken token, void **buffer, size_t *bufferlen ) + { + if ( token ) + { + *buffer = ( (DownloadData *)token )->buffer.get(); + *bufferlen = ( (DownloadData *)token )->buffer.getlen(); + + return 0; + } + else + return 1; + } + + uint64_t GetBytesDownloaded( DownloadToken token ) + { + if ( token ) + return ( (DownloadData *)token )->bytesDownloaded; + else + return 0; + } + +private: + CRITICAL_SECTION downloadsCS; + + bool DownloadThreadTick(); + static int DownloadTickThreadPoolFunc( HANDLE handle, void *user_data, intptr_t id ); + + bool InitDownloadThread(); + void FinishDownload( DownloadData *data, int code ); + int Tick( DownloadData *thisDownload, void *buffer, int bufferSize ); + + HANDLE download_thread; + HANDLE killswitch; + + std::vector<DownloadData *> downloads; + typedef std::vector<ifc_downloadManagerCallback *> StatusList; + StatusList status_callbacks; + +protected: + RECVS_DISPATCH; +}; + +#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_DOWNLOAD_MANAGER_H diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.rc b/Src/Components/wac_downloadManager/wac_downloadManager.rc new file mode 100644 index 00000000..fcff7711 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager.rc @@ -0,0 +1,76 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "#include ""version.rc2""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#include "version.rc2" + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj b/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj new file mode 100644 index 00000000..4238f73b --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj @@ -0,0 +1,209 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="17.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{66827D3B-AA81-4F38-A671-A0C9B0C2E21D}</ProjectGuid> + <Keyword>QtVS_v304</Keyword> + <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'">10.0.19041.0</WindowsTargetPlatformVersion> + <WindowsTargetPlatformVersion Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'">10.0.19041.0</WindowsTargetPlatformVersion> + <QtMsBuild Condition="'$(QtMsBuild)'=='' OR !Exists('$(QtMsBuild)\qt.targets')">$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <UseDebugLibraries>true</UseDebugLibraries> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration"> + <ConfigurationType>DynamicLibrary</ConfigurationType> + <PlatformToolset>v142</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')"> + <Import Project="$(QtMsBuild)\qt_defaults.props" /> + </ImportGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="QtSettings"> + <QtInstall>5.15.2_msvc2019</QtInstall> + <QtModules>core;network;concurrent;webengine;webenginewidgets</QtModules> + <QtBuildConfig>debug</QtBuildConfig> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="QtSettings"> + <QtInstall>5.15.2_msvc2019</QtInstall> + <QtModules>core;network;concurrent;webengine;webenginewidgets</QtModules> + <QtBuildConfig>release</QtBuildConfig> + </PropertyGroup> + <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')"> + <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." /> + </Target> + <ImportGroup Label="ExtensionSettings" /> + <ImportGroup Label="Shared" /> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(QtMsBuild)\Qt.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="$(QtMsBuild)\Qt.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'"> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <TargetExt>.w5s</TargetExt> + <LinkIncremental>false</LinkIncremental> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'"> + <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir> + <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir> + <TargetExt>.w5s</TargetExt> + <LinkIncremental>false</LinkIncremental> + <IncludePath>$(IncludePath)</IncludePath> + <LibraryPath>$(LibraryPath)</LibraryPath> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <AdditionalIncludeDirectories>..\..\Wasabi;..\..\replicant;%(AdditionalIncludeDirectories);$(Qt_INCLUDEPATH_)</AdditionalIncludeDirectories> + <WarningLevel>Level3</WarningLevel> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <FavorSizeOrSpeed>Size</FavorSizeOrSpeed> + <StringPooling>true</StringPooling> + </ClCompile> + <Link> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <AdditionalDependencies>comctl32.lib;ws2_32.lib;Crypt32.lib;shlwapi.lib;%(AdditionalDependencies);$(Qt_LIBS_)</AdditionalDependencies> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> + <AdditionalIncludeDirectories>..\..\Wasabi;..\..\replicant;%(AdditionalIncludeDirectories);$(Qt_INCLUDEPATH_)</AdditionalIncludeDirectories> + <SupportJustMyCode>false</SupportJustMyCode> + <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> + </ClCompile> + <Link> + <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers> + <RandomizedBaseAddress>false</RandomizedBaseAddress> + <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> + <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile> + <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary> + <AdditionalDependencies>comctl32.lib;ws2_32.lib;Crypt32.lib;shlwapi.lib;%(AdditionalDependencies);$(Qt_LIBS_)</AdditionalDependencies> + </Link> + <PostBuildEvent> + <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ +xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\</Command> + <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System'</Message> + </PostBuildEvent> + </ItemDefinitionGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <VcpkgUseStatic>true</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + </PropertyGroup> + <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <VcpkgUseStatic>true</VcpkgUseStatic> + <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet> + <VcpkgInstalledDir> + </VcpkgInstalledDir> + </PropertyGroup> + <PropertyGroup Label="Vcpkg"> + <VcpkgEnabled>true</VcpkgEnabled> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|Win32'" Label="Configuration"> + <ClCompile> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> + <Optimization>Disabled</Optimization> + <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> + <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;USE_SSL;WAC_DOWNLOAD_MANAGER_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Release|Win32'" Label="Configuration"> + <ClCompile> + <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType> + <MultiProcessorCompilation>true</MultiProcessorCompilation> + <DebugInformationFormat>None</DebugInformationFormat> + <Optimization>MinSpace</Optimization> + <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> + <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;USE_SSL;WAC_DOWNLOAD_MANAGER_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Windows</SubSystem> + <GenerateDebugInformation>false</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="BackgroundDownloader.cpp" /> + <ClCompile Include="wac_downloadManager.cpp"> + <DynamicSource Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">input</DynamicSource> + <QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(Filename).moc</QtMocFileName> + <DynamicSource Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">input</DynamicSource> + <QtMocFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(Filename).moc</QtMocFileName> + </ClCompile> + <ClCompile Include="wac_downloadManager_api.cpp" /> + <ClCompile Include="wac_downloadManager_factory.cpp" /> + <ClCompile Include="wac_download_http_receiver.cpp" /> + <ClCompile Include="wac_download_http_receiver_api.cpp" /> + <ClCompile Include="wac_download_http_receiver_factory.cpp" /> + <ClInclude Include="resource.h" /> + <ClInclude Include="wac_downloadManager_api.h" /> + <ClInclude Include="api__wac_downloadManager.h" /> + <ClInclude Include="BackgroundDownloader.h" /> + <ClInclude Include="DownloadCallbackT.h" /> + <ClInclude Include="wac_downloadManager_factory.h" /> + <ClInclude Include="wac_downloadManager_global.h" /> + <ClInclude Include="main.h" /> + <ClCompile Include="main.cpp" /> + <ClInclude Include="wac_downloadManager_Headers.h" /> + <ClInclude Include="wac_download_http_receiver_api.h" /> + <ClInclude Include="wac_download_http_receiver_factory.h" /> + <QtMoc Include="wac_download_http_receiver.h" /> + <QtMoc Include="wac_downloadManager.h" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\tataki\tataki.vcxproj"> + <Project>{255b68b5-7ef8-45ef-a675-2d6b88147909}</Project> + </ProjectReference> + <ProjectReference Include="..\..\Wasabi\Wasabi.vcxproj"> + <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="wac_downloadManager.rc" /> + </ItemGroup> + <ItemGroup> + <None Include="version.rc2" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Condition="Exists('$(QtMsBuild)\qt.targets')"> + <Import Project="$(QtMsBuild)\qt.targets" /> + </ImportGroup> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj.filters b/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj.filters new file mode 100644 index 00000000..7deccab2 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager.vcxproj.filters @@ -0,0 +1,118 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>qml;cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + <Filter Include="Form Files"> + <UniqueIdentifier>{99349809-55BA-4b9d-BF79-8FDBB0286EB3}</UniqueIdentifier> + <Extensions>ui</Extensions> + </Filter> + <Filter Include="Translation Files"> + <UniqueIdentifier>{639EADAA-A684-42e4-A9AD-28FC9BCB8F7C}</UniqueIdentifier> + <Extensions>ts</Extensions> + </Filter> + <Filter Include="Header Files\HTTP Receiver"> + <UniqueIdentifier>{738d86e2-2471-4e0d-bcb4-dd3b1c132c01}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\downloadManager"> + <UniqueIdentifier>{ddf711c1-7782-4349-9835-758b85fcfe53}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\HTTP Receiver"> + <UniqueIdentifier>{9892fa19-d3f5-43cf-a433-aa513290ca0d}</UniqueIdentifier> + </Filter> + <Filter Include="Source Files\downloadManager"> + <UniqueIdentifier>{c31b92ff-4576-420f-885a-333d90811b9b}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClInclude Include="main.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="api__wac_downloadManager.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="BackgroundDownloader.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="DownloadCallbackT.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_download_http_receiver_factory.h"> + <Filter>Header Files\HTTP Receiver</Filter> + </ClInclude> + <ClInclude Include="wac_download_http_receiver_api.h"> + <Filter>Header Files\HTTP Receiver</Filter> + </ClInclude> + <ClInclude Include="wac_downloadManager_api.h"> + <Filter>Header Files\downloadManager</Filter> + </ClInclude> + <ClInclude Include="wac_downloadManager_factory.h"> + <Filter>Header Files\downloadManager</Filter> + </ClInclude> + <ClCompile Include="wac_downloadManager_api.cpp"> + <Filter>Source Files\downloadManager</Filter> + </ClCompile> + <ClCompile Include="wac_downloadManager_factory.cpp"> + <Filter>Source Files\downloadManager</Filter> + </ClCompile> + <ClCompile Include="wac_download_http_receiver.cpp"> + <Filter>Source Files\HTTP Receiver</Filter> + </ClCompile> + <ClCompile Include="wac_download_http_receiver_api.cpp"> + <Filter>Source Files\HTTP Receiver</Filter> + </ClCompile> + <ClCompile Include="wac_download_http_receiver_factory.cpp"> + <Filter>Source Files\HTTP Receiver</Filter> + </ClCompile> + <ClCompile Include="wac_downloadManager.cpp"> + <Filter>Source Files\downloadManager</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClCompile Include="BackgroundDownloader.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <QtMoc Include="wac_download_http_receiver.h"> + <Filter>Header Files\HTTP Receiver</Filter> + </QtMoc> + <QtMoc Include="wac_downloadManager.h"> + <Filter>Header Files\downloadManager</Filter> + </QtMoc> + </ItemGroup> + <ItemGroup> + <ClInclude Include="wac_downloadManager_global.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="wac_downloadManager_Headers.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="resource.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="wac_downloadManager.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> + <ItemGroup> + <None Include="version.rc2"> + <Filter>Resource Files</Filter> + </None> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_Headers.h b/Src/Components/wac_downloadManager/wac_downloadManager_Headers.h new file mode 100644 index 00000000..5c0ac00a --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager_Headers.h @@ -0,0 +1,9 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_HEADERS_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_HEADERS_H + +#include "wac_downloadManager.h" +#include "wac_download_http_receiver.h" + + +#endif // NULLSOFT_WAC_DOWNLOAD_MANAGER_HEADERS_H + diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_api.cpp b/Src/Components/wac_downloadManager/wac_downloadManager_api.cpp new file mode 100644 index 00000000..54f5a1d3 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager_api.cpp @@ -0,0 +1 @@ +#include "wac_downloadManager_api.h"
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_api.h b/Src/Components/wac_downloadManager/wac_downloadManager_api.h new file mode 100644 index 00000000..99ce9a79 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager_api.h @@ -0,0 +1,274 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_API_DOWNLOADMANAGER_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_API_DOWNLOADMANAGER_H + +#include "bfc/dispatch.h" + +typedef void *DownloadToken; + +class ifc_downloadManagerCallback; +class api_httpreceiver; + +class ifc_downloadManagerCallback : public Dispatchable +{ +public: + void OnFinish( DownloadToken token ); + void OnTick( DownloadToken token ); + void OnError( DownloadToken token, int error ); + void OnCancel( DownloadToken token ); + void OnConnect( DownloadToken token ); + void OnInit( DownloadToken token ); + void OnData( DownloadToken token, void *data, size_t datalen ); + + int GetSource( wchar_t *source, size_t source_cch ); + int GetTitle( wchar_t *title, size_t title_cch ); + int GetLocation( wchar_t *location, size_t location_cch ); + + DISPATCH_CODES + { + IFC_DOWNLOADMANAGERCALLBACK_ONFINISH = 10, + IFC_DOWNLOADMANAGERCALLBACK_ONTICK = 20, + IFC_DOWNLOADMANAGERCALLBACK_ONERROR = 30, + IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL = 40, + IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT = 50, + IFC_DOWNLOADMANAGERCALLBACK_ONINIT = 60, + IFC_DOWNLOADMANAGERCALLBACK_ONDATA = 70, + IFC_DOWNLOADMANAGERCALLBACK_GETSOURCE = 80, + IFC_DOWNLOADMANAGERCALLBACK_GETTITLE = 90, + IFC_DOWNLOADMANAGERCALLBACK_GETLOCATION = 100, + }; +}; + +inline void ifc_downloadManagerCallback::OnFinish( DownloadToken token ) +{ + _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, token ); +} + +inline void ifc_downloadManagerCallback::OnTick( DownloadToken token ) +{ + _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONTICK, token ); +} + +inline void ifc_downloadManagerCallback::OnError( DownloadToken token, int error ) +{ + _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, token, error ); +} + +inline void ifc_downloadManagerCallback::OnCancel( DownloadToken token ) +{ + _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, token ); +} + +inline void ifc_downloadManagerCallback::OnConnect( DownloadToken token ) +{ + _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, token ); +} + +inline void ifc_downloadManagerCallback::OnInit( DownloadToken token ) +{ + _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, token ); +} + +inline void ifc_downloadManagerCallback::OnData( DownloadToken token, void *data, size_t datalen ) +{ + _voidcall( IFC_DOWNLOADMANAGERCALLBACK_ONDATA, token, data, datalen ); +} + +inline int ifc_downloadManagerCallback::GetSource( wchar_t *source, size_t source_cch ) +{ + return _call( IFC_DOWNLOADMANAGERCALLBACK_GETSOURCE, (int)1, source, source_cch ); +} + +inline int ifc_downloadManagerCallback::GetTitle( wchar_t *title, size_t title_cch ) +{ + return _call( IFC_DOWNLOADMANAGERCALLBACK_GETTITLE, (int)1, title, title_cch ); +} + +inline int ifc_downloadManagerCallback::GetLocation( wchar_t *location, size_t location_cch ) +{ + return _call( IFC_DOWNLOADMANAGERCALLBACK_GETLOCATION, (int)1, location, location_cch ); +} + + +class api_downloadManager : public Dispatchable +{ +public: + DownloadToken Download( const char *url, ifc_downloadManagerCallback *callback ); + DownloadToken DownloadEx( const char *url, ifc_downloadManagerCallback *callback, int flags ); + + api_httpreceiver *GetReceiver( DownloadToken token ); + const wchar_t *GetLocation( DownloadToken token ); + void SetLocation( DownloadToken token, const wchar_t *p_location ); + + + const char *GetExtention( DownloadToken token ); + const char *GetUrl( DownloadToken token ); + + int GetBuffer( DownloadToken token, void **buffer, size_t *bufferLength ); + uint64_t GetBytesDownloaded( DownloadToken token ); + + void ResumePendingDownload( DownloadToken token ); + void CancelDownload( DownloadToken token ); + void RetainDownload( DownloadToken token ); + void ReleaseDownload( DownloadToken token ); + + /* added in 5.58 */ + void RegisterStatusCallback( ifc_downloadManagerCallback *callback ); + void UnregisterStatusCallback( ifc_downloadManagerCallback *callback ); + + const wchar_t *GetSource( DownloadToken token ); + const wchar_t *GetTitle( DownloadToken token ); + + bool IsPending( DownloadToken token ); + + DISPATCH_CODES + { + API_DOWNLOADMANAGER_DOWNLOAD = 10, + API_DOWNLOADMANAGER_DOWNLOADEX = 20, + API_DOWNLOADMANAGER_GETRECEIVER = 100, + API_DOWNLOADMANAGER_GETLOCATION = 110, + API_DOWNLOADMANAGER_SETLOCATION = 112, + API_DOWNLOADMANAGER_GETEXTENTION = 115, + API_DOWNLOADMANAGER_GETURL = 117, + API_DOWNLOADMANAGER_GETBYTESDOWNLOADED = 120, + API_DOWNLOADMANAGER_GETBUFFER = 130, + API_DOWNLOADMANAGER_CANCELDOWNLOAD = 140, + API_DOWNLOADMANAGER_RETAINDOWNLOAD = 150, + API_DOWNLOADMANAGER_RELEASEDOWNLOAD = 160, + API_DOWNLOADMANAGER_REGISTERSTATUSCALLBACK = 170, + API_DOWNLOADMANAGER_UNREGISTERSTATUSCALLBACK = 180, + API_DOWNLOADMANAGER_GETSOURCE = 190, + API_DOWNLOADMANAGER_GETTITLE = 200, + API_DOWNLOADMANAGER_RESUMEPENDINGDOWNLOAD = 210, + API_DOWNLOADMANAGER_ISPENDING = 220, + }; + + enum + { + DOWNLOADEX_TEMPFILE = 0, // download as a temporary file + DOWNLOADEX_BUFFER = 1, // download to memory + DOWNLOADEX_CALLBACK = 2, // send data to OnData callback + DOWNLOADEX_MASK_DOWNLOADMETHOD = 0x3, + DOWNLOADEX_PENDING = 0xF00, + DOWNLOADEX_UI = 0xF000, // show up in the download manager UI + }; + + enum + { + TICK_NODATA = -2, // not necessarily an error, just means no data this time around + TICK_FINISHED = -1, + TICK_SUCCESS = 0, + TICK_FAILURE = 1, + TICK_TIMEOUT = 2, + TICK_CANT_CONNECT = 3, + TICK_WRITE_ERROR = 4, + TICK_CONNECTING = 5, + TICK_CONNECTED = 6, + + }; +}; + + +inline DownloadToken api_downloadManager::Download( const char *url, ifc_downloadManagerCallback *callback ) +{ + return _call( API_DOWNLOADMANAGER_DOWNLOAD, (DownloadToken *)0, url, callback ); +} + +inline DownloadToken api_downloadManager::DownloadEx( const char *url, ifc_downloadManagerCallback *callback, int flags ) +{ + return _call( API_DOWNLOADMANAGER_DOWNLOADEX, (DownloadToken *)0, url, callback, flags ); +} + +inline api_httpreceiver *api_downloadManager::GetReceiver( DownloadToken token ) +{ + return _call( API_DOWNLOADMANAGER_GETRECEIVER, (api_httpreceiver *)0, token ); +} + +inline const wchar_t *api_downloadManager::GetLocation( DownloadToken token ) +{ + return _call( API_DOWNLOADMANAGER_GETLOCATION, (const wchar_t *)0, token ); +} + +inline void api_downloadManager::SetLocation( DownloadToken token, const wchar_t *p_location ) +{ + _voidcall( API_DOWNLOADMANAGER_SETLOCATION, token, p_location ); +} + +inline const char *api_downloadManager::GetExtention( DownloadToken token ) +{ + return _call( API_DOWNLOADMANAGER_GETEXTENTION, (const char *)0, token ); +} + +inline const char *api_downloadManager::GetUrl( DownloadToken token ) +{ + return _call( API_DOWNLOADMANAGER_GETURL, (const char *)0, token ); +} + +inline uint64_t api_downloadManager::GetBytesDownloaded( DownloadToken token ) +{ + return _call( API_DOWNLOADMANAGER_GETBYTESDOWNLOADED, (uint64_t)0, token ); +} + +inline int api_downloadManager::GetBuffer( DownloadToken token, void **buffer, size_t *bufferLength ) +{ + return _call( API_DOWNLOADMANAGER_GETBUFFER, (int)1, token, buffer, bufferLength ); +} + +inline void api_downloadManager::ResumePendingDownload( DownloadToken token ) +{ + _voidcall( API_DOWNLOADMANAGER_RESUMEPENDINGDOWNLOAD, token ); +} + +inline void api_downloadManager::CancelDownload( DownloadToken token ) +{ + _voidcall( API_DOWNLOADMANAGER_CANCELDOWNLOAD, token ); +} + +inline void api_downloadManager::RetainDownload( DownloadToken token ) +{ + _voidcall( API_DOWNLOADMANAGER_RETAINDOWNLOAD, token ); +} + +inline void api_downloadManager::ReleaseDownload( DownloadToken token ) +{ + _voidcall( API_DOWNLOADMANAGER_RELEASEDOWNLOAD, token ); +} + + +inline void api_downloadManager::RegisterStatusCallback( ifc_downloadManagerCallback *callback ) +{ + _voidcall( API_DOWNLOADMANAGER_REGISTERSTATUSCALLBACK, callback ); +} + +inline void api_downloadManager::UnregisterStatusCallback( ifc_downloadManagerCallback *callback ) +{ + _voidcall( API_DOWNLOADMANAGER_UNREGISTERSTATUSCALLBACK, callback ); +} + + +inline const wchar_t *api_downloadManager::GetSource( DownloadToken token ) +{ + return _call( API_DOWNLOADMANAGER_GETSOURCE, (const wchar_t *)0, token ); +} + +inline const wchar_t *api_downloadManager::GetTitle( DownloadToken token ) +{ + return _call( API_DOWNLOADMANAGER_GETTITLE, (const wchar_t *)0, token ); +} + +inline bool api_downloadManager::IsPending( DownloadToken token ) +{ + return _call( API_DOWNLOADMANAGER_ISPENDING, (bool)0, token ); +} + + +// {9E5E732A-C612-489d-AB52-1501E1AF1710} +static const GUID DownloadManagerGUID = +{ 0x9e5e732a, 0xc612, 0x489d, { 0xab, 0x52, 0x15, 0x1, 0xe1, 0xaf, 0x17, 0x10 } }; + +extern api_downloadManager *g_downloadManagerApi; + +#ifndef WAC_API_DOWNLOADMANAGER +#define WAC_API_DOWNLOADMANAGER g_downloadManagerApi +#endif // !WAC_API_DOWNLOADMANAGER + +#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_API_DOWNLOADMANAGER_H diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_factory.cpp b/Src/Components/wac_downloadManager/wac_downloadManager_factory.cpp new file mode 100644 index 00000000..eb7cacf4 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager_factory.cpp @@ -0,0 +1,88 @@ +#include "wac_downloadManager_factory.h" + +static const char serviceName[] = "WAC Downloads"; +static const char testString[] = "Downloads Component"; + +// {B000EE81-199F-48C2-BDCB-F7E3C31A2A13} +static const GUID api_downloads_GUID = { 0xb000ee81, 0x199f, 0x48c2, { 0xbd, 0xcb, 0xf7, 0xe3, 0x1a, 0x12, 0x2a, 0x13 } }; + + +FOURCC wa::Components::WAC_DownloadManagerFactory::GetServiceType() +{ + return WaSvc::UNIQUE; +} + +const char *wa::Components::WAC_DownloadManagerFactory::GetServiceName() +{ + return serviceName; +} + +GUID wa::Components::WAC_DownloadManagerFactory::GetGUID() +{ + return api_downloads_GUID; +} + +const char *wa::Components::WAC_DownloadManagerFactory::GetTestString() +{ + return testString; +} + + +void *wa::Components::WAC_DownloadManagerFactory::GetInterface( int global_lock ) +{ + return nullptr; +} + +int wa::Components::WAC_DownloadManagerFactory::ReleaseInterface( void *ifc ) +{ + return 1; +} + + +int wa::Components::WAC_DownloadManagerFactory::SupportNonLockingInterface() +{ + return 1; +} + +int wa::Components::WAC_DownloadManagerFactory::ServiceNotify( int msg, int param1, int param2 ) +{ + return 1; +} + + +HRESULT wa::Components::WAC_DownloadManagerFactory::Register( api_service *p_service ) +{ + if ( p_service == NULL ) + return E_INVALIDARG; + + p_service->service_register( this ); + + return S_OK; +} + +HRESULT wa::Components::WAC_DownloadManagerFactory::Unregister( api_service *p_service ) +{ + if ( p_service == NULL ) + return E_INVALIDARG; + + p_service->service_deregister( this ); + + return S_OK; +} + + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS wa::Components::WAC_DownloadManagerFactory +START_DISPATCH; +CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType ) +CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName ) +CB( WASERVICEFACTORY_GETGUID, GetGUID ) +CB( WASERVICEFACTORY_GETINTERFACE, GetInterface ) +CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface ) +CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface ) +CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString ) +CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify ) +END_DISPATCH;
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_factory.h b/Src/Components/wac_downloadManager/wac_downloadManager_factory.h new file mode 100644 index 00000000..98d52030 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager_factory.h @@ -0,0 +1,37 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_H + +#include "api__wac_downloadManager.h" + +#include "api/service/waservicefactory.h" +#include "api/service/services.h" + +namespace wa +{ + namespace Components + { + class WAC_DownloadManagerFactory : public waServiceFactory + { + public: + FOURCC GetServiceType(); + const char *GetServiceName(); + GUID GetGUID(); + const char *GetTestString(); + + void *GetInterface( int global_lock ); + int ReleaseInterface( void *ifc ); + + int SupportNonLockingInterface(); + int ServiceNotify( int msg, int param1, int param2 ); + + HRESULT Register( api_service *p_service ); + HRESULT Unregister( api_service *p_service ); + + + protected: + RECVS_DISPATCH; + }; + } +} + +#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_H diff --git a/Src/Components/wac_downloadManager/wac_downloadManager_global.h b/Src/Components/wac_downloadManager/wac_downloadManager_global.h new file mode 100644 index 00000000..c670ccae --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_downloadManager_global.h @@ -0,0 +1,16 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_GLOBAL_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifndef BUILD_STATIC +# if defined(WAC_DOWNLOAD_MANAGER_LIB) +# define WAC_DOWNLOAD_MANAGER_EXPORT Q_DECL_EXPORT +# else +# define WAC_DOWNLOAD_MANAGER_EXPORT Q_DECL_IMPORT +# endif +#else +# define WAC_DOWNLOAD_MANAGER_EXPORT +#endif + +#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_GLOBAL_H
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver.cpp b/Src/Components/wac_downloadManager/wac_download_http_receiver.cpp new file mode 100644 index 00000000..46482862 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_download_http_receiver.cpp @@ -0,0 +1,64 @@ +#include "wac_download_http_receiver.h" + + +wa::Components::WAC_Download_HTTP_Receiver::WAC_Download_HTTP_Receiver() +{} + +wa::Components::WAC_Download_HTTP_Receiver::~WAC_Download_HTTP_Receiver() +{} + +void wa::Components::WAC_Download_HTTP_Receiver::open( api_dns * p_dns, size_t p_recvbufsize, const char *p_proxy ) +{ + Q_UNUSED( p_dns ) + Q_UNUSED( p_recvbufsize ) + Q_UNUSED( p_proxy ) +} + + +std::size_t wa::Components::WAC_Download_HTTP_Receiver::AddRef() +{ + return this->_reference_count.fetch_add( 1 ); +} + +std::size_t wa::Components::WAC_Download_HTTP_Receiver::Release() +{ + std::size_t l_reference_count = this->_reference_count.fetch_sub( 1 ); + if ( l_reference_count == 0 ) + delete this; + + return l_reference_count; +} + + +#ifdef CBCLASS +#undef CBCLASS +#endif + +#define CBCLASS wa::Components::WAC_Download_HTTP_Receiver +START_DISPATCH; +CB( ADDREF, AddRef ) +CB( RELEASE, Release ) +VCB( API_HTTPRECEIVER_OPEN, open ) +//VCB( API_HTTPRECEIVER_ADDHEADER, addheader ) +//VCB( API_HTTPRECEIVER_ADDHEADERVALUE, addheadervalue ) +//VCB( API_HTTPRECEIVER_CONNECT, connect ) +//CB( API_HTTPRECEIVER_RUN, run ) +//CB( API_HTTPRECEIVER_GETSTATUS, get_status ) +//CB( API_HTTPRECEIVER_GETBYTESAVAILABLE, bytes_available ) +//CB( API_HTTPRECEIVER_GETBYTES, get_bytes ) +//CB( API_HTTPRECEIVER_PEEKBYTES, peek_bytes ) +//CB( API_HTTPRECEIVER_GETHEADER, getheader ) +//CB( API_HTTPRECEIVER_GETCONTENTLENGTH, content_length ) +//CB( API_HTTPRECEIVER_GETALLHEADERS, getallheaders ) +//CB( API_HTTPRECEIVER_GETREPLYCODE, getreplycode ) +//CB( API_HTTPRECEIVER_GETREPLY, getreply ) +//CB( API_HTTPRECEIVER_GETERROR, geterrorstr ) +//CB( API_HTTPRECEIVER_GETCONNECTION, get_con ) +//VCB( API_HTTPRECEIVER_ALLOW_COMPRESSION, AllowCompression ) +//VCB( API_HTTPRECEIVER_RESET_HEADERS, reset_headers ) +//CB( API_HTTPRECEIVER_GET_URL, get_url ) +//VCB( API_HTTPRECEIVER_SET_SENDBUFSIZE, set_sendbufsize ) +//VCB( API_HTTPRECEIVER_SET_ACCEPT_ALL_REPLY_CODES, set_accept_all_reply_codes ) +//VCB( API_HTTPRECEIVER_SET_PERSISTENT, set_persistent ) +END_DISPATCH; +#undef CBCLASS diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver.h b/Src/Components/wac_downloadManager/wac_download_http_receiver.h new file mode 100644 index 00000000..bf90ca8c --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_download_http_receiver.h @@ -0,0 +1,48 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_HTTP_RECEIVER_H +#define NULLSOFT_WAC_NETWORK_HTTP_RECEIVER_H + +#include <atomic> + +#include <QtCore> +//#include <QAuthenticator> +//#include <QNetworkAccessManager> +#include <QNetworkRequest> +#include <QNetworkReply> + +#include <QUrl> +#include <QUrlQuery> + +//#include "wac_downloadManager_Headers.h" + +#include "wac_download_http_receiver_api.h" + +namespace wa +{ + namespace Components + { + class WAC_Download_HTTP_Receiver : public QObject, public api_wac_download_manager_http_receiver + { + Q_OBJECT + + public: + WAC_Download_HTTP_Receiver(); + ~WAC_Download_HTTP_Receiver(); + + void open( api_dns *p_dns = API_DNS_AUTODNS, size_t p_recvbufsize = PACKET_SIZE, const char *p_proxy = NULL ); + + std::size_t AddRef(); + std::size_t Release(); + + protected: + RECVS_DISPATCH; + + private: + volatile std::atomic<std::size_t> _reference_count = 1; + + + + }; + } +} + +#endif // !NULLSOFT_WAC_NETWORK_HTTP_RECEIVER_H
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver_api.cpp b/Src/Components/wac_downloadManager/wac_download_http_receiver_api.cpp new file mode 100644 index 00000000..3d3e3c96 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_download_http_receiver_api.cpp @@ -0,0 +1 @@ +#include "wac_download_http_receiver_api.h"
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver_api.h b/Src/Components/wac_downloadManager/wac_download_http_receiver_api.h new file mode 100644 index 00000000..52ced7f7 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_download_http_receiver_api.h @@ -0,0 +1,237 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_API_HTTP_RECEIVER_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_API_HTTP_RECEIVER_H + +#define PACKET_SIZE 16384 + +#include "bfc/dispatch.h" +#include "bfc/platform/types.h" + +#include "../wac_network/wac_network_dns_api.h" + +enum +{ + HTTP_RECEIVER_STATUS_ERROR = -1, + HTTP_RECEIVER_STATUS_CONNECTING = 0, + HTTP_RECEIVER_STATUS_READING_HEADERS = 1, + HTTP_RECEIVER_STATUS_READING_CONTENT = 2, +}; + +enum +{ + HTTP_RECEIVER_RUN_ERROR = -1, + HTTP_RECEIVER_RUN_OK = 0, + HTTP_RECEIVER_RUN_CONNECTION_CLOSED = 1, +}; + + +class NOVTABLE api_wac_download_manager_http_receiver : public Dispatchable +{ +protected: + api_wac_download_manager_http_receiver() {} + ~api_wac_download_manager_http_receiver() {} + +public: + void open( api_dns *dns = API_DNS_AUTODNS, size_t recvbufsize = PACKET_SIZE, const char *proxy = NULL ); + + void addheader( const char *header ); + void AddHeaderValue( const char *header, const char *value ); + void reset_headers(); + + char *getheader( char *headername ); + const char *getallheaders(); // double null terminated, null delimited list + + void connect( const char *url, int ver = 0, const char *requestmethod = "GET" ); + + int run(); // see HTTPRECEIVER_RUN_* enum for return values + int get_status(); // see HTTPRECEIVER_STATUS_* enum for return values + + int bytes_available(); + int get_bytes( void *buf, int len ); + int peek_bytes( void *buf, int len ); + + uint64_t content_length(); + + int getreplycode(); // returns 0 if none yet, otherwise returns http reply code. + const char *GetReply(); + + const char *geterrorstr(); + + //api_connection *GetConnection(); + + void AllowCompression(); + const char *get_url(); // might not be the same as what you passed in if a redirect happened + + void set_sendbufsize( int sendbufsize = PACKET_SIZE ); // call if you're going to POST or do any kind of bidirectional communications + void set_accept_all_reply_codes(); + void set_persistent(); + + DISPATCH_CODES + { + API_HTTPRECEIVER_OPEN = 10, + + API_HTTPRECEIVER_ADDHEADER = 20, + API_HTTPRECEIVER_ADDHEADERVALUE = 30, + + API_HTTPRECEIVER_CONNECT = 40, + + API_HTTPRECEIVER_RUN = 50, + API_HTTPRECEIVER_GETSTATUS = 60, + + API_HTTPRECEIVER_GETBYTESAVAILABLE = 70, + API_HTTPRECEIVER_GETBYTES = 80, + API_HTTPRECEIVER_PEEKBYTES = 90, + + API_HTTPRECEIVER_GETHEADER = 100, + API_HTTPRECEIVER_GETCONTENTLENGTH = 110, + API_HTTPRECEIVER_GETALLHEADERS = 120, + + API_HTTPRECEIVER_GETREPLYCODE = 130, + API_HTTPRECEIVER_GETREPLY = 140, + + API_HTTPRECEIVER_GETERROR = 150, + API_HTTPRECEIVER_GETCONNECTION = 160, + + API_HTTPRECEIVER_ALLOW_COMPRESSION = 170, + + API_HTTPRECEIVER_RESET_HEADERS = 180, + + API_HTTPRECEIVER_GET_URL = 190, + + API_HTTPRECEIVER_SET_SENDBUFSIZE = 200, + API_HTTPRECEIVER_SET_ACCEPT_ALL_REPLY_CODES = 210, + API_HTTPRECEIVER_SET_PERSISTENT = 220, + }; + +}; + +inline void api_wac_download_manager_http_receiver::open( api_dns *dns, size_t recvbufsize, const char *proxy ) +{ + _voidcall( API_HTTPRECEIVER_OPEN, dns, recvbufsize, proxy ); +} + + +inline void api_wac_download_manager_http_receiver::addheader( const char *header ) +{ + _voidcall( API_HTTPRECEIVER_ADDHEADER, header ); +} + +inline void api_wac_download_manager_http_receiver::AddHeaderValue( const char *header, const char *value ) +{ + _voidcall( API_HTTPRECEIVER_ADDHEADERVALUE, header, value ); +} + +inline void api_wac_download_manager_http_receiver::reset_headers() +{ + _voidcall( API_HTTPRECEIVER_RESET_HEADERS ); +} + + +inline char *api_wac_download_manager_http_receiver::getheader( char *headername ) +{ + return _call( API_HTTPRECEIVER_GETHEADER, (char *)NULL, headername ); +} + +inline const char *api_wac_download_manager_http_receiver::getallheaders() +{ + return _call( API_HTTPRECEIVER_GETALLHEADERS, (const char *)NULL ); +} + + +inline void api_wac_download_manager_http_receiver::connect( const char *url, int ver, const char *requestmethod ) +{ + _voidcall( API_HTTPRECEIVER_CONNECT, url, ver, requestmethod ); +} + + +inline int api_wac_download_manager_http_receiver::run() +{ + return _call( API_HTTPRECEIVER_RUN, (int)HTTP_RECEIVER_RUN_ERROR ); +} + +inline int api_wac_download_manager_http_receiver::get_status() +{ + return _call( API_HTTPRECEIVER_GETSTATUS, (int)HTTP_RECEIVER_STATUS_ERROR ); +} + + +inline int api_wac_download_manager_http_receiver::bytes_available() +{ + return _call( API_HTTPRECEIVER_GETBYTESAVAILABLE, (int)0 ); +} + +inline int api_wac_download_manager_http_receiver::get_bytes( void *buf, int len ) +{ + return _call( API_HTTPRECEIVER_GETBYTES, (int)0, buf, len ); +} + +inline int api_wac_download_manager_http_receiver::peek_bytes( void *buf, int len ) +{ + return _call( API_HTTPRECEIVER_PEEKBYTES, (int)0, buf, len ); +} + + +inline uint64_t api_wac_download_manager_http_receiver::content_length() +{ + return _call( API_HTTPRECEIVER_GETCONTENTLENGTH, (uint64_t)0 ); +} + + +inline int api_wac_download_manager_http_receiver::getreplycode() +{ + return _call( API_HTTPRECEIVER_GETREPLYCODE, 0 ); +} + +inline const char *api_wac_download_manager_http_receiver::GetReply() +{ + return _call( API_HTTPRECEIVER_GETREPLY, (const char *)NULL ); +} + + +inline const char *api_wac_download_manager_http_receiver::geterrorstr() +{ + return _call( API_HTTPRECEIVER_GETERROR, (const char *)NULL ); +} + + +//inline api_connection *api_wac_download_manager_http_receiver::GetConnection() +//{ +// return _call( API_HTTPRECEIVER_GETCONNECTION, (api_connection *)NULL ); +//} + + +inline void api_wac_download_manager_http_receiver::AllowCompression() +{ + _voidcall( API_HTTPRECEIVER_ALLOW_COMPRESSION ); +} + +inline const char *api_wac_download_manager_http_receiver::get_url() +{ + return _call( API_HTTPRECEIVER_GET_URL, (const char *)0 ); +} + + +inline void api_wac_download_manager_http_receiver::set_sendbufsize( int sendbufsize ) +{ + _voidcall( API_HTTPRECEIVER_SET_SENDBUFSIZE, sendbufsize ); +} + +inline void api_wac_download_manager_http_receiver::set_accept_all_reply_codes() +{ + _voidcall( API_HTTPRECEIVER_SET_ACCEPT_ALL_REPLY_CODES ); +} + +inline void api_wac_download_manager_http_receiver::set_persistent() +{ + _voidcall( API_HTTPRECEIVER_SET_PERSISTENT ); +} + +//////// {12475CD9-1BA3-4665-B395-F87DBF31E30F} +//////static const GUID httpreceiverGUID = +//////{ 0x12475cd9, 0x1ba3, 0x4665, { 0xb3, 0x95, 0xf8, 0x7d, 0xbf, 0x31, 0xe3, 0xf } }; + +// {1683C6B7-1F6A-4C56-8496-525A3F5929D9} +static const GUID httpreceiverGUID2 = +{ 0x1683c6b7, 0x1f6a, 0x4c56, { 0x84, 0x96, 0x52, 0x5a, 0x3f, 0x59, 0x29, 0xd9 } }; + + +#endif // !NULLSOFT_WAC_DOWNLOAD_MANAGER_API_HTTP_RECEIVER_H diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.cpp b/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.cpp new file mode 100644 index 00000000..ae9e4f29 --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.cpp @@ -0,0 +1,82 @@ +#define GUID_EQUALS_DEFINED + +//#include "util.h" + +#include "api__wac_downloadManager.h" + +#include "wac_download_http_receiver.h" +//#include "wac_download_http_receiver_api.h" +#include "wac_download_http_receiver_factory.h" + + +static const std::string _serviceName = "DownloadManager HTTP Receiver Service"; + + +FOURCC wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetServiceType() +{ + return WaSvc::OBJECT; +} + +const char *wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetServiceName() +{ + return _serviceName.c_str(); +} + +GUID wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetGUID() +{ + return httpreceiverGUID2; +} + +void *wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetInterface( int global_lock ) +{ + //if ( JNL::open_socketlib() ) + // return NULL; + + api_wac_download_manager_http_receiver *ifc = new wa::Components::WAC_Download_HTTP_Receiver(); + + //JNL::close_socketlib(); // new JNL_HTTPGet will call open_socketlib also, so we can release now + + //// if (global_lock) + //// WASABI_API_SVC->service_lock(this, (void *)ifc); + + return ifc; + //return NULL; +} + +int wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::SupportNonLockingInterface() +{ + return 1; +} + +int wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::ReleaseInterface( void *ifc ) +{ + //WASABI_API_SVC->service_unlock(ifc); + api_wac_download_manager_http_receiver *httpget = static_cast<api_wac_download_manager_http_receiver *>( ifc ); + if ( httpget ) + httpget->Release(); + + return 1; +} + +const char *wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::GetTestString() +{ + return NULL; +} + +int wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory::ServiceNotify( int msg, int param1, int param2 ) +{ + return 1; +} + +#define CBCLASS wa::Factory::WAC_DownloadMabager_HTTPReceiver_Factory +START_DISPATCH; +CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType ) +CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName ) +CB( WASERVICEFACTORY_GETGUID, GetGUID ) +CB( WASERVICEFACTORY_GETINTERFACE, GetInterface ) +CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface ) +CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface ) +CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString ) +CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify ) +END_DISPATCH; +#undef CBCLASS
\ No newline at end of file diff --git a/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.h b/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.h new file mode 100644 index 00000000..4e98c41c --- /dev/null +++ b/Src/Components/wac_downloadManager/wac_download_http_receiver_factory.h @@ -0,0 +1,33 @@ +#ifndef NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_HTTP_RECEIVER_H +#define NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_HTTP_RECEIVER_H + +#include <string> + +#include "api/service/waservicefactory.h" +#include "api/service/services.h" + +namespace wa +{ + namespace Factory + { + class WAC_DownloadMabager_HTTPReceiver_Factory : public waServiceFactory + { + public: + FOURCC GetServiceType(); + const char *GetServiceName(); + GUID GetGUID(); + + void *GetInterface( int global_lock ); + int SupportNonLockingInterface(); + int ReleaseInterface( void *ifc ); + + const char *GetTestString(); + int ServiceNotify( int msg, int param1, int param2 ); + + protected: + RECVS_DISPATCH; + }; + } +} + +#endif //!NULLSOFT_WAC_DOWNLOAD_MANAGER_FACTORY_HTTP_RECEIVER_H
\ No newline at end of file |