Send delivery notifications when loading chat rooms from DB if needed.

This commit is contained in:
Ghislain MARY 2018-04-26 11:06:05 +02:00
parent 9b0d705ee0
commit 38ea7dc357
8 changed files with 159 additions and 1 deletions

View file

@ -47,6 +47,8 @@ public:
virtual void addTransientEvent (const std::shared_ptr<EventLog> &eventLog) = 0;
virtual void removeTransientEvent (const std::shared_ptr<EventLog> &eventLog) = 0;
virtual void sendDeliveryNotifications () = 0;
virtual void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) = 0;
virtual void notifyUndecryptableChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) = 0;

View file

@ -69,6 +69,7 @@ public:
void sendDeliveryErrorNotification (const std::shared_ptr<ChatMessage> &message, LinphoneReason reason);
void sendDeliveryNotification (const std::shared_ptr<ChatMessage> &message);
void sendDeliveryNotifications () override;
bool sendDisplayNotification (const std::shared_ptr<ChatMessage> &message);
void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override;

View file

@ -153,6 +153,16 @@ void ChatRoomPrivate::sendDeliveryNotification (const shared_ptr<ChatMessage> &m
imdnHandler->notifyDelivery(message);
}
void ChatRoomPrivate::sendDeliveryNotifications () {
L_Q();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore());
if (linphone_im_notif_policy_get_send_imdn_delivered(policy)) {
auto messages = q->getCore()->getPrivate()->mainDb->findChatMessagesToBeNotifiedAsDelivered(q->getChatRoomId());
for (const auto message : messages)
imdnHandler->notifyDelivery(message);
}
}
bool ChatRoomPrivate::sendDisplayNotification (const shared_ptr<ChatMessage> &message) {
L_Q();
LinphoneImNotifPolicy *policy = linphone_core_get_im_notif_policy(q->getCore()->getCCore());

View file

@ -57,6 +57,10 @@ public:
chatRoom->getPrivate()->removeTransientEvent(eventLog);
}
inline void sendDeliveryNotifications () override {
chatRoom->getPrivate()->sendDeliveryNotifications();
}
inline void notifyChatMessageReceived (const std::shared_ptr<ChatMessage> &chatMessage) override {
chatRoom->getPrivate()->notifyChatMessageReceived(chatMessage);
}

View file

@ -179,8 +179,10 @@ void CorePrivate::insertChatRoomWithDb (const shared_ptr<AbstractChatRoom> &chat
void CorePrivate::loadChatRooms () {
chatRooms.clear();
chatRoomsById.clear();
for (auto &chatRoom : mainDb->getChatRooms())
for (auto &chatRoom : mainDb->getChatRooms()) {
insertChatRoom(chatRoom);
chatRoom->getPrivate()->sendDeliveryNotifications();
}
}
void CorePrivate::replaceChatRoom (const shared_ptr<AbstractChatRoom> &replacedChatRoom, const shared_ptr<AbstractChatRoom> &newChatRoom) {

View file

@ -2148,6 +2148,43 @@ list<shared_ptr<ChatMessage>> MainDb::findChatMessages (
};
}
list<shared_ptr<ChatMessage>> MainDb::findChatMessagesToBeNotifiedAsDelivered (
const ChatRoomId &chatRoomId
) const {
static const string query = Statements::get(Statements::SelectConferenceEvents) +
string(" AND direction = :direction AND state = :state AND delivery_notification_required <> 0");
DurationLogger durationLogger(
"Find chat messages to be notified as delivered: (peer=" + chatRoomId.getPeerAddress().asString() +
", local=" + chatRoomId.getLocalAddress().asString() + ")."
);
return L_DB_TRANSACTION {
L_D();
shared_ptr<AbstractChatRoom> chatRoom = d->findChatRoom(chatRoomId);
list<shared_ptr<ChatMessage>> chatMessages;
if (!chatRoom)
return chatMessages;
const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId);
const int &state = int(ChatMessage::State::Delivered);
const int &direction = int(ChatMessage::Direction::Incoming);
soci::rowset<soci::row> rows = (
d->dbSession.getBackendSession()->prepare << query, soci::use(dbChatRoomId), soci::use(direction), soci::use(state)
);
for (const auto &row : rows) {
shared_ptr<EventLog> event = d->selectGenericConferenceEvent(chatRoom, row);
if (event) {
L_ASSERT(event->getType() == EventLog::Type::ConferenceChatMessage);
chatMessages.push_back(static_pointer_cast<ConferenceChatMessageEvent>(event)->getChatMessage());
}
}
return chatMessages;
};
}
list<shared_ptr<EventLog>> MainDb::getHistory (const ChatRoomId &chatRoomId, int nLast, FilterMask mask) const {
return getHistoryRange(chatRoomId, 0, nLast, mask);
}

