увеличить wait_for_any с помощью asio io-service ... как я могу вернуть подходящее будущее для wait_for_any? - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть код, который использует asio coroutine для получения файла с использованием http, получает асинхронно.
Теперь я пытаюсь изменить этот код, чтобы получить 24 файла, я хочу сделать контейнер, который имеет boost :: futures ", а не std :: futures ", чтобы я мог использовать wait_for_any для обработки готового к использованию будущего.
я хочу преобразовать свою сопрограмму во что-то, что сохраняет асинхронный http get, и в то же время возвращает правильное имя файла при окончании http get" или ошибка ".
это моя сопрограмма:

   void HTTPRequest::Execute(boost::asio::yield_context yield_r, std::string request_name, boost::shared_ptr<std::map<std::string, boost::shared_ptr<HTTPResponse>>> mHTTPClient_Responses_Map_shared_pointer)
//4-9-2020 trial of promise
//13std::string HTTPRequest::Execute(boost::asio::yield_context yield_r, boost::promise<std::string> &p, std::string request_name, boost::shared_ptr<std::map<std::string, boost::shared_ptr<HTTPResponse>>> mHTTPClient_Responses_Map_shared_pointer)
{
    std::map<std::string, boost::shared_ptr<HTTPResponse>> & mHTTPClient_Responses_Map = boost::ref(*mHTTPClient_Responses_Map_shared_pointer).get() ;
    ptime startFetch = second_clock::local_time();
    boost::unique_lock<boost::mutex> cancel_lock(mCancelMutex);
    if (mWasCancelled)
    {
        cancel_lock.unlock();
        OnFinish(boost::system::error_code(boost::asio::error::operation_aborted));

        m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << " has been cancelled by the user at start of HTTPRequest::Execute coroutine." << std::endl;
        m_formatting_ostream.flush();
        ////allam2020 change UniqueSignalValue to url
        boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "cancelExecute", request_name, m_formatting_ostream_string);
        m_formatting_ostream.clear();

        //p.set_value(request_name);
        //return request_name;

    }
    cancel_lock.unlock();

    bool iterator_failed = true;////    allam 2020 where is this variable changed?????????? is it before SendRequest()??????? after async_connect retruns successfully
    boost::system::error_code ec;
    for (auto iterator_resolve : *mRequestSharedPtrVecResolverIterator)
    {
        BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) << "Request #" << this->GetId() << " for " << mUrl <<" trying to send request using " << iterator_resolve->endpoint().address().to_string() << std::endl;

        // Compose the request message.
        mRequestBuf += "GET " + mUri + " HTTP/1.1\r\n";
        // Add mandatory header.
        mRequestBuf += "Host: " + mHost + "\r\n";
        mRequestBuf += "\r\n";

        for (int mIrange : boost::irange(0, ATTEMPTS))
        {
            HTTPRequest::mIrange = mIrange;
            ////allam2020 1111111111111111111111111111111111111111111111111111111111
            resolver_iterator iterator_connect = boost::asio::async_connect(mSock, iterator_resolve, yield_r[ec]);////allam 2020 this gets us back to io_stream_run

            if (ec.value() == boost::system::errc::errc_t::success)//(ec.value()==0)
            {               
                ////allam 2020
                iterator_failed = false;//????????????/////???????

                boost::unique_lock<boost::mutex> cancel_lock(mCancelMutex);
                if (mWasCancelled)
                {
                    cancel_lock.unlock();
                    OnFinish(boost::system::error_code(boost::asio::error::operation_aborted));

                    m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << " has been cancelled by the user after returning from async_connect inside HTTPRequest::Execute using"<< iterator_resolve->endpoint().address().to_string() << std::endl;
                    m_formatting_ostream.flush();
                    boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "cancel_async_connect_Execute", iterator_resolve->endpoint().address().to_string(),m_formatting_ostream_string);
                    m_formatting_ostream.clear();

                    //p.set_value(request_name);
                    //return request_name;
                }

                cancel_lock.unlock();

                // Send the request message.
                SendRequest(yield_r);////alllam 2020 VVVVVVVVIIIIIIIIIIIIIPPPPPPPPPPP MILESTONE
            }
            else if (ec.value() != boost::system::errc::errc_t::success)//(ec.value()==0) //(ec.value() != 0)
            {
                OnFinish(ec);               
                BOOST_LOG((*mHTTPRequest_LoggingInstance_shared_pointer).mloggerCoutLog) <<"Request #" << this->GetId() << " for " << mUrl <<" failed after trying " << mIrange << "times" << " to async_connect inside HTTPRequest::Execute " << std::endl;                
                continue;
            }


            ////allam 2020  now test for mContinue_for ,this is done for other functions recurdively called inside SendRequest
            if (mContinue_for==true)
            {
                mContinue_for = !(mContinue_for);
                boost::this_thread::sleep_for(boost::chrono::seconds(mIrange));

                continue;
            }

            // Response is correct.
            //log str_status_code
            //Logger.info("Fetched {0} completed in {1}s".format(id, time.time() - start))
            //allam2020
            m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << "Fetched " << mUrl << " completed in : " << (second_clock::local_time() - startFetch) << "with HTTP code :" << mResponsePtr->get_status_code() << "\n" << "and the code reasonPhrase is :" << HttpStatus::reasonPhrase(static_cast<int>(mResponsePtr->get_status_code())) << "with certain resolver iterator " << iterator_resolve->endpoint().address().to_string() << std::endl;
            m_formatting_ostream.flush();

            boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "http_request_completed", HttpStatus::reasonPhrase(static_cast<int>(mResponsePtr->get_status_code())), m_formatting_ostream_string);
            m_formatting_ostream.clear();

            //if len(buffer.getbuffer()) <= 0:
            if (mResponsePtr->get_response_buf().size() <= 0)
            {
                //Logger.info("Buffer for {0} is empty ".format(id))
                //allam2020
                m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << "Fetched " << mUrl << " with Buffer for " << mUrl << " is empty  " << "\n" << "with HTTP code :" << mResponsePtr->get_status_code() << "\n" << "and the code reasonPhrase is :" << HttpStatus::reasonPhrase(static_cast<int>(mResponsePtr->get_status_code())) << std::endl;
                m_formatting_ostream.flush();

                boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "http_request_completed_empty", HttpStatus::reasonPhrase(static_cast<int>(mResponsePtr->get_status_code())), m_formatting_ostream_string);
                m_formatting_ostream.clear();

            }

            //continue work on response
            ////std::string response_name = "response_" + request_name;////allam 2020 make this member variable????????????//4-22-2020 yes 
            mHTTPRequest_response_name = "response_" + request_name;
            mHTTPClient_Responses_Map[mHTTPRequest_response_name] = GetResponseSharedPtr();

            break;
        }

        //the following conditions test the result of send request
        if (mSendRequest == 0)
        {
            if (mReadStatusLine == 0)
            {
                if (mHttp_1_1 == 0)
                {
                    if (mStatusCodeNot200 == 0)
                    {
                        if (mReadResponseHeaders == 0)
                        {
                            if (mReadResponseBody == 0)
                            {
                                ////allam2020 4-4-2020 no error present and response is recieved in its mHTTPResponse SO DO NOTHING 
                            }
                            else if (mReadResponseBody != 0)
                            {
                                m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << " has failed completely after trying" << ATTEMPTS << "times" << " to async_read inside HTTPRequest::ReadResponseBody to get ResponseBody  " << "with certain resolver iterator " << iterator_resolve->endpoint().address().to_string() << std::endl;
                                m_formatting_ostream.flush();
                                boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "failed_async_read_inside_HTTPRequest_ReadResponseBody", "requestFailed_ReadResponseBody_Iterator_ " + iterator_resolve->endpoint().address().to_string(),m_formatting_ostream_string);
                                m_formatting_ostream.clear();
                            }
                        }
                        else if (mReadResponseHeaders != 0)
                        {
                            m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << " has failed completely after trying" << ATTEMPTS << "times" << " to async_read_until inside HTTPRequest::ReadResponseHeadersto get ResponseHeaders " << "with certain resolver iterator " << iterator_resolve->endpoint().address().to_string() << std::endl;
                            m_formatting_ostream.flush();
                            boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "failed_async_read_until_inside_HTTPRequest_ReadResponseHeaders", "requestFailed_ReadResponseHeaders_Iterator_ " + iterator_resolve->endpoint().address().to_string(), m_formatting_ostream_string);
                            m_formatting_ostream.clear();
                        }
                    }
                    else if (mStatusCodeNot200 != 0)
                    {
                        m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << " has failed completely after" << ATTEMPTS << "times" << " to async_read_until inside HTTPRequest::ReadStatusLine because of status_code not 200:" << http_errors::invalid_response << "the error code is :" << mStatusCode << "\n" << "and the error reasonPhrase is :" << HttpStatus::reasonPhrase(static_cast<int>(std::stoul(mStatusCode))) << "with certain resolver iterator " << iterator_resolve->endpoint().address().to_string() << std::endl;
                        m_formatting_ostream.flush();
                        boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "failed_StatusCodeNot200_inside_HTTPRequest_ReadStatusLine", "requestFailed_ReadStatusLine_StatusCodeNot200:" + mStatusCode + "_Iterator_ " + iterator_resolve->endpoint().address().to_string(), m_formatting_ostream_string);
                        m_formatting_ostream.clear();
                    }
                }
                else if (mHttp_1_1 != 0)
                {
                    ////4-2-2020
                    m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << " after trying " << ATTEMPTS << "times" << " to async_read_until inside HTTPRequest::ReadStatusLine because of bad not http/1.1 version response" << mHTTP_Version << "recieved with certain resolver iterator " << iterator_resolve->endpoint().address().to_string() << std::endl;
                    m_formatting_ostream.flush();
                    boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "failed_Http_1_1_inside_HTTPRequest_ReadStatusLine", "requestFailed_ReadStatusLine_Http_1_1_Iterator " + iterator_resolve->endpoint().address().to_string(), m_formatting_ostream_string);
                    m_formatting_ostream.clear();
                }
            }
            else if (mReadStatusLine != 0)
            {
                ////4-2-2020
                m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << " after trying " << ATTEMPTS << "times" << " to async_read_until inside HTTPRequest::ReadStatusLine  with certain resolver iterator " << iterator_resolve->endpoint().address().to_string() << std::endl;
                m_formatting_ostream.flush();
                boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "failed_async_read_until_inside_HTTPRequest_ReadStatusLine", "requestFailed_ReadStatusLine_Iterator " + iterator_resolve->endpoint().address().to_string(), m_formatting_ostream_string);
                m_formatting_ostream.clear();
            }
        }
        else if (mSendRequest != 0)
        {
            ////4-2-2020
            m_formatting_ostream << "Request #" << this->GetId() << " for " << mUrl << " after trying " << ATTEMPTS << "times" << " to async_write inside HTTPRequest::SendRequest  with certain resolver iterator " << iterator_resolve->endpoint().address().to_string() << std::endl;
            m_formatting_ostream.flush();
            boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "failed_async_write_inside_HTTPRequest_SendRequest", "requestFailed_SendRequest_Iterator " + iterator_resolve->endpoint().address().to_string(), m_formatting_ostream_string);
            m_formatting_ostream.clear();
        }



        if (iterator_failed == true)
        {
            m_formatting_ostream << "Request failed for " << mUrl << " after trying " << ATTEMPTS << "times" << " to async_connect inside HTTPRequest::Execute with certain resolver iterator "<< iterator_resolve->endpoint().address().to_string() << std::endl;
            m_formatting_ostream.flush();
            ////allam 2020 i might need to pass iterator resolve which has failed
            boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "failed_async_connect_inside_HTTPRequest_Execute", "requestFailed_Iterator " + iterator_resolve->endpoint().address().to_string(), m_formatting_ostream_string);
            m_formatting_ostream.clear();


            continue;////allam 2020 here i should continue for next iterator
        }
    }
    if (iterator_failed == true)
    {
        m_formatting_ostream << "Request failed for " << mUrl << " after trying " << ATTEMPTS << "times" << " to async_connect inside HTTPRequest::Execute with ALL resolver iterators" << std::endl;
        m_formatting_ostream.flush();
        ////allam 2020 i might need to pass iterator resolve which has failed
        boost_log_function(mHTTPRequest_LoggingInstance_shared_pointer, "failed_async_connect_inside_HTTPRequest_Execute", "requestFailed_Iterator" + GetmUrlLogger(),m_formatting_ostream_string);////allam2020 ?????i might need to change this from GetmUrlLogger to request name argument of Execute???????????????????4-2-2020
        m_formatting_ostream.clear();
        ////allam 2020 here i should return from execute because no resolved address could be used so the whole execute request operation failed

        //p.set_value(request_name);
        //return request_name;
    }
    ////allam2020 should i put if conditions for mSendRequest ....mReadResponseBody????? to identify final complete error at these functions and end of 5 attempts

}

