in Source/Services/Notification/notification_service.cpp [124:264]
HRESULT NotificationService::RegisterForNotificationsHelper(
_In_ const String& applicationInstanceId,
_In_ const String& uriData,
_In_ const String& platform,
_In_ const String& deviceName,
_In_ const String& platformVersion,
_In_ const Vector<NotificationFilter> notificationFilterEnum,
_In_ AsyncContext<HRESULT> async
)
{
switch (m_registrationStatus)
{
case RegistrationStatus::PendingUnregistration:
{
// This indicates registration is in progress. Since another registration was requested, abort the
// pending unregistration, complete the unregistration AsyncContext, and collapse the register AsyncContexts
m_registrationAsync = AsyncContext<HRESULT>::Collapse({ std::move(m_registrationAsync), std::move(async) });
m_registrationStatus = RegistrationStatus::Registering;
m_unregistrationAsync.Complete(E_ABORT);
return S_OK;
}
case RegistrationStatus::Registered:
{
// If we have already registered, no work to do
async.Complete(S_OK);
return S_OK;
}
case RegistrationStatus::Registering:
{
// If we are already registering, collapse the AsyncContexts and return
m_registrationAsync = AsyncContext<HRESULT>::Collapse({ std::move(m_registrationAsync), std::move(async) });
return S_OK;
}
default:
{
auto workQueue = async.Queue().DeriveWorkerQueue();
m_registrationAsync = AsyncContext<HRESULT>::Collapse({ std::move(m_registrationAsync), std::move(async) });
m_registrationStatus = RegistrationStatus::Registering;
xsapi_internal_stringstream str;
str << AppConfig::Instance()->TitleId();
xsapi_internal_string titleId = str.str();
JsonDocument payload(rapidjson::kObjectType);
JsonDocument::AllocatorType& allocator = payload.GetAllocator();
payload.AddMember("systemId", JsonValue(applicationInstanceId.data(), allocator).Move(), allocator);
payload.AddMember("endpointUri", JsonValue(uriData.data(), allocator).Move(), allocator);
payload.AddMember("platform", JsonValue(platform.data(), allocator).Move(), allocator);
if (!platformVersion.empty())
{
payload.AddMember("platformVersion", JsonValue(platformVersion.data(), allocator).Move(), allocator);
}
#if HC_PLATFORM == HC_PLATFORM_IOS
payload.AddMember("transport", "NotiHub", allocator);
payload.AddMember("transportPath", JsonValue(AppConfig::Instance()->APNSEnvironment().c_str(), allocator).Move(), allocator);
#elif HC_PLATFORM == HC_PLATFORM_ANDROID
payload.AddMember("transport", "FCM", allocator);
#elif HC_PLATFORM == HC_PLATFORM_WIN32 || HC_PLATFORM == HC_PLATFORM_GDK || HC_PLATFORM_IS_EXTERNAL
payload.AddMember("transport", "RTA", allocator);
#endif
xsapi_internal_string locale = utils::get_locales();
payload.AddMember("locale", JsonValue(locale.c_str(), allocator).Move(), allocator);
payload.AddMember("titleId", JsonValue(titleId.c_str(), allocator).Move(), allocator);
if (!deviceName.empty())
{
payload.AddMember("deviceName", JsonValue(deviceName.data(), allocator).Move(), allocator);
}
JsonValue filterJson(rapidjson::kArrayType);
for (auto& notificationFilter : notificationFilterEnum)
{
JsonValue filterObj(rapidjson::kObjectType);
filterObj.AddMember("action", "Include", allocator);
filterObj.AddMember("source", notificationFilter.sourceType, allocator);
filterObj.AddMember("type", notificationFilter.type, allocator);
filterJson.PushBack(filterObj, allocator);
}
payload.AddMember("filters", filterJson, allocator);
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_contextSettings,
"POST",
XblHttpCall::BuildUrl("notify", "/system/notifications/endpoints"),
xbox_live_api::subscribe_to_notifications
));
RETURN_HR_IF_FAILED(httpCall->SetRequestBody(payload));
return httpCall->Perform(AsyncContext<HttpResult>{
workQueue,
[
thisWeakPtr = std::weak_ptr<NotificationService>{ shared_from_this() }
](HttpResult httpResult)
{
std::shared_ptr<NotificationService> pThis(thisWeakPtr.lock());
if (pThis == nullptr)
{
return;
}
HRESULT hr = httpResult.Hresult();
if (SUCCEEDED(hr))
{
hr = httpResult.Payload()->Result();
if (SUCCEEDED(hr))
{
const JsonValue& responseJson = httpResult.Payload()->GetResponseBodyJson();
hr = JsonUtils::ExtractJsonString(responseJson, "endpointId", pThis->m_endpointId);
// Registration has succeeded at this point
switch (pThis->m_registrationStatus)
{
case RegistrationStatus::Registering:
{
pThis->m_registrationStatus = RegistrationStatus::Registered;
pThis->m_registrationAsync.Complete(hr);
break;
}
default:
{
// No other states should be possible
assert(false);
}
}
}
else
{
// Registration failed for some reason
pThis->m_registrationStatus = RegistrationStatus::Unregistered;
pThis->m_registrationAsync.Complete(E_XBL_RUNTIME_ERROR);
}
}
}
});
}
};
}