JD2022-TU1/main/extern/UbiServices/custom/client-sdk/private/ubiservices/services/jobUbiservicesCall.inl

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;
}
};