View file

@ -130,6 +130,10 @@ public:
const std::string &imdnMessageId
) const;
std::list<std::shared_ptr<ChatMessage>> findChatMessagesToBeNotifiedAsDelivered (
const ChatRoomId &chatRoomId
) const;
// ---------------------------------------------------------------------------
// Conference events.
// ---------------------------------------------------------------------------

View file

@ -3235,6 +3235,103 @@ static void aggregated_imdn_for_group_chat_room_read_while_offline (void) {
aggregated_imdn_for_group_chat_room_base(TRUE);
}
static void imdn_sent_from_db_state (void) {
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
LinphoneCoreManager *chloe = linphone_core_manager_create("chloe_rc");
bctbx_list_t *coresManagerList = NULL;
bctbx_list_t *participantsAddresses = NULL;
coresManagerList = bctbx_list_append(coresManagerList, marie);
coresManagerList = bctbx_list_append(coresManagerList, pauline);
coresManagerList = bctbx_list_append(coresManagerList, chloe);
bctbx_list_t *coresList = init_core_for_conference(coresManagerList);
start_core_for_conference(coresManagerList);
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(pauline->lc)));
participantsAddresses = bctbx_list_append(participantsAddresses, linphone_address_new(linphone_core_get_identity(chloe->lc)));
stats initialMarieStats = marie->stat;
stats initialPaulineStats = pauline->stat;
stats initialChloeStats = chloe->stat;
time_t initialTime = ms_time(NULL);
// Enable IMDN except for Marie
linphone_im_notif_policy_clear(linphone_core_get_im_notif_policy(marie->lc));
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc));
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(chloe->lc));
// Marie creates a new group chat room
const char *initialSubject = "Colleagues";
LinphoneChatRoom *marieCr = create_chat_room_client_side(coresList, marie, &initialMarieStats, participantsAddresses, initialSubject, -1);
LinphoneAddress *confAddr = linphone_address_clone(linphone_chat_room_get_conference_address(marieCr));
// Check that the chat room is correctly created on Pauline's side and that the participants are added
LinphoneChatRoom *paulineCr = check_creation_chat_room_client_side(coresList, pauline, &initialPaulineStats, confAddr, initialSubject, 2, FALSE);
// Check that the chat room is correctly created on Chloe's side and that the participants are added
LinphoneChatRoom *chloeCr = check_creation_chat_room_client_side(coresList, chloe, &initialChloeStats, confAddr, initialSubject, 2, FALSE);
// Chloe begins composing a message
const char *chloeTextMessage = "Hello";
LinphoneChatMessage *chloeMessage = _send_message(chloeCr, chloeTextMessage);
BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageReceived, initialMarieStats.number_of_LinphoneMessageReceived + 1, 3000));
BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, initialPaulineStats.number_of_LinphoneMessageReceived + 1, 3000));
LinphoneChatMessage *marieLastMsg = marie->stat.last_received_chat_message;
if (!BC_ASSERT_PTR_NOT_NULL(marieLastMsg))
goto end;
BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(marieLastMsg), chloeTextMessage);
LinphoneAddress *chloeAddr = linphone_address_new(linphone_core_get_identity(chloe->lc));
BC_ASSERT_TRUE(linphone_address_weak_equal(chloeAddr, linphone_chat_message_get_from_address(marieLastMsg)));
linphone_address_unref(chloeAddr);
// Check that the message is not globally marked as delivered to user since Marie do not notify its delivery
BC_ASSERT_FALSE(wait_for_list(coresList, &chloe->stat.number_of_LinphoneMessageDeliveredToUser, initialChloeStats.number_of_LinphoneMessageDeliveredToUser + 1, 3000));
// Restart Marie's core with IMDN enabled so that delivery notification is sent when chat room is loaded from DB
coresList = bctbx_list_remove(coresList, marie->lc);
linphone_core_manager_reinit(marie);
bctbx_list_t *tmpCoresManagerList = bctbx_list_append(NULL, marie);
bctbx_list_t *tmpCoresList = init_core_for_conference(tmpCoresManagerList);
bctbx_list_free(tmpCoresManagerList);
coresList = bctbx_list_concat(coresList, tmpCoresList);
linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc));
linphone_core_manager_start(marie, TRUE);
char *marieIdentity = linphone_core_get_device_identity(marie->lc);
LinphoneAddress *marieAddr = linphone_address_new(marieIdentity);
bctbx_free(marieIdentity);
marieCr = linphone_core_find_chat_room(marie->lc, confAddr, marieAddr);
linphone_address_unref(marieAddr);
linphone_address_unref(confAddr);
// Check that the message has been delivered to Marie and Pauline
BC_ASSERT_TRUE(wait_for_list(coresList, &chloe->stat.number_of_LinphoneMessageDeliveredToUser, initialChloeStats.number_of_LinphoneMessageDeliveredToUser + 1, 3000));
BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_that_have_displayed(chloeMessage));
bctbx_list_t *participantsThatReceivedChloeMessage = linphone_chat_message_get_participants_that_have_received(chloeMessage);
if (BC_ASSERT_PTR_NOT_NULL(participantsThatReceivedChloeMessage)) {
BC_ASSERT_EQUAL((int)bctbx_list_size(participantsThatReceivedChloeMessage), 2, int, "%d");
for (bctbx_list_t *item = participantsThatReceivedChloeMessage; item; item = bctbx_list_next(item)) {
LinphoneParticipantImdnState *state = (LinphoneParticipantImdnState *)bctbx_list_get_data(item);
BC_ASSERT_GREATER(linphone_participant_imdn_state_get_state_change_time(state), initialTime, int, "%d");
BC_ASSERT_EQUAL(linphone_participant_imdn_state_get_state(state), LinphoneChatMessageStateDeliveredToUser, int, "%d");
BC_ASSERT_PTR_NOT_NULL(linphone_participant_imdn_state_get_participant(state));
}
bctbx_list_free_with_data(participantsThatReceivedChloeMessage, (bctbx_list_free_func)linphone_participant_imdn_state_unref);
}
BC_ASSERT_PTR_NULL(linphone_chat_message_get_participants_that_have_not_received(chloeMessage));
linphone_chat_message_unref(chloeMessage);
end:
// Clean db from chat room
linphone_core_manager_delete_chat_room(marie, marieCr, coresList);
linphone_core_manager_delete_chat_room(chloe, chloeCr, coresList);
linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList);
bctbx_list_free(coresList);
bctbx_list_free(coresManagerList);
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(chloe);
}
static void find_one_to_one_chat_room (void) {
LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc");
LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc");
@ -3423,6 +3520,7 @@ test_t group_chat_tests[] = {
TEST_NO_TAG("IMDN for group chat room", imdn_for_group_chat_room),
TEST_NO_TAG("Aggregated IMDN for group chat room", aggregated_imdn_for_group_chat_room),
TEST_NO_TAG("Aggregated IMDN for group chat room read while offline", aggregated_imdn_for_group_chat_room_read_while_offline),
TEST_ONE_TAG("IMDN sent from DB state", imdn_sent_from_db_state, "LeaksMemory"),
TEST_NO_TAG("Find one to one chat room", find_one_to_one_chat_room),
TEST_NO_TAG("New device after group chat room creation", group_chat_room_new_device_after_creation)
};