есть другие функции SendRequest ..., которые вызываются из Execute, но я не помещал их, чтобы сделать меньше кода.
при необходимости я буду опубликовать их.

1 Ответ

1 голос
/ 24 апреля 2020

Я не часто выдыхаю, просто читая код. Это один из тех моментов. Вы должны, вероятно, просто заявить о своей цели.

  • Кроме того, mRequestSharedPtrVecResolverIterator предполагает, что вы сохраняете вектор результатов распознавателя только для того, чтобы просмотреть их и попытаться выполнить запрос.

    Знаете ли вы, что вы можете просто использовать boost::asio::[async_]connect, чтобы сделать это для вас ?. Похоже, что простой boost::asio::async_connect должен решить все ваши проблемы с итераторами распознавателя, а

  • вы должны просто вернуть ответ вместо того, чтобы волшебным образом установить его на карте (вам не нужно иметь доступ на другие записи).
  • Наконец, вы можете сократить 99% общих указателей, и это сэкономит вам больше времени, чем надуманная оптимизация с m_formatting_ostream, которую я представлял как

    std::string m_formatting_ostream_string;
    boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>>
        m_formatting_ostream{ m_formatting_ostream_string };
    

    , но вы сохраняете повторяя подверженный ошибкам и неэффективный код, такой как

    m_formatting_ostream << ... << std::endl;
    m_formatting_ostream.flush(); // this is redundant already
    boost_log_function(
        ...,
        m_formatting_ostream_string);
    m_formatting_ostream.clear();
    
  • Там намного больше запутанного кода. Например, что здесь происходит?

    boost :: ref (* mHTTPClient_Responses_Map_shared_pointer) .get ();

