Added version detection before resuming download

Tries to detect if remote file is different from local file before resuming
Remote XML data is saved when download is started
This commit is contained in:
Sude 2013-04-08 13:43:11 +03:00
parent 9d59b8f5cf
commit d4db79e783
2 changed files with 116 additions and 23 deletions

View File

@ -54,9 +54,9 @@ class Downloader
ProgressBar* progressbar;
protected:
private:
CURLcode downloadFile(std::string url, std::string filepath);
int repairFile(std::string url, std::string filepath, std::string xml_data = std::string(), std::string xml_dir = std::string());
int downloadCovers(std::string gamename, std::string directory, std::string cover_xml_data);
CURLcode downloadFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string());
int repairFile(const std::string& url, const std::string& filepath, const std::string& xml_data = std::string());
int downloadCovers(const std::string& gamename, const std::string& directory, const std::string& cover_xml_data);
int login();
int getGameDetails();
void getGameList();

View File

@ -353,7 +353,7 @@ void Downloader::repair()
continue;
}
std::cout << "Repairing file " << filepath << std::endl;
this->repairFile(url, filepath, XML, config.sXMLDirectory);
this->repairFile(url, filepath, XML);
std::cout << std::endl;
}
}
@ -374,7 +374,7 @@ void Downloader::repair()
continue;
}
std::cout << "Repairing file " << filepath << std::endl;
this->repairFile(url, filepath, std::string(), config.sXMLDirectory);
this->repairFile(url, filepath);
std::cout << std::endl;
}
}
@ -435,10 +435,13 @@ void Downloader::download()
// Download
if (!url.empty())
{
std::string XML;
if (!config.bNoRemoteXML)
XML = gogAPI->getXML(games[i].gamename, games[i].installers[j].id);
if (!games[i].installers[j].name.empty())
std::cout << "Dowloading: " << games[i].installers[j].name << std::endl;
std::cout << filepath << std::endl;
this->downloadFile(url, filepath);
this->downloadFile(url, filepath, XML);
std::cout << std::endl;
}
}
@ -479,7 +482,7 @@ void Downloader::download()
}
// Download a file, resume if possible
CURLcode Downloader::downloadFile(std::string url, std::string filepath)
CURLcode Downloader::downloadFile(const std::string& url, const std::string& filepath, const std::string& xml_data)
{
CURLcode res = CURLE_RECV_ERROR; // assume network error
bool bResume = false;
@ -489,6 +492,39 @@ CURLcode Downloader::downloadFile(std::string url, std::string filepath)
// Get directory from filepath
boost::filesystem::path pathname = filepath;
std::string directory = pathname.parent_path().string();
std::string filenameXML = pathname.filename().string() + ".xml";
// Using local XML data for version check before resuming
boost::filesystem::path local_xml_file;
if (config.sXMLDirectory.empty())
local_xml_file = config.sHome + "/.gogdownloader/xml/" + filenameXML;
else
local_xml_file = config.sXMLDirectory + "/" + filenameXML;
bool bSameVersion = true; // assume same version
bool bLocalXMLExists = boost::filesystem::exists(local_xml_file);
if (!xml_data.empty())
{
// Do version check if local XML file exists
if (bLocalXMLExists)
{
TiXmlDocument remote_xml, local_xml;
remote_xml.Parse(xml_data.c_str());
local_xml.LoadFile(local_xml_file.string());
TiXmlNode *fileNodeRemote = remote_xml.FirstChild("file");
TiXmlNode *fileNodeLocal = local_xml.FirstChild("file");
if (fileNodeRemote && fileNodeLocal)
{
TiXmlElement *fileElemRemote = fileNodeRemote->ToElement();
TiXmlElement *fileElemLocal = fileNodeLocal->ToElement();
std::string remoteHash = fileElemRemote->Attribute("md5");
std::string localHash = fileElemLocal->Attribute("md5");
if (remoteHash != localHash)
bSameVersion = false;
}
}
}
// Check that directory exists and create subdirectories
boost::filesystem::path path = directory;
@ -511,6 +547,8 @@ CURLcode Downloader::downloadFile(std::string url, std::string filepath)
// Check if file exists
if ((outfile=fopen(filepath.c_str(), "r"))!=NULL)
{
if (bSameVersion)
{
// File exists, resume
if ((outfile = freopen(filepath.c_str(), "r+", outfile))!=NULL )
@ -529,10 +567,33 @@ CURLcode Downloader::downloadFile(std::string url, std::string filepath)
}
else
{
// File doesn't exist, create new file
fclose(outfile);
std::cout << "Remote file is different, renaming local file" << std::endl;
boost::filesystem::path new_name = filepath + ".old";
if (boost::filesystem::exists(new_name))
{
std::cout << "Old renamed file found, deleting old file" << std::endl;
if (!boost::filesystem::remove(new_name))
{
std::cout << "Failed to delete " << new_name.string() << std::endl;
std::cout << "Skipping file" << std::endl;
return res;
}
}
boost::system::error_code ec;
boost::filesystem::rename(pathname, new_name, ec);
if (ec)
{
std::cout << "Failed to rename " << filepath << " to " << new_name.string() << std::endl;
std::cout << "Skipping file" << std::endl;
return res;
}
else
{
// Create new file
if ((outfile=fopen(filepath.c_str(), "w"))!=NULL)
{
curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM, offset); // start downloading from the beginning of file
curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM, 0); // start downloading from the beginning of file
this->resume_position = 0;
}
else
@ -541,6 +602,40 @@ CURLcode Downloader::downloadFile(std::string url, std::string filepath)
return res;
}
}
}
}
else
{
// File doesn't exist, create new file
if ((outfile=fopen(filepath.c_str(), "w"))!=NULL)
{
curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM, 0); // start downloading from the beginning of file
this->resume_position = 0;
}
else
{
std::cout << "Failed to create " << filepath << std::endl;
return res;
}
}
// Save remote XML
if (!xml_data.empty())
{
if ((bLocalXMLExists && (!bSameVersion || config.bRepair)) || !bLocalXMLExists)
{
std::ofstream ofs(local_xml_file.string().c_str());
if (ofs)
{
ofs << xml_data;
ofs.close();
}
else
{
std::cout << "Can't create " << local_xml_file.string() << std::endl;
}
}
}
curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str());
curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, outfile);
@ -561,13 +656,11 @@ CURLcode Downloader::downloadFile(std::string url, std::string filepath)
}
// Repair file
int Downloader::repairFile(std::string url, std::string filepath, std::string xml_data, std::string xml_dir)
int Downloader::repairFile(const std::string& url, const std::string& filepath, const std::string& xml_data)
{
int res = 0;
FILE *outfile;
size_t offset=0;
if (xml_dir.empty())
xml_dir = config.sHome + "/.gogdownloader/xml";
size_t from_offset, to_offset;
@ -592,7 +685,7 @@ int Downloader::repairFile(std::string url, std::string filepath, std::string xm
}
else
{
std::string xml_file = xml_dir + "/" + filename + ".xml";
std::string xml_file = config.sXMLDirectory + "/" + filename + ".xml";
std::cout << "XML: Using local file" << std::endl;
xml.LoadFile(xml_file);
}
@ -669,7 +762,7 @@ int Downloader::repairFile(std::string url, std::string filepath, std::string xm
}
else
{
CURLcode result = this->downloadFile(url, filepath);
CURLcode result = this->downloadFile(url, filepath, xml_data);
std::cout << std::endl;
if (result == CURLE_OK)
res = 1;
@ -736,7 +829,7 @@ int Downloader::repairFile(std::string url, std::string filepath, std::string xm
}
// Download cover images
int Downloader::downloadCovers(std::string gamename, std::string directory, std::string cover_xml_data)
int Downloader::downloadCovers(const std::string& gamename, const std::string& directory, const std::string& cover_xml_data)
{
int res = 0;
TiXmlDocument xml;