Получение прогресса загрузки файла из POCO StreamCopier через HTTPS

Я работал над HTTP-клиентами, использующими WinHTTP и WinInet, и недавно подумал о переходе на POCO, поскольку он предлагает лучшие API для реализации HTTP.

Я сделал это, но проблема в том, что я хочу узнать ход загрузки файла, периодически запрашивая поток или обрабатывая некоторые события.

Начал поиск API, который может это сделать, затем натолкнулся на эту загрузку по протоколу HTTP с информацией о прогрессе в C++ (Poco/Boost), которая говорит о получении прогресса для сценариев загрузки файлов с использованием CountingOutputStream. Я чувствую, что это неполно и не работает так, как я ожидал, что вообще не использует фактическую реализацию CountingStream.

Я узнал, что реализация возможна через CountingInputStream, но я не знаю, как это сделать с потоком, возвращаемым открытым вызовом HttpStreamFactory. Можно ли читать поток несколькими кусками, используя это? или периодически запрашивать объем прочитанных данных, чтобы я мог уведомить пользовательский интерфейс?

Вот мой код:

bool HttpClientConnection::DownloadFile ( const std::string& file_url, const std::string file_location )
{

         try
         {
               std::string complete_page_url = "";
               std::ofstream file_stream;
               std::unique_ptr<std::istream> pStr       = nullptr;


               if (isSecureConnection)
               {
                    complete_page_url = "https://";
               }
               else
               {
                    complete_page_url = "http://";
               }


               {
                    complete_page_url = serverHostName + file_url;// assuming the file url itself will contain leading forward slash
               }


             // Create the URI from the URL to the file.
             URI uri(complete_page_url);

               //std::auto_ptr<std::istream>pStr(URIStreamOpener::defaultOpener().open(uri);
            //StreamCopier::copyStream(*pStr.get(), std::cout);

             if (isSecureConnection)
             {
                  std::unique_ptr<HTTPSStreamFactory> https_stream_factory = nullptr;

                  if (_buseProxy)
                  {
                       https_stream_factory = std::unique_ptr<HTTPSStreamFactory>(new HTTPSStreamFactory(proxyHostName, proxyPort, getProxyUserName(),  getProxyPassword()));
                  }
                  else
                  {
                       https_stream_factory = std::unique_ptr<HTTPSStreamFactory>(new HTTPSStreamFactory());
                  }

                  if (https_stream_factory)
                  {
                      pStr  = std::unique_ptr<std::istream>(https_stream_factory->open(uri));
                  }
              }
              else
              {
                  std::unique_ptr<HTTPStreamFactory> http_stream_factory = nullptr;

                  if (_buseProxy)
                  {
                      http_stream_factory = std::unique_ptr<HTTPStreamFactory>(new HTTPStreamFactory(proxyHostName, proxyPort, getProxyUserName(),  getProxyPassword()));
                  }
                  else
                  {
                      http_stream_factory   = std::unique_ptr<HTTPStreamFactory>(new HTTPStreamFactory());
                  }

                  if (http_stream_factory)
                  {
                      pStr  = std::unique_ptr<std::istream>(http_stream_factory->open(uri));
                  }
            }

            if (pStr)
            {
                  file_stream.open(file_location, ios::out | ios::trunc | ios::binary);

                  StreamCopier::copyStream(*pStr.get(), file_stream);

                  file_stream.close();
             }

           return true;
}
catch (Exception& exc)
{
    if (httpLogger)
    {
                                         httpLogger->log(dcLogger::LOG_INFO, "HttpClient:: Exception in DownloadFile , error code: %d", exc.code());
    }
}

return false;

}

1 ответ

Решение

Передал объект потока выходного файла в CountingOutputStream и запустил таймер с подсчетом выходного потока в качестве параметра. Таймер вызывается периодически до завершения передачи данных, который получает количество записанных байтов и уведомляет того, кто зарегистрировался для этого события. Это сработало!

shared_ptr<CountingOutputStream> cout_stream = shared_ptr<CountingOutputStream>(new CountingOutputStream(file_stream));

if (callback && callback_interval_in_millis > 0)
{
    shared_ptr<FileProgressHandler> file_progress = shared_ptr<FileProgressHandler>(new FileProgressHandler(cout_stream, file_size, callback));

    if (file_progress)
    {
        TimerCallback<FileProgressHandler> callback(*(file_progress.get()), &FileProgressHandler::onTimer);

        timer = shared_ptr<Timer>(new Timer(0, callback_interval_in_millis));

        if (timer)
        {
            timer->start(callback);
        }
    }

    StreamCopier::copyStream(*pStr.get(), *cout_stream);

    if (timer)
    {
         timer->stop();
    }
}

void onTimer(Timer& timer)
{
    try
    {
        if (progress_callback)
        {
            int data_processed = 0;

            counting_io_stream ? data_processed = counting_io_stream->chars() : __noop;

            if (data_processed != total_processed_data)
            {
                total_processed_data = data_processed;

                int percent     = (100 * total_processed_data) / file_size;

                progress_callback(percent);
            }
        }
    }
    catch(const std::bad_function_call& e) 
    {

    }
    catch(const std::bad_weak_ptr& e)
    {

    }
    catch(const std::exception& e)
    {

    }
}
Другие вопросы по тегам