You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
4.6 KiB

// Copyright (C) 2024 Simon Quigley <tsimonq2@ubuntu.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "utilities.h"
#include <fstream>
#include <iostream>
#include <filesystem>
#include <regex>
#include <zlib.h>
#include <curl/curl.h>
#include <sys/stat.h>
namespace fs = std::filesystem;
// Function to read the entire content of a file into a string
std::string readFile(const fs::path& filePath) {
std::ifstream inFile(filePath, std::ios::binary);
if (inFile) {
return std::string((std::istreambuf_iterator<char>(inFile)),
std::istreambuf_iterator<char>());
}
return "";
}
// Function to write a string into a file
void writeFile(const fs::path& filePath, const std::string& content) {
std::ofstream outFile(filePath, std::ios::binary);
if (outFile) {
outFile << content;
}
}
// Function to perform in-place regex replace on a file
void regexReplaceInFile(const fs::path& filePath, const std::string& pattern, const std::string& replace) {
std::string content = readFile(filePath);
content = std::regex_replace(content, std::regex(pattern), replace);
writeFile(filePath, content);
}
// Function to decompress gzipped files
std::string decompressGzip(const fs::path& filePath) {
gzFile infile = gzopen(filePath.c_str(), "rb");
if (!infile) return "";
std::string decompressedData;
char buffer[8192];
int numRead = 0;
while ((numRead = gzread(infile, buffer, sizeof(buffer))) > 0) {
decompressedData.append(buffer, numRead);
}
gzclose(infile);
return decompressedData;
}
// Helper function for libcurl write callback
size_t write_data(void* ptr, size_t size, size_t nmemb, void* stream) {
FILE* out = static_cast<FILE*>(stream);
return fwrite(ptr, size, nmemb, out);
}
// Function to download a file with timestamping using libcurl
void downloadFileWithTimestamping(const std::string& url, const fs::path& outputPath,
const fs::path& logFilePath, std::mutex& logMutex) {
CURL* curl;
CURLcode res;
FILE* fp;
curl = curl_easy_init();
if (curl) {
fs::path tempFilePath = outputPath.string() + ".tmp";
fp = fopen(tempFilePath.c_str(), "wb");
if (!fp) {
std::cerr << "Failed to open file: " << tempFilePath << std::endl;
curl_easy_cleanup(curl);
return;
}
// Set curl options for downloading the file
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
// Timestamping: set If-Modified-Since header
struct stat file_info;
if (stat(outputPath.c_str(), &file_info) == 0) {
// Set the time condition to If-Modified-Since
curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
curl_easy_setopt(curl, CURLOPT_TIMEVALUE, file_info.st_mtime);
}
// Perform the file download
res = curl_easy_perform(curl);
// Get the HTTP response code
long response_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
fclose(fp);
curl_easy_cleanup(curl);
// Log the result and handle the downloaded file
{
std::lock_guard<std::mutex> lock(logMutex);
std::ofstream logFile(logFilePath, std::ios::app);
if (res == CURLE_OK && (response_code == 200 || response_code == 201)) {
fs::rename(tempFilePath, outputPath);
logFile << "Downloaded: " << url << std::endl;
} else if (response_code == 304) {
fs::remove(tempFilePath);
logFile << "Not Modified: " << url << std::endl;
} else {
fs::remove(tempFilePath);
logFile << "Failed to download: " << url << std::endl;
}
}
} else {
std::cerr << "Failed to initialize CURL." << std::endl;
}
}