boost::ref(*p).get() по определению просто *p.

  • Все с состоянием и хуже: состояние видоизменяется. Например,

    mRequestBuf += "GET " + mUri + " HTTP/1.1\r\n";
    // Add mandatory header.
    mRequestBuf += "Host: " + mHost + "\r\n";
    mRequestBuf += "\r\n";
    

    происходит каждый раз через l oop, но никогда не сбрасывается. Вероятно, это не должно происходить несколько раз (это расточительно)

  • boost::this_thread::sleep_for(boost::chrono::seconds(mIrange)); - огромный красный флаг в asyn c IO. Вы должны ждать результатов без сна.

  • Вы используете весь мьютекс вокруг логического флага. Просто сделайте этот атом c

    std::atomic_bool mWasCancelled{ false };
    

    Кроме того, использование unique_lock не имеет смысла, если вы делаете разблокировку вручную 100% времени.

  • В общем, существует тенденция к очень многословным ( венгерским ) именам и тем же комментариям. Это, вероятно, пытается получить контроль над смыслом, но происходит обратное: код становится настолько «впечатляющим» и «учитываемым», что на самом деле неясно, что он должен делать и почему он должен работать.

  • Этот шаблон Christmas Tree anti - это то, для чего были придуманы исключения. Это также устраняет необходимость Execute «знать» о каждой маленькой детали реализации SendRequest и множестве непостижимых флагов состояния, которые он может устанавливать в таинственные значения.

enter image description here

Хорошо. Я действительно задыхаюсь. Я не смогу это исправить или даже распознать вопрос (потому что не было ни единого будущего). Вместо этого я бы предложил использовать что-то вроде https://www.boost.org/doc/libs/develop/libs/beast/example/http/client/async/http_client_async.cpp для немного менее сложного подхода, который подойдет для поддержки.

...