HRESULT NotificationService::RegisterForNotificationsHelper()

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