update FileDownload

This commit is contained in:
AJ Kelly
2010-12-15 18:35:05 -06:00
parent a31bc6c27d
commit d80e4630a7
2 changed files with 132 additions and 72 deletions
+108 -55
View File
@@ -6,8 +6,10 @@
#include "RageFileManager.h" #include "RageFileManager.h"
#include "SpecialFiles.h" #include "SpecialFiles.h"
#include "RageLog.h" #include "RageLog.h"
#include "Preference.h"
#include "Foreach.h"
FileDownload::FileDownload() FileTransfer::FileTransfer()
{ {
m_iPackagesPos = 0; m_iPackagesPos = 0;
m_iLinksPos = 0; m_iLinksPos = 0;
@@ -23,29 +25,26 @@ FileDownload::FileDownload()
// Workaround: For some reason, the first download sometimes corrupts; // Workaround: For some reason, the first download sometimes corrupts;
// by opening and closing the RageFile, this problem does not occur. // by opening and closing the RageFile, this problem does not occur.
// Go figure? // Go figure?
// XXX: This is a really dirty work around! Why does RageFile do this? // XXX: This is a really dirty work around! Why does RageFile do this?
// It's always some strange number of bytes at the end of the file when it corrupts.
// It's always some strange number of bytes at the end of the m_fOutputFile.Open("Packages/dummy.txt", RageFile::WRITE);
// file when it corrupts.
m_fOutputFile.Open( "Packages/dummy.txt", RageFile::WRITE );
m_fOutputFile.Close(); m_fOutputFile.Close();
} }
FileDownload::~FileDownload() FileTransfer::~FileTransfer()
{ {
m_fOutputFile.Close(); m_fOutputFile.Close();
} }
RString FileDownload::Update( float fDeltaTime ) RString FileTransfer::Update( float fDeltaTime )
{ {
HTTPUpdate(); HTTPUpdate();
m_fLastUpdate += fDeltaTime; m_fLastUpdate += fDeltaTime;
if ( m_fLastUpdate >= 1.0 ) if (m_fLastUpdate >= 1.0)
{ {
if ( m_bIsDownloading && m_bGotHeader ) if (m_bIsDownloading && m_bGotHeader)
m_sStatus = ssprintf( "DL @ %d KB/s", int((m_iDownloaded-m_bytesLastUpdate)/1024) ); m_sStatus = ssprintf("DL @ %d KB/s", int((m_iDownloaded-m_bytesLastUpdate)/1024));
m_bytesLastUpdate = m_iDownloaded; m_bytesLastUpdate = m_iDownloaded;
UpdateProgress(); UpdateProgress();
@@ -55,7 +54,7 @@ RString FileDownload::Update( float fDeltaTime )
return m_sStatus; return m_sStatus;
} }
void FileDownload::UpdateProgress() void FileTransfer::UpdateProgress()
{ {
float DownloadedRatio; float DownloadedRatio;
@@ -65,7 +64,7 @@ void FileDownload::UpdateProgress()
DownloadedRatio = float(m_iDownloaded) / float(m_iTotalBytes); DownloadedRatio = float(m_iDownloaded) / float(m_iTotalBytes);
} }
void FileDownload::CancelDownload( ) void FileTransfer::Cancel()
{ {
m_wSocket.close(); m_wSocket.close();
m_bIsDownloading = false; m_bIsDownloading = false;
@@ -74,10 +73,22 @@ void FileDownload::CancelDownload( )
m_fOutputFile.Close(); m_fOutputFile.Close();
m_sStatus = "Failed."; m_sStatus = "Failed.";
m_sBUFFER = ""; m_sBUFFER = "";
FILEMAN->Remove( "Packages/" + m_sEndName ); FILEMAN->Remove("Packages/" + m_sEndName);
} }
void FileDownload::StartDownload( const RString &sURL, const RString &sDestFile ) void FileTransfer::StartDownload( const RString &sURL, const RString &sDestFile )
{
StartTransfer( download, sURL, "", sDestFile );
}
void FileTransfer::StartUpload( const RString &sURL, const RString &sSrcFile, const RString &sDestFile )
{
StartTransfer( upload, sURL, sSrcFile, sDestFile );
}
extern Preference<RString> g_sCookie;
void FileTransfer::StartTransfer( TransferType type, const RString &sURL, const RString &sSrcFile, const RString &sDestFile )
{ {
RString Proto; RString Proto;
RString Server; RString Server;
@@ -87,16 +98,12 @@ void FileDownload::StartDownload( const RString &sURL, const RString &sDestFile
if( !ParseHTTPAddress( sURL, Proto, Server, Port, sAddress ) ) if( !ParseHTTPAddress( sURL, Proto, Server, Port, sAddress ) )
{ {
m_sStatus = "Invalid URL."; m_sStatus = "Invalid URL.";
m_bFinished = true;
UpdateProgress(); UpdateProgress();
return; return;
} }
//Determine if this is a website, or a package? m_bSavingFile = sDestFile != "";
//Criteria: does it end with *zip?
if( sAddress.Right(3).CompareNoCase("zip") == 0 )
m_bIsPackage=true;
else
m_bIsPackage = false;
m_sBaseAddress = "http://" + Server; m_sBaseAddress = "http://" + Server;
if( Port != 80 ) if( Port != 80 )
@@ -113,24 +120,15 @@ void FileDownload::StartDownload( const RString &sURL, const RString &sDestFile
m_sEndName = ""; m_sEndName = "";
} }
//Open the file... // Open the file...
//First find out if a file by this name already exists // First find out if a file by this name already exists if so, then we gotta
//if so, then we gotta ditch out. // ditch out.
//XXX: This should be fixed by a prompt or something? // XXX: This should be fixed by a prompt or something?
//if we are not talking about a file, let's not worry // if we are not talking about a file, let's not worry
if( m_sEndName != "" && m_bIsPackage ) if( m_sEndName != "" && m_bSavingFile )
{ {
vector<RString> AddTo;
GetDirListing( "Packages/"+m_sEndName, AddTo, false, false );
if ( AddTo.size() > 0 )
{
m_sStatus = "File Already Exists";
UpdateProgress();
return;
}
if( !m_fOutputFile.Open( sDestFile, RageFile::WRITE | RageFile::STREAMED ) ) if( !m_fOutputFile.Open( sDestFile, RageFile::WRITE | RageFile::STREAMED ) )
{ {
m_sStatus = m_fOutputFile.GetError(); m_sStatus = m_fOutputFile.GetError();
@@ -138,7 +136,7 @@ void FileDownload::StartDownload( const RString &sURL, const RString &sDestFile
return; return;
} }
} }
//Continue... // Continue...
sAddress = URLEncode( sAddress ); sAddress = URLEncode( sAddress );
@@ -157,15 +155,64 @@ void FileDownload::StartDownload( const RString &sURL, const RString &sDestFile
return; return;
} }
//Produce HTTP header // Produce HTTP header
RString sAction;
switch( type )
{
case upload: sAction = "POST"; break;
case download: sAction = "GET"; break;
}
RString Header=""; vector<RString> vsHeaders;
vsHeaders.push_back( sAction+" "+sAddress+" HTTP/1.0" );
vsHeaders.push_back( "Host: " + Server );
vsHeaders.push_back( "Cookie: " + g_sCookie.Get() );
vsHeaders.push_back( "Connection: closed" );
string sBoundary = "--ZzAaB03x";
vsHeaders.push_back( "Content-Type: multipart/form-data; boundary=" + sBoundary );
RString sRequestPayload;
if( type == upload )
{
RageFile f;
if( !f.Open( sSrcFile ) )
FAIL_M( f.GetError() );
sRequestPayload.reserve( f.GetFileSize() );
int iBytesRead = f.Read( sRequestPayload );
if( iBytesRead == -1 )
FAIL_M( f.GetError() );
Header = "GET "+sAddress+" HTTP/1.0\r\n"; sRequestPayload = "--" + sBoundary + "\r\n" +
Header+= "Host: " + Server + "\r\n"; "Content-Disposition: form-data; name=\"name\"\r\n" +
Header+= "Connection: closed\r\n\r\n"; "\r\n" +
"Chris\r\n" +
"--" + sBoundary + "\r\n" +
"Content-Disposition: form-data; name=\"userfile\"; filename=\"" + Basename(sSrcFile) + "\"\r\n" +
"Content-Type: application/zip\r\n" +
"\r\n" +
sRequestPayload + "\r\n" +
"--" + sBoundary + "--";
}
/*
if( sRequestPayload.size() > 0 )
{
sHeader += "Content-Type: application/octet-stream\r\n";
sHeader += "Content-Length: multipart/form-data; boundary=" + sBoundary + "\r\n";
//sHeader += "Content-Length: " + ssprintf("%d",sRequestPayload.size()) + "\r\n";
}
*/
vsHeaders.push_back( "Content-Length: " + ssprintf("%d",sRequestPayload.size()) );
RString sHeader;
FOREACH_CONST( RString, vsHeaders, h )
sHeader += *h + "\r\n";
sHeader += "\r\n";
m_wSocket.SendData( sHeader.c_str(), sHeader.length() );
m_wSocket.SendData( "\r\n" );
m_wSocket.SendData( sRequestPayload.GetBuffer(), sRequestPayload.size() );
m_wSocket.SendData( Header.c_str(), Header.length() );
m_sStatus = "Header Sent."; m_sStatus = "Header Sent.";
m_wSocket.blocking = false; m_wSocket.blocking = false;
m_bIsDownloading = true; m_bIsDownloading = true;
@@ -187,14 +234,13 @@ static size_t FindEndOfHeaders( const RString &buf )
return string::npos; return string::npos;
} }
void FileDownload::HTTPUpdate() void FileTransfer::HTTPUpdate()
{ {
if( !m_bIsDownloading ) if( !m_bIsDownloading )
return; return;
int BytesGot=0; int BytesGot=0;
//Keep this as a code block // Keep this as a code block, as there may be need to "if" it out some time.
//as there may be need to "if" it out some time.
/* If you need a conditional for a large block of code, stick it in /* If you need a conditional for a large block of code, stick it in
* a function and return. */ * a function and return. */
while(1) while(1)
@@ -211,7 +257,7 @@ void FileDownload::HTTPUpdate()
if( !m_bGotHeader ) if( !m_bGotHeader )
{ {
m_sStatus = "Waiting for header."; m_sStatus = "Waiting for header.";
//We don't know if we are using unix-style or dos-style // We don't know if we are using unix-style or dos-style
size_t iHeaderEnd = FindEndOfHeaders( m_sBUFFER ); size_t iHeaderEnd = FindEndOfHeaders( m_sBUFFER );
if( iHeaderEnd == m_sBUFFER.npos ) if( iHeaderEnd == m_sBUFFER.npos )
return; return;
@@ -235,13 +281,13 @@ void FileDownload::HTTPUpdate()
if( i != string::npos ) if( i != string::npos )
m_iTotalBytes = atoi(m_sBUFFER.substr(i+16,j-i).c_str()); m_iTotalBytes = atoi(m_sBUFFER.substr(i+16,j-i).c_str());
else else
m_iTotalBytes = -1; //We don't know, so go until disconnect m_iTotalBytes = -1; // We don't know, so go until disconnect
m_bGotHeader = true; m_bGotHeader = true;
m_sBUFFER.erase( 0, iHeaderEnd ); m_sBUFFER.erase( 0, iHeaderEnd );
} }
if( m_bIsPackage ) if( m_bSavingFile )
{ {
m_iDownloaded += m_sBUFFER.length(); m_iDownloaded += m_sBUFFER.length();
m_fOutputFile.Write( m_sBUFFER ); m_fOutputFile.Write( m_sBUFFER );
@@ -260,8 +306,8 @@ void FileDownload::HTTPUpdate()
//We have the full doc. (And we knew how big it was) //We have the full doc. (And we knew how big it was)
( m_iTotalBytes == -1 && ( m_iTotalBytes == -1 &&
( m_wSocket.state == EzSockets::skERROR || m_wSocket.state == EzSockets::skDISCONNECTED ) ) ) ( m_wSocket.state == EzSockets::skERROR || m_wSocket.state == EzSockets::skDISCONNECTED ) ) )
//We didn't know how big it was, and were disconnected // We didn't know how big it was, and were disconnected
//So that means we have it all. // So that means we have it all.
{ {
m_wSocket.close(); m_wSocket.close();
m_bIsDownloading = false; m_bIsDownloading = false;
@@ -275,7 +321,7 @@ void FileDownload::HTTPUpdate()
} }
else else
{ {
if( m_bIsPackage && m_iResponseCode < 300 ) if( m_bSavingFile && m_iResponseCode < 300 )
{ {
RString sZipFile = m_fOutputFile.GetRealPath(); RString sZipFile = m_fOutputFile.GetRealPath();
m_fOutputFile.Close(); m_fOutputFile.Close();
@@ -286,7 +332,7 @@ void FileDownload::HTTPUpdate()
} }
} }
bool FileDownload::ParseHTTPAddress( const RString &URL, RString &sProto, RString &sServer, int &iPort, RString &sAddress ) bool FileTransfer::ParseHTTPAddress( const RString &URL, RString &sProto, RString &sServer, int &iPort, RString &sAddress )
{ {
// [PROTO://]SERVER[:PORT][/URL] // [PROTO://]SERVER[:PORT][/URL]
@@ -316,9 +362,16 @@ bool FileDownload::ParseHTTPAddress( const RString &URL, RString &sProto, RStrin
return true; return true;
} }
bool FileDownload::IsFinished() void FileTransfer::Finish()
{ {
return m_bFinished; while( true )
{
float fSleepSeconds = 0.1f;
this->Update( fSleepSeconds );
usleep( int( fSleepSeconds * 1000000.0 ) );
if( this->IsFinished() )
break;
}
} }
#endif #endif
+21 -14
View File
@@ -1,33 +1,40 @@
/* FileDownload - Downloads a file from the Internet. */ #ifndef FileTransfer_H
#ifndef ScreenPackages_H #define FileTransfer_H
#define ScreenPackages_H
#if !defined(WITHOUT_NETWORKING) #if !defined(WITHOUT_NETWORKING)
#include "EzSockets.h" #include "ezsockets.h"
#include "RageFile.h" #include "RageFile.h"
class FileDownload class FileTransfer
{ {
public: public:
FileDownload(); FileTransfer();
~FileDownload(); ~FileTransfer();
void StartDownload( const RString &sURL, const RString &sDestFile ); void StartDownload(const RString &sURL, const RString &sDestFile);
void CancelDownload( ); void StartUpload(const RString &sURL, const RString &sSrcFile, const RString &sDestFile);
void Cancel();
RString Update(float fDeltaTime); RString Update(float fDeltaTime);
bool IsFinished(); bool IsFinished() const { return m_bFinished; }
void Finish();
int GetResponseCode() const { return m_iResponseCode; }
RString GetResponse() const { return m_sBUFFER; }
RString GetStatus() const { return m_sStatus; }
private: private:
enum TransferType { download, upload };
void StartTransfer(TransferType type, const RString &sURL, const RString &sSrcFile, const RString &sDestFile);
int m_iPackagesPos; int m_iPackagesPos;
int m_iLinksPos; int m_iLinksPos;
int m_iDLorLST; int m_iDLorLST;
// HTTP portion // HTTP portion
void HTTPUpdate( ); void HTTPUpdate();
// True if proper string, false if improper // True if proper string, false if improper
bool ParseHTTPAddress( const RString & URL, RString & Proto, RString & Server, int & Port, RString & Addy ); bool ParseHTTPAddress(const RString & URL, RString & Proto, RString & Server, int & Port, RString & Addy);
void UpdateProgress(); void UpdateProgress();
@@ -43,10 +50,10 @@ private:
RageFile m_fOutputFile; RageFile m_fOutputFile;
RString m_sEndName; RString m_sEndName;
bool m_bIsPackage; bool m_bSavingFile;
RString m_sBaseAddress; RString m_sBaseAddress;
// HTTP Header information response // HTTP Header information responce
long m_iTotalBytes; long m_iTotalBytes;
long m_iDownloaded; long m_iDownloaded;