Adding Social Manager Rich Presence Polling and fixed lock issues

This commit is contained in:
Blake Gross 2017-01-03 16:46:27 -08:00 коммит произвёл GitHub
Родитель 08dd6e8cc7
Коммит a1c5904f71
11 изменённых файлов: 379 добавлений и 72 удалений

Просмотреть файл

@ -227,7 +227,7 @@
<ClInclude Include="..\..\Tests\UnitTests\Tests\Services\SocialManagerHelper.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Casablanca\Release\src\build\vs14\casablanca140.static.vcxproj">
<ProjectReference Include="..\..\External\cpprestsdk\Release\src\build\vs14\casablanca140.static.vcxproj">
<Project>{04d42f35-e5d5-4d95-980e-1bd7e900f2dd}</Project>
</ProjectReference>
</ItemGroup>

Просмотреть файл

@ -369,7 +369,7 @@ public:
/// <summary>
/// Internal function
/// </summary>
bool _Compare(_In_ const social_manager_presence_record& presenceRecord);
bool _Compare(_In_ const social_manager_presence_record& presenceRecord) const;
/// <summary>
/// Internal function
@ -867,6 +867,17 @@ public:
_In_ const std::shared_ptr<xbox_social_user_group>& group,
_In_ const std::vector<string_t>& users
);
/// <summary>
/// Whether to enable social manager to poll every 30 seconds from the presence service
/// </summary>
/// <param name="user">Xbox Live User</param>
/// <param name="shouldEnablePolling">Whether or not polling should enabled</param>
/// <returns>An xbox_live_result representing the success enabling polling</returns>
_XSAPIIMP xbox_live_result<void> set_rich_presence_polling_status(
_In_ xbox_live_user_t user,
_In_ bool shouldEnablePolling
);
/// <summary>
/// Internal function

Просмотреть файл

@ -160,6 +160,19 @@ void SocialManager::UpdateSocialUserGroup(
THROW_IF_ERR(result);
}
void SocialManager::SetRichPresencePollingState(
_In_ XboxLiveUser_t user,
_In_ bool shouldEnablePolling
)
{
THROW_INVALIDARGUMENT_IF_NULL(user);
auto result = m_cppObj->set_rich_presence_polling_status(
user_context::user_convert(user),
shouldEnablePolling
);
THROW_IF_ERR(result);
}
void SocialManager::LogState()
{

Просмотреть файл

@ -107,6 +107,17 @@ public:
_In_ Windows::Foundation::Collections::IVectorView<Platform::String^>^ users
);
/// <summary>
/// Whether to enable social manager to poll every 30 seconds from the presence service
/// </summary>
/// <param name="user">Xbox Live User</param>
/// <param name="shouldEnablePolling">Whether or not polling should enabled</param>
/// <returns>An xbox_live_result representing the success enabling polling</returns>
void SetRichPresencePollingState(
_In_ XboxLiveUser_t user,
_In_ bool shouldEnablePolling
);
internal:
SocialManager();
std::shared_ptr<xbox::services::social::manager::social_manager> GetCppObj() const;

Просмотреть файл

