in Source/Services/Multiplayer/multiplayer_service.cpp [972:1132]
HRESULT MultiplayerService::WriteSessionUsingSubpath(
_In_ std::shared_ptr<XblMultiplayerSession> session,
_In_ XblMultiplayerSessionWriteMode mode,
_In_ const String& subpathAndQuery,
_In_ AsyncContext<Result<std::shared_ptr<XblMultiplayerSession>>> async
) noexcept
{
RETURN_HR_INVALIDARGUMENT_IF(subpathAndQuery.empty());
Result<User> userResult = m_user.Copy();
RETURN_HR_IF_FAILED(userResult.Hresult());
auto httpCall = MakeShared<XblHttpCall>(userResult.ExtractPayload());
RETURN_HR_IF_FAILED(httpCall->Init(
m_xboxLiveContextSettings,
"PUT",
XblHttpCall::BuildUrl("sessiondirectory", subpathAndQuery),
xbox_live_api::write_session_using_subpath
));
RETURN_HR_IF_FAILED(httpCall->SetRetryAllowed(false));
RETURN_HR_IF_FAILED(httpCall->SetXblServiceContractVersion(MULTIPLAYER_SERVICE_CONTRACT_VERSION));
switch (mode)
{
case XblMultiplayerSessionWriteMode::CreateNew:
{
RETURN_HR_IF_FAILED(httpCall->SetHeader("If-None-Match", "*"));
break;
}
case XblMultiplayerSessionWriteMode::UpdateExisting:
{
RETURN_HR_IF_FAILED(httpCall->SetHeader("If-Match", "*"));
break;
}
case XblMultiplayerSessionWriteMode::UpdateOrCreateNew:
{
// No match header
break;
}
case XblMultiplayerSessionWriteMode::SynchronizedUpdate:
{
if (session->ETag().empty())
{
RETURN_HR_IF_FAILED(httpCall->SetHeader("If-None-Match", "*"));
}
else
{
RETURN_HR_IF_FAILED(httpCall->SetHeader("If-Match", session->ETag()));
}
break;
}
default:
{
return E_INVALIDARG;
}
}
// Set the ConnectionId for the session
TaskQueue derivedQueue{ async.Queue().DeriveWorkerQueue() };
return SetRtaConnectionId(session, AsyncContext<Result<void>>{ derivedQueue,
[
httpCall,
xuid{ m_user.Xuid() },
sessionReference{ session->SessionReference() },
session,
async{ std::move(async) }
]
(Result<void> setConnectionIdResult)
{
if (Failed(setConnectionIdResult))
{
return async.Complete({ setConnectionIdResult.Hresult(), "Failed to establish MPSD RTA subscription" });
}
JsonDocument requestBody{ rapidjson::kObjectType };
session->Serialize(requestBody, requestBody.GetAllocator());
HRESULT hr = httpCall->SetRequestBody(requestBody);
if (FAILED(hr))
{
return async.Complete(hr);
}
hr = httpCall->Perform(AsyncContext<HttpResult>{ async.Queue().DeriveWorkerQueue(),
[
xuid,
sessionReference,
async
]
(HttpResult httpResult)
{
HRESULT hr = httpResult.Hresult();
if (FAILED(hr))
{
return async.Complete({ hr, "Http call failed" });
}
hr = httpResult.Payload()->Result();
auto statusCode = httpResult.Payload()->HttpStatus();
if (FAILED(hr) && statusCode != 412)
{
return async.Complete(hr);
}
else if (statusCode == 204)
{
// Consistent with XDK behavior, return success on 204 when writing session
return async.Complete(S_OK);
}
auto responseJson = httpResult.Payload()->GetResponseBodyJson();
if (responseJson.IsNull())
{
return async.Complete(hr);
}
XblMultiplayerSessionReference localSessionRef;
if (sessionReference.Scid[0] == 0)
{
auto contentLocation = httpResult.Payload()->GetResponseHeader("Content-Location");
hr = XblMultiplayerSessionReferenceParseFromUriPath(contentLocation.c_str(), &localSessionRef);
if (FAILED(hr))
{
return async.Complete({ E_FAIL, "Failed to parse session reference from URI" });
}
}
else
{
localSessionRef = sessionReference;
}
auto session = MakeShared<XblMultiplayerSession>(
xuid,
localSessionRef,
httpResult.Payload()->GetResponseHeader(ETAG_HEADER),
httpResult.Payload()->GetResponseHeader(DATE_HEADER),
httpResult.Payload()->GetResponseBodyJson()
);
if (FAILED(session->DeserializationError()) && SUCCEEDED(hr))
{
// WriteSession failed due to deserialization error
hr = session->DeserializationError();
}
session->SetWriteSessionStatus(
statusCode
);
return async.Complete(Result<std::shared_ptr<XblMultiplayerSession>>(session, hr));
}});
if (FAILED(hr))
{
return async.Complete(hr);
}
}
});
}