212 lines
7.6 KiB
C++
212 lines
7.6 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// (c) Copyright, Ubisoft Entertainment Inc. || Created by Harbour //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
#pragma once
|
|
#include "ubiservices/core/errors/errorDetails.h"
|
|
#include "ubiservices/core/errors/restErrorHandler.h"
|
|
#include "ubiservices/core/helpers/helpers.h"
|
|
#include "ubiservices/core/helpers/restServerFault.h"
|
|
#include "ubiservices/core/JSON/jsonWriter.h"
|
|
#include "ubiservices/core/log/remoteLoggerHelper.h"
|
|
#include "ubiservices/services/http/httpResponse.h"
|
|
#include "ubiservices/services/http/request/httpRequest.h"
|
|
|
|
namespace US_NS {;
|
|
|
|
template<typename T>
|
|
JobUbiservicesCall<T>::JobUbiservicesCall(
|
|
const JobAsyncType& asyncResult, FacadeInternal& facade,
|
|
const Job::Step& stepFirst, ClockSteady::TTimeMilli waitTime)
|
|
: JobAsyncWait<T>(asyncResult, stepFirst, waitTime)
|
|
, FacadeInterface(facade)
|
|
{
|
|
}
|
|
|
|
template<typename T>
|
|
JobUbiservicesCall<T>::JobUbiservicesCall(
|
|
const JobAsyncType& asyncResult, const FacadeInterface& facade,
|
|
const Job::Step& stepFirst, ClockSteady::TTimeMilli waitTime)
|
|
: JobAsyncWait<T>(asyncResult, stepFirst, waitTime)
|
|
, FacadeInterface(facade)
|
|
{
|
|
}
|
|
|
|
template<typename T>
|
|
JobUbiservicesCall<T>::~JobUbiservicesCall()
|
|
{
|
|
}
|
|
|
|
template<typename T>
|
|
void JobUbiservicesCall<T>::waitUntilCompletionRest(
|
|
Job::Step::StepMethod method, const char* description,
|
|
const HttpRequest& request, const RestFaultData& errorHandler)
|
|
{
|
|
waitUntilCompletionRest(getAsyncResultRest(), method, description, request, errorHandler);
|
|
}
|
|
|
|
template<typename T>
|
|
void JobUbiservicesCall<T>::waitUntilCompletionRest(
|
|
const AsyncResult<HttpResponse>& asyncResult,
|
|
Job::Step::StepMethod method, const char* description,
|
|
const HttpRequest& request, const RestFaultData& errorHandler)
|
|
{
|
|
US_PERF_TASK_FUNC_DETAIL();
|
|
//US_ASSERT(errorHandler.m_handler, "Design expectation");
|
|
US_ASSERT(!asyncResult.isAvailable(), "Design expectation");
|
|
|
|
const Job::Step step(method, description);
|
|
|
|
m_errorHandler = errorHandler; //m_restErrorHandler.reset(errorHandler);
|
|
m_httpPendingRequest.reset(request.clone());
|
|
|
|
if (asyncResult.hasFailed())
|
|
{
|
|
this->onError(step.getDescription(), asyncResult.getError());
|
|
this->reportError(asyncResult.getError());
|
|
}
|
|
else if (asyncResult.hasSucceeded())
|
|
{
|
|
if (asyncResult.getResult().isSuccessStatusCode())
|
|
{
|
|
this->setStep(step);
|
|
}
|
|
else
|
|
{
|
|
handleRestError(asyncResult.getResult(), step.getDescription());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
this->getCallerAsync().addChildAsync(asyncResult);
|
|
this->m_asyncPendingRest = asyncResult;
|
|
this->saveNextStep(step);
|
|
|
|
JOB_STEP_NEXT(JobUbiservicesCall::waitAsyncRest);
|
|
return;
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void JobUbiservicesCall<T>::waitUntilCompletionRest(const HttpRequest& request, const RestFaultData& errorHandler)
|
|
{
|
|
waitUntilCompletionRest(getAsyncResultRest(), JOB_STEP(JobUbiservicesCall<T>::reportOutcomeRest), request, errorHandler);
|
|
}
|
|
|
|
template<typename T>
|
|
void JobUbiservicesCall<T>::waitUntilCompletionRest(const AsyncResult<HttpResponse>& asyncResult, const HttpRequest& request, const RestFaultData& errorHandler)
|
|
{
|
|
waitUntilCompletionRest(asyncResult, JOB_STEP(JobUbiservicesCall<T>::reportOutcomeRest), request, errorHandler);
|
|
}
|
|
|
|
template<typename T>
|
|
AsyncResult<HttpResponse>& JobUbiservicesCall<T>::getAsyncResultRest()
|
|
{
|
|
return m_asyncPendingRest;
|
|
}
|
|
|
|
template<typename T>
|
|
void JobUbiservicesCall<T>::waitAsyncRest()
|
|
{
|
|
US_PERF_TASK_FUNC_DETAIL();
|
|
|
|
const AsyncResultBase& asyncRest = m_asyncPendingRest;
|
|
|
|
if (asyncRest.hasFailed() || asyncRest.hasSucceeded())
|
|
{
|
|
// The condition check is redundant but this method implementation following
|
|
// the same pattern as JobSequence<T>::waitAsync()
|
|
if (asyncRest.hasFailed())
|
|
{
|
|
this->onError(this->getNextStepDescription(), asyncRest.getError());
|
|
this->reportError(asyncRest.getError());
|
|
}
|
|
else if (this->m_asyncPendingRest.getResult().isSuccessStatusCode())
|
|
{
|
|
this->enableNextStep();
|
|
}
|
|
else
|
|
{
|
|
handleRestError(m_asyncPendingRest.getResult(), this->getNextStepDescription());
|
|
}
|
|
|
|
// Remove m_asynPending from the childrenAsyncs to avoid piling up in periodic infinite jobs
|
|
// such as JobSendEventsPeriodic or JobExtendSession
|
|
// This function calls the destructor so there is no need to decrease ref count
|
|
this->getCallerAsync().removeChildAsync(asyncRest);
|
|
}
|
|
else
|
|
{
|
|
// There is no timeout. It is assumed timeout is implemented for m_asyncPending call.
|
|
this->setToWaiting(10);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void JobUbiservicesCall<T>::handleRestError(const HttpResponse& httpResponse, const String& stepDescription)
|
|
{
|
|
US_PERF_TASK_FUNC_DETAIL();
|
|
RestServerFault restFault = RestError::translateError(*m_httpPendingRequest, httpResponse,
|
|
m_errorHandler.m_genericErrorCode,
|
|
m_errorHandler.m_logCategory,
|
|
m_errorHandler.m_handler);
|
|
|
|
if (restFault.m_environment.isSpecified())
|
|
{
|
|
FacadeInterface::setEnvironmentOnError(restFault.m_environment.value());
|
|
}
|
|
|
|
// Logging both the request and the response for debugging & support!
|
|
US_LOG(LogLevel::Error, restFault.m_logCategory,
|
|
this->getNextStepDescription() << " received service error: " << *m_httpPendingRequest << httpResponse);
|
|
|
|
// Send remote log
|
|
if (RemoteLoggerHelper::isRemoteLogEnabled(FacadeInterface::getFacade(), LogLevel::Error, restFault.m_logCategory))
|
|
{
|
|
JsonWriter fields;
|
|
fields["requestStatusCode"] = httpResponse.getStatusCode();
|
|
fields["sdkErrorCode"] = restFault.m_usError.m_usCode;
|
|
fields["serviceErrorCode"] = restFault.m_serverErrorCode;
|
|
fields["transactionId"] = httpResponse.getHeader("Ubi-TransactionId");
|
|
|
|
StringStream ss;
|
|
// The httpRequest and the httpResponse are logged in jobHttpRequest, it is not required to log them again.
|
|
ss << this->getNextStepDescription() << " received service error: " << restFault.m_serverErrorCode << US_NS::endl
|
|
<< restFault.m_serverErrorContext << ": " << restFault.m_serverErrorMsg << US_NS::endl
|
|
<< "sdkErrorCode: " << restFault.m_usError.m_usCode;
|
|
InstancesHelper::sendRemoteLog(FacadeInterface::getFacade(), LogLevel::Error, restFault.m_logCategory, ss.getContent(), fields.getJson());
|
|
}
|
|
this->onRestError(stepDescription, restFault);
|
|
|
|
// The onRestError may contain some code needed for ending the job cleanly.
|
|
// The job shall be set to error AFTER the onRestError call(), otherwise,
|
|
// the AsyncResult::wait() returns before the onRestError is achieved
|
|
restFault.m_usSetJobToError = onRestErrorSetJobToError();
|
|
if (restFault.m_usSetJobToError)
|
|
{
|
|
SET_JOB_TO_ERROR(this->getCallerAsync(), restFault.m_usError.m_usCode, restFault.m_usError.m_usText);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void JobUbiservicesCall<T>::logError(LogLevel logLevel, LogCategory logCategory, const String& description)
|
|
{
|
|
US_LOG_REMOTE(FacadeInterface::getFacade(), logLevel, logCategory, description);
|
|
#if !defined(US_LOG_ENABLED)
|
|
US_UNUSED(description);
|
|
#endif
|
|
}
|
|
|
|
template<typename T>
|
|
void JobUbiservicesCall<T>::onRestError(const String& stepDescription, const RestServerFault& fault)
|
|
{
|
|
US_UNUSED(stepDescription);
|
|
US_UNUSED(fault);
|
|
}
|
|
|
|
template<typename T>
|
|
bool JobUbiservicesCall<T>::onRestErrorSetJobToError()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
};
|