@ -53,7 +53,9 @@ social_graph::social_graph(
m_perfTester(_T("social_graph")),
m_wasDisconnected(false),
m_numEventsThisFrame(0),
m_userAddedContext(0)
m_userAddedContext(0),
m_shouldCancel(utility::details::make_unique<bool>(false)),
m_isPollingRichPresence(false)
{
m_xboxLiveContextImpl->user_context()->set_caller_context_type(caller_context_type::social_manager);
m_xboxLiveContextImpl->init();
@ -70,8 +72,9 @@ social_graph::~social_graph()
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
m_perfTester.start_timer(_T("~social_graph"));
m_xboxLiveContextImpl->real_time_activity_service()->deactivate();
m_perfTester.start_timer(_T("~social_graph"));
try
{
if (m_graphDestructionCompleteCallback != nullptr)
@ -86,7 +89,6 @@ social_graph::~social_graph()
LOG_DEBUG("social_graph destroyed");
m_perfTester.stop_timer(_T("~social_graph"));
}
@ -108,6 +110,18 @@ social_graph::initialize()
}
});
m_presencePollingTimer = std::make_shared<rta_trigger_timer>(
[thisWeakPtr](std::vector<string_t> eventArgs, const fire_timer_completion_context&)
{
std::shared_ptr<social_graph> pThis(thisWeakPtr.lock());
if (pThis)
{
pThis->presence_timer_callback(
eventArgs
);
}
});
m_socialGraphRefreshTimer = std::make_shared<rta_trigger_timer>(
[thisWeakPtr](std::vector<string_t> eventArgs, const fire_timer_completion_context& completionContext)
{
@ -142,22 +156,30 @@ social_graph::initialize()
pThis->social_graph_refresh_callback();
}
});
pplx::create_task([thisWeakPtr]()
{
try
{
static const std::chrono::milliseconds sleepTime(30);
while (true)
{
std::shared_ptr<social_graph> pThis(thisWeakPtr.lock());
if (pThis)
bool hasRemainingEvent = false;
{
pThis->do_event_work();
std::shared_ptr<social_graph> pThis(thisWeakPtr.lock());
if (pThis)
{
hasRemainingEvent = pThis->do_event_work();
}
else
{
LOG_DEBUG("exiting event processing loop");
return;
}
}
else
if (!hasRemainingEvent)
{
LOG_DEBUG("exiting event processing loop");
return;
std::this_thread::sleep_for(sleepTime);
}
}
}
@ -245,57 +267,56 @@ social_graph::active_buffer_social_graph()
return &m_userBuffer.active_buffer()->socialUserGraph;
}
void
bool
social_graph::do_event_work()
{
static const std::chrono::milliseconds sleepTime(30);
bool hasRemainingEvent = false;
bool hasCachedEvents = false;
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
set_state(social_graph_state::event_processing);
std::lock_guard<std::recursive_mutex> socialGraphStateLock(m_socialGraphStateMutex);
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
set_state(social_graph_state::event_processing);
m_perfTester.start_timer(_T("do_event_work: event_processing"));
m_perfTester.start_timer(_T("do_event_work: has_cached_events"));
hasCachedEvents = m_isInitialized && m_userBuffer.inactive_buffer() && !m_userBuffer.inactive_buffer()->socialUserEventQueue.empty(true);
m_perfTester.stop_timer(_T("do_event_work: has_cached_events"));
m_perfTester.start_timer(_T("do_event_work: event_processing"));
m_perfTester.start_timer(_T("do_event_work: has_cached_events"));
hasCachedEvents = m_isInitialized && m_userBuffer.inactive_buffer() && !m_userBuffer.inactive_buffer()->socialUserEventQueue.empty(true);
m_perfTester.stop_timer(_T("do_event_work: has_cached_events"));
if (hasCachedEvents)
{
m_perfTester.start_timer(_T("do_event_work: set_state"));
LOG_INFO("set state: event_processing");
m_perfTester.stop_timer(_T("do_event_work: set_state"));
}
m_perfTester.stop_timer(_T("do_event_work: event_processing"));
}
if (hasCachedEvents)
{
m_perfTester.start_timer(_T("do_event_work: set_state"));
LOG_INFO("set state: event_processing");
m_perfTester.stop_timer(_T("do_event_work: set_state"));
process_cached_events();
hasRemainingEvent = true;
}
m_perfTester.stop_timer(_T("do_event_work: event_processing"));
}
if (hasCachedEvents)
{
process_cached_events();
hasRemainingEvent = true;
}
else if(m_isInitialized)
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
m_perfTester.start_timer(_T("do_event_work: process_events"));
set_state(social_graph_state::normal);
hasRemainingEvent = process_events(); //effectively a coroutine here so that each event yields when it is done processing
m_perfTester.stop_timer(_T("do_event_work: process_events"));
}
else
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
else if (m_isInitialized)
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
m_perfTester.start_timer(_T("do_event_work: process_events"));
set_state(social_graph_state::normal);
hasRemainingEvent = process_events(); //effectively a coroutine here so that each event yields when it is done processing
m_perfTester.stop_timer(_T("do_event_work: process_events"));
}
else
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
m_perfTester.start_timer(_T("set_state: normal"));
set_state(social_graph_state::normal);
m_perfTester.stop_timer(_T("set_state: normal"));
m_perfTester.start_timer(_T("set_state: normal"));
set_state(social_graph_state::normal);
m_perfTester.stop_timer(_T("set_state: normal"));
}
}
if (!hasRemainingEvent)
{
std::this_thread::sleep_for(sleepTime);
}
return hasRemainingEvent;
}
void social_graph::initialize_social_buffers(
@ -686,7 +707,7 @@ void social_graph::apply_presence_changed_event(
}
}
if (isFreshEvent)
if (isFreshEvent && !userAddedVec.empty())
{
internal_social_event internalPresenceChangedEvent(internal_social_event_type::presence_changed, userAddedVec);
m_socialEventQueue.push(internalPresenceChangedEvent, m_user, social_event_type::presence_changed);
@ -926,6 +947,7 @@ social_graph::refresh_graph()
{
std::vector<uint64_t> userRefreshList;
{
std::lock_guard<std::recursive_mutex> socialGraphStateLock(m_socialGraphStateMutex);
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
@ -993,6 +1015,7 @@ social_graph::perform_diff(
_In_ const xsapi_internal_unordered_map(uint64_t, xbox_social_user)& xboxSocialUsers
)
{
std::lock_guard<std::recursive_mutex> socialGraphStateLock(m_socialGraphStateMutex);
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
@ -1341,8 +1364,8 @@ social_graph::presence_timer_callback(
{
return;
}
std::weak_ptr<social_graph> thisWeakPtr = shared_from_this();
m_xboxLiveContextImpl->presence_service().get_presence_for_multiple_users(
users,
std::vector<presence_device_type>(),
@ -1358,6 +1381,15 @@ social_graph::presence_timer_callback(
{
if (!presenceRecordsResult.err())
{
std::lock_guard<std::recursive_mutex> socialGraphStateLock(pThis->m_socialGraphStateMutex);
{
std::lock_guard<std::recursive_mutex> lock(pThis->m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(pThis->m_socialGraphPriorityMutex);
pThis->m_perfTester.start_timer(_T("social graph refresh state set"));
pThis->set_state(social_graph_state::refresh);
pThis->m_perfTester.start_timer(_T("social graph refresh state set"));
}
auto presenceRecordReturnVec = presenceRecordsResult.payload();
xsapi_internal_vector(social_manager_presence_record) socialManagerPresenceVec;
socialManagerPresenceVec.reserve(presenceRecordReturnVec.size());
@ -1366,10 +1398,38 @@ social_graph::presence_timer_callback(
socialManagerPresenceVec.push_back(social_manager_presence_record(presenceRecord));
}
std::vector<social_manager_presence_record> presenceRecordChanges;
for (auto& record : socialManagerPresenceVec)
{
auto previousRecordIter = pThis->m_userBuffer.inactive_buffer()->socialUserGraph.find(record._Xbox_user_id());
if (previousRecordIter == pThis->m_userBuffer.inactive_buffer()->socialUserGraph.end())
{
continue;
}
if (previousRecordIter->second.socialUser == nullptr)
{
continue;
}
auto& previousRecord = previousRecordIter->second.socialUser->presence_record();
if (previousRecord._Compare(record))
{
presenceRecordChanges.push_back(record);
}
}
pThis->m_internalEventQueue.push(
internal_social_event_type::presence_changed,
socialManagerPresenceVec
);
{
std::lock_guard<std::recursive_mutex> lock(pThis->m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(pThis->m_socialGraphPriorityMutex);
pThis->m_perfTester.start_timer(_T("social graph refresh state set normal"));
pThis->set_state(social_graph_state::normal);
pThis->m_perfTester.stop_timer(_T("social graph refresh state set normal"));
}
}
else
{
@ -1379,7 +1439,6 @@ social_graph::presence_timer_callback(
});
}
bool
social_graph::are_events_empty()
{
@ -1408,6 +1467,93 @@ social_graph::remove_users(
m_internalEventQueue.push(internal_social_event_type::users_removed, utils::std_vector_to_xsapi_vector(users));
}
void
social_graph::presence_refresh_callback()
{
std::vector<string_t> userList;
{
std::lock_guard<std::recursive_mutex> socialGraphStateLock(m_socialGraphStateMutex);
if (m_userBuffer.inactive_buffer() != nullptr)
{
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
m_perfTester.start_timer(_T("presence refresh state set"));
set_state(social_graph_state::refresh);
m_perfTester.stop_timer(_T("presence refresh state set"));
}
userList.reserve(m_userBuffer.inactive_buffer()->socialUserGraph.size());
for (auto& user : m_userBuffer.inactive_buffer()->socialUserGraph)
{
if (user.second.socialUser != nullptr)
{
userList.push_back(user.second.socialUser->xbox_user_id());
}
}
m_presencePollingTimer->fire(userList);
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
m_perfTester.start_timer(_T("presence refresh fire"));
set_state(social_graph_state::normal);
m_perfTester.stop_timer(_T("presence refresh fire"));
}
}
}
std::weak_ptr<social_graph> thisWeakPtr = shared_from_this();
create_delayed_task(
rta_trigger_timer::TIME_PER_CALL_MS,
[thisWeakPtr]()
{
std::shared_ptr<social_graph> pThis(thisWeakPtr.lock());
if (pThis)
{
{
std::lock_guard<std::recursive_mutex> socialGraphStateLock(pThis->m_socialGraphStateMutex);
if (*pThis->m_shouldCancel)
{
return;
}
}
pThis->presence_refresh_callback();
}
});
}
void
social_graph::enable_rich_presence_polling(
_In_ bool shouldEnablePolling
)
{
bool isPollingRichPresence;
{
std::lock_guard<std::recursive_mutex> lock(m_socialGraphMutex);
std::lock_guard<std::recursive_mutex> priorityLock(m_socialGraphPriorityMutex);
isPollingRichPresence = m_isPollingRichPresence;
m_isPollingRichPresence = shouldEnablePolling;
}
if (shouldEnablePolling && !isPollingRichPresence)
{
{
std::lock_guard<std::recursive_mutex> socialGraphStateLock(m_socialGraphStateMutex);
*m_shouldCancel = false;
}
presence_refresh_callback();
}
else if(!shouldEnablePolling)
{
std::lock_guard<std::recursive_mutex> socialGraphStateLock(m_socialGraphStateMutex);
*m_shouldCancel = true;
}
}
void social_graph::clear_debug_counters()
{
}
@ -1439,22 +1585,39 @@ rta_trigger_timer::fire(
_In_ const fire_timer_completion_context& usersAddedStruct
)
{
std::lock_guard<std::mutex> lock(m_timerLock);
if (xboxUserIds.empty())
{
return;
}
std::lock_guard<std::mutex> lock(m_timerLock.get());
if (m_usersToCall.capacity() < m_usersToCall.size() + xboxUserIds.size())
{
m_usersToCall.reserve((m_usersToCall.size() + xboxUserIds.size()) - m_usersToCall.capacity());
}
for (auto& xboxUserId : xboxUserIds)
{
if (std::find(m_usersToCall.begin(), m_usersToCall.end(), xboxUserId) == m_usersToCall.end())
if (m_usersToCallMap.find(xboxUserId) == m_usersToCallMap.end())
{
m_usersToCall.push_back(xboxUserId);
m_usersToCallMap[xboxUserId] = true;
}
}
fire_helper(usersAddedStruct);
std::weak_ptr<rta_trigger_timer> thisWeak = shared_from_this();
pplx::create_task([thisWeak, usersAddedStruct]()
{
std::shared_ptr<rta_trigger_timer> pThis(thisWeak.lock());
if (pThis == nullptr)
{
return;
}
std::lock_guard<std::mutex> lock(pThis->m_timerLock);
pThis->fire_helper(usersAddedStruct);
});
}
void
@ -1466,8 +1629,7 @@ rta_trigger_timer::fire_helper(
{
std::chrono::milliseconds timeDiff = TIME_PER_CALL_MS - std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_previousTime);
std::chrono::milliseconds timeRemaining = std::max<std::chrono::milliseconds>(std::chrono::milliseconds::zero(), timeDiff);
auto usersToCall = m_usersToCall;
m_usersToCall.clear();
auto& usersToCall = m_usersToCall;
std::weak_ptr<rta_trigger_timer> thisWeakPtr = shared_from_this();
m_isTaskInProgress = true;
@ -1479,7 +1641,7 @@ rta_trigger_timer::fire_helper(
std::shared_ptr<rta_trigger_timer> pThis(thisWeakPtr.lock());
if (pThis != nullptr)
{
std::lock_guard<std::mutex> lock(pThis->m_timerLock.get());
std::lock_guard<std::mutex> lock(pThis->m_timerLock);
pThis->m_isTaskInProgress = false;
pThis->m_fCallback(usersToCall, usersAddedStruct);
@ -1490,6 +1652,9 @@ rta_trigger_timer::fire_helper(
}
}
});
m_usersToCall.clear();
m_usersToCallMap.clear();
}
else
{

Просмотреть файл

@ -365,8 +365,8 @@ social_manager::remove_local_user(
std::lock_guard<std::mutex> lock(m_socialMangerLock);
auto xboxUserId = user_context::get_user_id(user);
if (m_localGraphs.find(xboxUserId) == m_localGraphs.end())
auto graphIter = m_localGraphs.find(xboxUserId);
if (graphIter == m_localGraphs.end())
{
return xbox_live_result<void>(xbox_live_error_code::logic_error, "User not found in graph");
}
@ -497,6 +497,23 @@ xbox_live_result<void> social_manager::update_social_user_group(
return xbox_live_result<void>();
}
xbox_live_result<void>
social_manager::set_rich_presence_polling_status(
_In_ xbox_live_user_t user,
_In_ bool shouldEnablePolling
)
{
std::lock_guard<std::mutex> lock(m_socialMangerLock);
auto localGraphIter = m_localGraphs.find(user_context::get_user_id(user));
if (localGraphIter == m_localGraphs.end())
{
return xbox_live_result<void>(xbox_live_error_code::logic_error, "User not found in graph");
}
localGraphIter->second->enable_rich_presence_polling(shouldEnablePolling);
return xbox_live_result<void>();
}
void social_manager::_Log_state()
{
LOGS_DEBUG << "[SM] State: m_xboxSocialUserGroups: " << m_xboxSocialUserGroups.size()

Просмотреть файл

@ -150,8 +150,8 @@ public:
void fire();
void fire(_In_ const std::vector<string_t>& xboxUserIds, _In_ const fire_timer_completion_context& usersAddedStruct = fire_timer_completion_context());
private:
static const std::chrono::milliseconds TIME_PER_CALL_MS;
private:
void fire_helper(_In_ const fire_timer_completion_context& usersAddedStruct = fire_timer_completion_context());
@ -163,8 +163,9 @@ private:
std::chrono::time_point<std::chrono::steady_clock> m_previousTime;
#endif
std::vector<string_t> m_usersToCall;
std::unordered_map<string_t, bool> m_usersToCallMap; // duplicating data to make lookup faster. SHould be a better way to do this
std::function<void(const std::vector<string_t>&, const fire_timer_completion_context&)> m_fCallback;
xbox::services::system::xbox_live_mutex m_timerLock;
std::mutex m_timerLock;
};
struct xbox_social_user_context
@ -433,6 +434,8 @@ public:
void clear_debug_counters();
void print_debug_info();
void enable_rich_presence_polling(_In_ bool shouldEnablePolling);
const xsapi_internal_unordered_map(uint64_t, xbox_social_user_context)* active_buffer_social_graph();
@ -455,7 +458,9 @@ protected:
void social_graph_refresh_callback();
void do_event_work();
void presence_refresh_callback();
bool do_event_work();
void presence_timer_callback(
_In_ const std::vector<string_t>& users
@ -530,6 +535,7 @@ protected:
bool m_isInitialized;
bool m_wasDisconnected;
bool m_isPollingRichPresence;
//rta function contexts
function_context m_devicePresenceContext;
@ -546,8 +552,10 @@ protected:
social_graph_state m_socialGraphState;
xbox_live_user_t m_user;
std::unique_ptr<bool> m_shouldCancel;
std::shared_ptr<xbox_live_context_impl> m_xboxLiveContextImpl;
std::shared_ptr<rta_trigger_timer> m_presenceRefreshTimer;
std::shared_ptr<rta_trigger_timer> m_presencePollingTimer;
std::shared_ptr<rta_trigger_timer> m_socialGraphRefreshTimer;
std::shared_ptr<rta_trigger_timer> m_resyncRefreshTimer;
std::shared_ptr<xbox::services::social::social_relationship_change_subscription> m_socialRelationshipChangeSubscription;
@ -557,6 +565,7 @@ protected:
xsapi_internal_unordered_map(uint64_t, xbox_social_user_subscriptions) m_socialUserSubscriptions;
std::recursive_mutex m_socialGraphMutex;
std::recursive_mutex m_socialGraphPriorityMutex;
std::recursive_mutex m_socialGraphStateMutex;
xbox::services::perf_tester m_perfTester;
event_queue m_socialEventQueue;
internal_event_queue m_internalEventQueue;

Просмотреть файл

@ -136,7 +136,7 @@ social_manager_presence_record::presence_title_records() const
bool
social_manager_presence_record::_Compare(
_In_ const social_manager_presence_record& presenceRecord
)
) const
{
if (presenceRecord.m_userState != m_userState)
{

Просмотреть файл

@ -159,6 +159,11 @@ change_list_enum xbox_social_user::_Compare(
changeResult = static_cast<change_list_enum>(changeResult | change_list_enum::social_relationship_change);
}
if (previous.m_presenceRecord._Compare(current.m_presenceRecord))
{
changeResult = static_cast<change_list_enum>(changeResult | change_list_enum::presence_change);
}
return changeResult;
}

Просмотреть файл

@ -258,6 +258,10 @@ xbox_social_user_group::filter_list(
}
auto user = userPair->second.socialUser;
if (user == nullptr)
{
continue;
}
if ((m_relationshipFilter == relationship_filter::favorite && user->is_favorite()) ||
(m_relationshipFilter == relationship_filter::friends && user->is_followed_by_caller())
)

Просмотреть файл

@ -500,6 +500,7 @@ public:
{
if (evt->EventType == SocialEventType::PresenceChanged)
{
assert(evt->UsersAffected->Size != 0);
totalSize += evt->UsersAffected->Size;
++numEvents;
}
@ -543,7 +544,7 @@ public:
}
} while (shouldLoop);
Sleep(100);
VERIFY_IS_TRUE(xblContext->real_time_activity_service()->_Subscription_Count() == 0);
}
@ -1214,8 +1215,9 @@ public:
pplx::task_completion_event<void> tce;
std::unordered_map<string_t, std::shared_ptr<HttpResponseStruct>> responses;
auto presenceResponse = StockMocks::CreateMockHttpCallResponse(devicePresenceResponse);
auto devicePresenceResponseCopy = devicePresenceResponse;
devicePresenceResponseCopy[0][L"state"] = web::json::value::string(L"Offline");
auto presenceResponse = StockMocks::CreateMockHttpCallResponse(devicePresenceResponseCopy);
auto presenceResponseStruct = std::make_shared<HttpResponseStruct>();
presenceResponseStruct->responseList = { presenceResponse };
@ -1601,7 +1603,6 @@ public:
auto socialManagerInitializationStruct = Initialize(xboxLiveContext, true);
socialManagerInitializationStruct.socialManager->DoWork();
auto group = socialManagerInitializationStruct.socialManager->CreateSocialUserGroupFromFilters(
xboxLiveContext->user(),
PresenceFilter::All,
@ -1627,8 +1628,11 @@ public:
m_mockXboxSystemFactory->add_http_state_response(responses);
m_mockXboxSystemFactory->GetMockWebSocketClient()->recieve_message(rtaResyncMessage);
VERIFY_IS_TRUE(group->Users->GetAt(0)->PresenceRecord->PresenceTitleRecords->GetAt(0)->PresenceText == L"Home");
bool shouldLoop = true;
bool foundProfileChange = false;
bool foundPresenceChange = false;
do
{
auto changeList = socialManagerInitializationStruct.socialManager->DoWork();
@ -1638,9 +1642,18 @@ public:
for (auto evt : socialManagerInitializationStruct.socialEvents)
{
if (evt->EventType == SocialEventType::ProfilesChanged)
{
foundProfileChange = true;
}
else if (evt->EventType == SocialEventType::PresenceChanged)
{
foundPresenceChange = true;
VERIFY_IS_TRUE(group->Users->GetAt(0)->PresenceRecord->PresenceTitleRecords->GetAt(0)->PresenceText->IsEmpty());
}
if (foundProfileChange && foundPresenceChange)
{
shouldLoop = false;
break;
}
}
} while (shouldLoop);
@ -2502,6 +2515,65 @@ public:
Cleanup(socialManagerInitializationStruct, xboxLiveContext);
}
DEFINE_TEST_CASE(TestSocialManagerRichPresencePolling)
{
DEFINE_TEST_CASE_PROPERTIES_FOCUS(TestSocialManagerRichPresencePolling);
m_mockXboxSystemFactory->reinit();
auto xboxLiveContext = GetMockXboxLiveContext_Cpp();
auto socialManagerInitializationStruct = Initialize(xboxLiveContext, true);
auto socialUserGroupAll = socialManagerInitializationStruct.socialManager->CreateSocialUserGroupFromFilters(
xboxLiveContext->user(),
PresenceFilter::All,
RelationshipFilter::Friends
);
auto presenceJSON = GenerateInitialPresenceJSON(false);
auto presenceResponse = StockMocks::CreateMockHttpCallResponse(presenceJSON);
std::shared_ptr<HttpResponseStruct> presenceResponseStruct = std::make_shared<HttpResponseStruct>();
presenceResponseStruct->responseList = { presenceResponse };
std::unordered_map<string_t, std::shared_ptr<HttpResponseStruct>> responses;
// set up http response set
responses[_T("https://userpresence.mockenv.xboxlive.com")] = presenceResponseStruct;
m_mockXboxSystemFactory->add_http_state_response(responses);
VERIFY_IS_TRUE(socialUserGroupAll->Users->GetAt(0)->PresenceRecord->UserState == UserPresenceState::Online);
socialManagerInitializationStruct.socialManager->SetRichPresencePollingState(xboxLiveContext->user(), true);
while (true)
{
auto userCount = 0;
AppendToPendingEvents(socialManagerInitializationStruct.socialManager->DoWork(), socialManagerInitializationStruct);
for (auto evt : socialManagerInitializationStruct.socialEvents)
{
if (evt->EventType == SocialEventType::PresenceChanged)
{
userCount += evt->UsersAffected->Size;
}
}
if (userCount == USER_LIST.size())
{
break;
}
}
VERIFY_IS_TRUE(socialUserGroupAll->Users->GetAt(0)->PresenceRecord->UserState == UserPresenceState::Offline);
socialManagerInitializationStruct.socialManager->SetRichPresencePollingState(xboxLiveContext->user(), false);
presenceJSON = GenerateInitialPresenceJSON(true);
presenceResponse = StockMocks::CreateMockHttpCallResponse(presenceJSON);
presenceResponseStruct = std::make_shared<HttpResponseStruct>();
presenceResponseStruct->responseList = { presenceResponse };
// set up http response set
responses[_T("https://userpresence.mockenv.xboxlive.com")] = presenceResponseStruct;
socialManagerInitializationStruct.socialManager->DoWork();
VERIFY_IS_TRUE(socialUserGroupAll->Users->GetAt(0)->PresenceRecord->UserState == UserPresenceState::Offline);
Cleanup(socialManagerInitializationStruct, xboxLiveContext);
}
};
NAMESPACE_MICROSOFT_XBOX_SERVICES_SYSTEM_CPP_END