165 lines
4.8 KiB
C++
165 lines
4.8 KiB
C++
///////////////////////////////////////////////////////////////////
|
|
//*-------------------------------------------------------------*//
|
|
//| Part of the Game Jolt API C++ Library (http://gamejolt.com) |//
|
|
//*-------------------------------------------------------------*//
|
|
//| Released under the zlib License |//
|
|
//| More information available in the readme file |//
|
|
//*-------------------------------------------------------------*//
|
|
///////////////////////////////////////////////////////////////////
|
|
#include "gjAPI.h"
|
|
|
|
|
|
// ****************************************************************
|
|
/* constructor */
|
|
gjNetwork::gjNetwork(gjAPI* pAPI)noexcept
|
|
: m_iNumSessions (0)
|
|
, m_pAPI (pAPI)
|
|
{
|
|
// init cURL
|
|
curl_global_init(CURL_GLOBAL_ALL);
|
|
m_pMultiHandle = curl_multi_init();
|
|
|
|
// reserve some memory
|
|
m_apCall.reserve(GJ_API_RESERVE_CALL);
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* destructor */
|
|
gjNetwork::~gjNetwork()
|
|
{
|
|
// finish and remove open sessions
|
|
this->Wait(2);
|
|
while(!m_apCall.empty())
|
|
{
|
|
gjAPI::ErrorLogAdd("Network Error: session had to be killed <" + m_apCall[0]->GetInfo() + ">");
|
|
this->__KillCall(m_apCall[0]);
|
|
}
|
|
|
|
// clear memory
|
|
m_apCall.clear();
|
|
|
|
// exit cURL
|
|
curl_multi_cleanup(m_pMultiHandle);
|
|
curl_global_cleanup();
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* update all active non-blocking cURL sessions */
|
|
bool gjNetwork::Update()
|
|
{
|
|
if(m_apCall.empty()) return false;
|
|
|
|
// update cURL
|
|
curl_multi_perform(m_pMultiHandle, &m_iNumSessions);
|
|
|
|
// manage active cURL sessions
|
|
CURLMsg* pMsg;
|
|
while((pMsg = curl_multi_info_read(m_pMultiHandle, &m_iNumSessions)))
|
|
{
|
|
// cURL session finished
|
|
if(pMsg->msg == CURLMSG_DONE)
|
|
{
|
|
CURL* pSession = pMsg->easy_handle;
|
|
const bool bOK = (pMsg->data.result == CURLE_OK) ? true : false;
|
|
|
|
// search callback object and finish the operation
|
|
FOR_EACH(it, m_apCall)
|
|
{
|
|
gjCall* pCall = (*it);
|
|
|
|
if(pCall->GetSession() == pSession)
|
|
{
|
|
// check for errors
|
|
if(!bOK)
|
|
{
|
|
gjAPI::ErrorLogAdd("Network Error: sending non-blocking request failed <" + pCall->GetInfo() + ">");
|
|
gjAPI::ErrorLogAdd("Network Error: " + std::string(curl_easy_strerror(pMsg->data.result)));
|
|
}
|
|
|
|
pCall->Finish(bOK);
|
|
SAFE_DELETE(pCall)
|
|
m_apCall.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// close cURL session
|
|
curl_multi_remove_handle(m_pMultiHandle, pSession);
|
|
curl_easy_cleanup(pSession);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* finish all active sessions and return */
|
|
void gjNetwork::Wait(const unsigned int& iMaxWait)
|
|
{
|
|
// get max waiting time (low precision)
|
|
const time_t iMaxTime = std::time(NULL) + iMaxWait;
|
|
|
|
// force network update
|
|
while((iMaxTime >= std::time(NULL) || !iMaxWait) && this->Update()) {}
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* check for existing callbacks on the list */
|
|
gjNetwork::gjCall* gjNetwork::__CheckCall(const std::string& sInfo)
|
|
{
|
|
// search callback object and compare info string
|
|
FOR_EACH(it, m_apCall)
|
|
{
|
|
if((*it)->GetInfo() == sInfo)
|
|
return (*it);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* kill and remove session and callback object */
|
|
void gjNetwork::__KillCall(gjCall* pCall)
|
|
{
|
|
// search callback object
|
|
FOR_EACH(it, m_apCall)
|
|
{
|
|
gjCall* pCurCall = (*it);
|
|
|
|
if(pCurCall == pCall)
|
|
{
|
|
CURL* pSession = pCurCall->GetSession();
|
|
|
|
// delete callback object
|
|
pCurCall->Finish(false);
|
|
SAFE_DELETE(pCurCall)
|
|
m_apCall.erase(it);
|
|
|
|
// close cURL session
|
|
curl_multi_remove_handle(m_pMultiHandle, pSession);
|
|
curl_easy_cleanup(pSession);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ****************************************************************
|
|
/* callbacks for writing operations with cURL */
|
|
size_t write_to_string(char* ptr, size_t size, size_t count, std::string* stream)
|
|
{
|
|
const size_t num = size * count;
|
|
stream->append(ptr, 0, num);
|
|
return num;
|
|
}
|
|
|
|
size_t write_to_file(void* ptr, size_t size, size_t count, FILE* stream)
|
|
{
|
|
return fwrite(ptr, size, count, stream);
|
|
} |