//-------------------------------------------------------------------------------------------------------------- void DownloadManager::Reset() { // ask the active request to bail if ( m_activeRequest ) { ConDColorMsg( DownloadColor, "Aborting download of %s\n", m_activeRequest->gamePath ); if ( m_activeRequest->nBytesTotal && m_activeRequest->nBytesCurrent ) { // Persist partial data to cache TheDownloadCache->PersistToCache( m_activeRequest ); } m_activeRequest->shouldStop = true; m_completedRequests.AddToTail( m_activeRequest ); m_activeRequest = NULL; //TODO: StopLoadingProgressBar(); } // clear out any queued requests for ( int i=0; i<m_queuedRequests.Count(); ++i ) { ConDColorMsg( DownloadColor, "Discarding queued download of %s\n", m_queuedRequests[i]->gamePath ); delete m_queuedRequests[i]; } m_queuedRequests.RemoveAll(); if ( TheDownloadCache ) { delete TheDownloadCache; TheDownloadCache = NULL; } m_lastPercent = 0; m_totalRequests = 0; }
//-------------------------------------------------------------------------------------------------------------- // Starts a new download if there are queued requests void DownloadManager::StartNewDownload() { if ( m_activeRequest || !m_queuedRequests.Count() ) return; while ( !m_activeRequest && m_queuedRequests.Count() ) { // Remove one request from the queue and make it active m_activeRequest = m_queuedRequests[0]; m_queuedRequests.Remove( 0 ); if ( g_pFileSystem->FileExists( m_activeRequest->gamePath ) ) { ConDColorMsg( DownloadColor, "Skipping existing file %s%s.\n", m_activeRequest->baseURL, m_activeRequest->gamePath ); m_activeRequest->shouldStop = true; m_activeRequest->threadDone = true; m_completedRequests.AddToTail( m_activeRequest ); m_activeRequest = NULL; } } if ( !m_activeRequest ) return; if ( g_pFileSystem->FileExists( m_activeRequest->gamePath ) ) { m_activeRequest->shouldStop = true; m_activeRequest->threadDone = true; m_completedRequests.AddToTail( m_activeRequest ); m_activeRequest = NULL; return; // don't download existing files } if ( m_activeRequest->bAsHTTP ) { // Check cache for partial match TheDownloadCache->GetCachedData( m_activeRequest ); //TODO: ContinueLoadingProgressBar( "Http", m_totalRequests - m_queuedRequests.Count(), 0.0f ); //TODO: SetLoadingProgressBarStatusText( "#GameUI_VerifyingAndDownloading" ); //TODO: SetSecondaryProgressBarText( m_activeRequest->gamePath ); //TODO: SetSecondaryProgressBar( 0.0f ); UpdateProgressBar(); ConDColorMsg( DownloadColor, "Downloading %s%s.\n", m_activeRequest->baseURL, m_activeRequest->gamePath ); m_lastPercent = 0; // Start the thread DWORD threadID; VCRHook_CreateThread(NULL, 0, DownloadThread, m_activeRequest, 0, &threadID ); } else { UpdateProgressBar(); ConDColorMsg( DownloadColor, "Downloading %s.\n", m_activeRequest->gamePath ); m_lastPercent = 0; m_activeRequest->nRequestID = cl.m_NetChannel->RequestFile( m_activeRequest->gamePath ); } }
Tag Request(std::shared_ptr<IRequest> p) { unsigned int num = m_requests.size(); for (unsigned int ui=0; ui<num; ++ui) { if ( m_requests.at(ui) == nullptr ) { m_requests.at(ui) = p; return static_cast<Tag>(ui); } } m_requests.push_back(p); return static_cast<Tag>(num); }
//-------------------------------------------------------------------------------------------------------------- // Check download requests that have been completed to see if their threads have exited void DownloadManager::PruneCompletedRequests() { for ( int i=m_completedRequests.Count()-1; i>=0; --i ) { if ( m_completedRequests[i]->threadDone || !m_completedRequests[i]->bAsHTTP ) { if ( m_completedRequests[i]->cacheData ) { delete[] m_completedRequests[i]->cacheData; } delete m_completedRequests[i]; m_completedRequests.Remove( i ); } } }
//-------------------------------------------------------------------------------------------------------------- void DownloadManager::UpdateProgressBar() { if ( !m_activeRequest ) { return; } wchar_t filenameBuf[MAX_OSPATH]; float progress = 0.0f; if ( m_activeRequest->bAsHTTP ) { int overallPercent = (m_totalRequests - m_queuedRequests.Count() - 1) * 100 / m_totalRequests; int filePercent = 0; if ( m_activeRequest->nBytesTotal > 0 ) { filePercent = ( m_activeRequest->nBytesCurrent * 100 / m_activeRequest->nBytesTotal ); } progress = (overallPercent + filePercent * 1.0f / m_totalRequests) * 0.01f; } else { int received, total; cl.m_NetChannel->GetStreamProgress( FLOW_INCOMING, &received, &total ); progress = (float)(received)/(float)(total); } _snwprintf( filenameBuf, 256, L"Downloading %hs", m_activeRequest->gamePath ); EngineVGui()->UpdateCustomProgressBar( progress, filenameBuf ); }
//--------------------------------------------------------------------------------------// void CMarketDataProvider::Subscribe(RequestVector& request) { HRESULT hr = S_OK; try { IBatchPriceProviderPtr spBatchPriceProvider = GetBatchPriceProvider(); if (static_cast<bool>(spBatchPriceProvider)) { CComRecPtr<QuoteUpdateParams, &LIBID_PRICEPROVIDERSLib> RequestInfo; RequestInfo.Init(); long outSize = static_cast<long>(request.size()); SAFEARRAYBOUND sab = { outSize, 0 }; LPSAFEARRAY psa = ::SafeArrayCreateEx( VT_RECORD, 1, &sab, (PVOID) RequestInfo.GetRecordInfo() ); if(psa) { QuoteUpdateParams* pvOutData = NULL; if(SUCCEEDED(hr = ::SafeArrayAccessData(psa, (void**)&pvOutData))) { memset(pvOutData, 0, outSize * sizeof(QuoteUpdateParams)); int j = 0; for (RequestVector::iterator it = request.begin(); it != request.end(); ++it) { (*it).CopyTo(pvOutData[j]); j++; } ::SafeArrayUnaccessData(psa); } } _com_util::CheckError(spBatchPriceProvider->raw_SubscribeMultipleQuotes(&psa)); ::SafeArrayDestroy(psa); m_bInSubscribeMode = true; } } catch (_com_error& err) { TRACE_COM_ERROR(err); } catch (...) { TRACE_UNKNOWN_ERROR(); }; return; };
bool DownloadManager::FileReceived( const char *filename, unsigned int requestID ) { if ( !m_activeRequest ) return false; if ( m_activeRequest->nRequestID != requestID ) return false; if ( m_activeRequest->bAsHTTP ) return false; ConDColorMsg( DownloadCompleteColor, "Download finished!\n" ); UpdateProgressBar(); m_completedRequests.AddToTail( m_activeRequest ); m_activeRequest = NULL; return true; }
bool DownloadManager::FileDenied( const char *filename, unsigned int requestID ) { if ( !m_activeRequest ) return false; if ( m_activeRequest->nRequestID != requestID ) return false; if ( m_activeRequest->bAsHTTP ) return false; ConDColorMsg( DownloadErrorColor, "Error downloading %s\n", m_activeRequest->gamePath ); UpdateProgressBar(); // try to download the next file m_completedRequests.AddToTail( m_activeRequest ); m_activeRequest = NULL; return true; }
Manager(){ m_requests.reserve(100); }
//-------------------------------------------------------------------------------------------------------------- // Checks download status, and updates progress bar void DownloadManager::CheckActiveDownload() { if ( !m_activeRequest ) return; if ( !m_activeRequest->bAsHTTP ) { UpdateProgressBar(); return; } // check active request for completion / error / progress update switch ( m_activeRequest->status ) { case HTTP_DONE: ConDColorMsg( DownloadCompleteColor, "Download finished!\n" ); UpdateProgressBar(); if ( m_activeRequest->nBytesTotal ) { // Persist complete data to disk, and remove cache entry //TODO: SetSecondaryProgressBarText( m_activeRequest->gamePath ); TheDownloadCache->PersistToDisk( m_activeRequest ); m_activeRequest->shouldStop = true; m_completedRequests.AddToTail( m_activeRequest ); m_activeRequest = NULL; if ( !m_queuedRequests.Count() ) { //TODO: StopLoadingProgressBar(); //TODO: Cbuf_AddText("retry\n"); } } break; case HTTP_ERROR: ConDColorMsg( DownloadErrorColor, "Error downloading %s%s\n", m_activeRequest->baseURL, m_activeRequest->gamePath ); UpdateProgressBar(); // try to download the next file m_activeRequest->shouldStop = true; m_completedRequests.AddToTail( m_activeRequest ); m_activeRequest = NULL; if ( !m_queuedRequests.Count() ) { //TODO: StopLoadingProgressBar(); //TODO: Cbuf_AddText("retry\n"); } break; case HTTP_FETCH: UpdateProgressBar(); // Update progress bar //TODO: SetSecondaryProgressBarText( m_activeRequest->gamePath ); if ( m_activeRequest->nBytesTotal ) { int percent = ( m_activeRequest->nBytesCurrent * 100 / m_activeRequest->nBytesTotal ); if ( percent != m_lastPercent ) { /* ConDColorMsg( DownloadColor, "Downloading %s%s: %3.3d%% - %d of %d bytes\n", m_activeRequest->baseURL, m_activeRequest->gamePath, percent, m_activeRequest->nBytesCurrent, m_activeRequest->nBytesTotal ); */ m_lastPercent = percent; //TODO: SetSecondaryProgressBar( m_lastPercent * 0.01f ); } } break; } }
//-------------------------------------------------------------------------------------------------------------- void DownloadManager::Queue( const char *baseURL, const char *gamePath ) { bool bAsHTTP = false; if ( !gamePath ) { return; } #ifndef _DEBUG if ( sv.IsActive() ) { return; // don't try to download things for the local server (in case a map is missing sounds etc that // aren't needed to play. } #endif // only http downloads if ( baseURL && (!Q_strnicmp( baseURL, "http://", 7 ) || !Q_strnicmp( baseURL, "https://", 8 )) ) { bAsHTTP = true; } if ( g_pFileSystem->FileExists( gamePath ) ) { return; // don't download existing files } if ( Q_strstr( gamePath, "//" ) ) { return; } if ( Q_strstr( gamePath, "\\\\" ) ) { return; } if ( Q_strstr( gamePath, ":" ) ) { return; } if ( Q_strstr( gamePath, "lua/" ) ) return; // don't download into lua/ folder if ( Q_strstr( gamePath, "gamemodes/" ) ) return; // don't download into gamemodes/ folder if ( Q_strstr( gamePath, "addons/" ) ) return; // don't download into addons/ folder // Disallow .. in paths, but allow multiple periods otherwise. This way we can download blah.dx80.vtx etc. const char *backup = strstr( gamePath, ".." ); const char *extension = strrchr( gamePath, '.' ); if ( backup || !extension ) return; int baseLen = strlen( extension ); if ( baseLen > 4 || baseLen < 3 ) return; if ( !Q_strcasecmp( extension, ".cfg" ) ) return; if ( !Q_strcasecmp( extension, ".lst" ) ) return; if ( !Q_strcasecmp( extension, ".exe" ) ) return; if ( !Q_strcasecmp( extension, ".vbs" ) ) return; if ( !Q_strcasecmp( extension, ".com" ) ) return; if ( !Q_strcasecmp( extension, ".bat" ) ) return; if ( !Q_strcasecmp( extension, ".dll" ) ) return; if ( !Q_strcasecmp( extension, ".ini" ) ) return; if ( !Q_strcasecmp( extension, ".log" ) ) return; if ( !Q_strcasecmp( extension, ".lua" ) ) return; if ( bAsHTTP && !g_pFileSystem->FileExists( va( "%s.bz2", gamePath ) ) ) { // Queue up an HTTP download of the bzipped asset, in case it exists. // When a bzipped download finishes, we'll uncompress the file to it's // original destination, and the queued download of the uncompressed // file will abort. ++m_totalRequests; if ( !TheDownloadCache ) { TheDownloadCache = new DownloadCache; TheDownloadCache->Init(); } RequestContext *rc = new RequestContext; m_queuedRequests.AddToTail( rc ); memset( rc, 0, sizeof(RequestContext) ); rc->status = HTTP_CONNECTING; Q_strncpy( rc->basePath, com_gamedir, BufferSize ); Q_strncpy( rc->gamePath, gamePath, BufferSize ); Q_strncat( rc->gamePath, ".bz2", BufferSize, COPY_ALL_CHARACTERS ); Q_FixSlashes( rc->gamePath, '/' ); // only matters for debug prints, which are full URLS, so we want forward slashes Q_strncpy( rc->serverURL, cl.m_NetChannel->GetRemoteAddress().ToString(), BufferSize ); rc->bIsBZ2 = true; rc->bAsHTTP = true; Q_strncpy( rc->baseURL, baseURL, BufferSize ); Q_strncat( rc->baseURL, "/", BufferSize, COPY_ALL_CHARACTERS ); //ConDColorMsg( DownloadColor, "Queueing %s%s.\n", rc->baseURL, gamePath ); } ++m_totalRequests; if ( !TheDownloadCache ) { TheDownloadCache = new DownloadCache; TheDownloadCache->Init(); } RequestContext *rc = new RequestContext; m_queuedRequests.AddToTail( rc ); memset( rc, 0, sizeof(RequestContext) ); rc->status = HTTP_CONNECTING; Q_strncpy( rc->basePath, com_gamedir, BufferSize ); Q_strncpy( rc->gamePath, gamePath, BufferSize ); Q_FixSlashes( rc->gamePath, '/' ); // only matters for debug prints, which are full URLS, so we want forward slashes Q_strncpy( rc->serverURL, cl.m_NetChannel->GetRemoteAddress().ToString(), BufferSize ); if ( bAsHTTP ) { rc->bAsHTTP = true; Q_strncpy( rc->baseURL, baseURL, BufferSize ); Q_strncat( rc->baseURL, "/", BufferSize, COPY_ALL_CHARACTERS ); } else { rc->bAsHTTP = false; } //ConDColorMsg( DownloadColor, "Queueing %s%s.\n", rc->baseURL, gamePath ); }