//-------------------------------------------------------------------------------------------------------------- // 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 ); } }
//-------------------------------------------------------------------------------------------------------------- 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; }
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; }
//-------------------------------------------------------------------------------------------------------------- // 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 ); }