1+ #include " download_service.h"
12#include < curl/curl.h>
23#include < httplib.h>
34#include < stdio.h>
45#include < trantor/utils/Logger.h>
56#include < filesystem>
7+ #include < ostream>
68#include < thread>
7-
8- #include " download_service.h"
99#include " exceptions/failed_curl_exception.h"
1010#include " exceptions/failed_init_curl_exception.h"
1111#include " exceptions/failed_open_file_exception.h"
12+ #include " utils/format_utils.h"
1213#include " utils/logging_utils.h"
1314
1415namespace {
@@ -19,14 +20,15 @@ size_t WriteCallback(void* ptr, size_t size, size_t nmemb, FILE* stream) {
1920} // namespace
2021
2122void DownloadService::AddDownloadTask (
22- const DownloadTask& task,
23- std::optional<OnDownloadTaskSuccessfully> callback) {
23+ DownloadTask& task, std::optional<OnDownloadTaskSuccessfully> callback) {
2424 CLI_LOG (" Validating download items, please wait.." );
2525 // preprocess to check if all the item are valid
2626 auto total_download_size{0 };
27- for (const auto & item : task.items ) {
27+ for (auto & item : task.items ) {
2828 try {
29- total_download_size += GetFileSize (item.downloadUrl );
29+ auto size = GetFileSize (item.downloadUrl );
30+ item.bytes = size;
31+ total_download_size += size;
3032 } catch (const FailedCurlException& e) {
3133 CTL_ERR (" Found invalid download item: " << item.downloadUrl << " - "
3234 << e.what ());
@@ -37,7 +39,7 @@ void DownloadService::AddDownloadTask(
3739 // all items are valid, start downloading
3840 for (const auto & item : task.items ) {
3941 CLI_LOG (" Start downloading: " + item.localPath .filename ().string ());
40- Download (task.id , item);
42+ Download (task.id , item, true );
4143 }
4244
4345 if (callback.has_value ()) {
@@ -76,15 +78,16 @@ void DownloadService::AddAsyncDownloadTask(
7678
7779 for (const auto & item : task.items ) {
7880 std::thread ([this , task, &callback, item]() {
79- this ->Download (task.id , item);
81+ this ->Download (task.id , item, false );
8082 }).detach ();
8183 }
8284
8385 // TODO: how to call the callback when all the download has finished?
8486}
8587
8688void DownloadService::Download (const std::string& download_id,
87- const DownloadItem& download_item) {
89+ const DownloadItem& download_item,
90+ bool allow_resume) {
8891 CTL_INF (" Absolute file output: " << download_item.localPath .string ());
8992
9093 CURL* curl;
@@ -96,7 +99,43 @@ void DownloadService::Download(const std::string& download_id,
9699 throw FailedInitCurlException ();
97100 }
98101
99- file = fopen (download_item.localPath .string ().c_str (), " wb" );
102+ std::string mode = " wb" ;
103+ if (allow_resume && std::filesystem::exists (download_item.localPath ) &&
104+ download_item.bytes .has_value ()) {
105+ FILE* existing_file = fopen (download_item.localPath .string ().c_str (), " r" );
106+ fseek (existing_file, 0 , SEEK_END);
107+ curl_off_t existing_file_size = ftell (existing_file);
108+ fclose (existing_file);
109+ auto missing_bytes = download_item.bytes .value () - existing_file_size;
110+ if (missing_bytes > 0 ) {
111+ CLI_LOG (" Found unfinished download! Additional "
112+ << format_utils::BytesToHumanReadable (missing_bytes)
113+ << " need to be downloaded." );
114+ std::cout << " Continue download [Y/n]: " << std::flush;
115+ std::string answer{" " };
116+ std::cin >> answer;
117+ if (answer == " Y" || answer == " y" || answer.empty ()) {
118+ mode = " ab" ;
119+ CLI_LOG (" Resuming download.." );
120+ } else {
121+ CLI_LOG (" Start over.." );
122+ }
123+ } else {
124+ CLI_LOG (download_item.localPath .filename ().string ()
125+ << " is already downloaded!" );
126+ std::cout << " Re-download? [Y/n]: " << std::flush;
127+
128+ std::string answer = " " ;
129+ std::cin >> answer;
130+ if (answer == " Y" || answer == " y" || answer.empty ()) {
131+ CLI_LOG (" Re-downloading.." );
132+ } else {
133+ return ;
134+ }
135+ }
136+ }
137+
138+ file = fopen (download_item.localPath .string ().c_str (), mode.c_str ());
100139 if (!file) {
101140 auto err_msg{" Failed to open output file " +
102141 download_item.localPath .string ()};
@@ -109,6 +148,12 @@ void DownloadService::Download(const std::string& download_id,
109148 curl_easy_setopt (curl, CURLOPT_NOPROGRESS, 0L );
110149 curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L );
111150
151+ if (mode == " ab" ) {
152+ fseek (file, 0 , SEEK_END);
153+ curl_off_t local_file_size = ftell (file);
154+ curl_easy_setopt (curl, CURLOPT_RESUME_FROM_LARGE, local_file_size);
155+ }
156+
112157 res = curl_easy_perform (curl);
113158
114159 if (res != CURLE_OK) {
0 commit comments