diff --git a/include/asterisk/app.h b/include/asterisk/app.h index a998ed86d82f665bf58a09553b83ae7063192689..70cf7527091f76172da1836cb9bb9e40ec64584b 100644 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -1341,13 +1341,14 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen def /*! * \since 12 * \brief Publish a MWI state update via stasis - * \param[in] mailbox The number identifying this mailbox + * + * \param[in] mailbox The mailbox identifier string. * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) * \param[in] new_msgs The number of new messages in this mailbox * \param[in] old_msgs The number of old messages in this mailbox + * * \retval 0 Success * \retval -1 Failure - * \since 12 */ #define ast_publish_mwi_state(mailbox, context, new_msgs, old_msgs) \ ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, NULL, NULL) @@ -1355,15 +1356,16 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen def /*! * \since 12 * \brief Publish a MWI state update associated with some channel - * \param[in] mailbox The number identifying this mailbox + * + * \param[in] mailbox The mailbox identifier string. * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) * \param[in] new_msgs The number of new messages in this mailbox * \param[in] old_msgs The number of old messages in this mailbox * \param[in] channel_id A unique identifier for a channel associated with this * change in mailbox state + * * \retval 0 Success * \retval -1 Failure - * \since 12 */ #define ast_publish_mwi_state_channel(mailbox, context, new_msgs, old_msgs, channel_id) \ ast_publish_mwi_state_full(mailbox, context, new_msgs, old_msgs, channel_id, NULL) @@ -1371,23 +1373,51 @@ int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen def /*! * \since 12 * \brief Publish a MWI state update via stasis with all parameters - * \param[in] mailbox The number identifying this mailbox + * + * \param[in] mailbox The mailbox identifier string. * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) * \param[in] new_msgs The number of new messages in this mailbox * \param[in] old_msgs The number of old messages in this mailbox * \param[in] channel_id A unique identifier for a channel associated with this + * change in mailbox state * \param[in] eid The EID of the server that originally published the message + * * \retval 0 Success * \retval -1 Failure - * \since 12 */ int ast_publish_mwi_state_full( - const char *mailbox, - const char *context, - int new_msgs, - int old_msgs, - const char *channel_id, - struct ast_eid *eid); + const char *mailbox, + const char *context, + int new_msgs, + int old_msgs, + const char *channel_id, + struct ast_eid *eid); + +/*! + * \since 12.2.0 + * \brief Delete MWI state cached by stasis + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * + * \retval 0 Success + * \retval -1 Failure + */ +#define ast_delete_mwi_state(mailbox, context) \ + ast_delete_mwi_state_full(mailbox, context, NULL) + +/*! + * \since 12.2.0 + * \brief Delete MWI state cached by stasis with all parameters + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * \param[in] eid The EID of the server that originally published the message + * + * \retval 0 Success + * \retval -1 Failure + */ +int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid); /*! \addtogroup StasisTopicsAndMessages * @{ @@ -1421,6 +1451,9 @@ struct ast_mwi_blob { * \since 12 * \brief Create a \ref ast_mwi_state object * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * * \retval \ref ast_mwi_state object on success * \retval NULL on error */ diff --git a/main/app.c b/main/app.c index ce0d16cdd3d25a8e64cefab5ae5a88a874ac167f..b6c9882583f28e98094511f1bc2e1ecadfb551d7 100644 --- a/main/app.c +++ b/main/app.c @@ -2821,36 +2821,51 @@ struct ast_mwi_state *ast_mwi_create(const char *mailbox, const char *context) return mwi_state; } -int ast_publish_mwi_state_full( - const char *mailbox, - const char *context, - int new_msgs, - int old_msgs, - const char *channel_id, - struct ast_eid *eid) +/*! + * \internal + * \brief Create a MWI state snapshot message. + * \since 12.2.0 + * + * \param[in] mailbox The mailbox identifier string. + * \param[in] context The context this mailbox resides in (NULL or "" if only using mailbox) + * \param[in] new_msgs The number of new messages in this mailbox + * \param[in] old_msgs The number of old messages in this mailbox + * \param[in] channel_id A unique identifier for a channel associated with this + * change in mailbox state + * \param[in] eid The EID of the server that originally published the message + * + * \retval message on success. Use ao2_cleanup() when done with it. + * \retval NULL on error. + */ +static struct stasis_message *mwi_state_create_message( + const char *mailbox, + const char *context, + int new_msgs, + int old_msgs, + const char *channel_id, + struct ast_eid *eid) { - RAII_VAR(struct ast_mwi_state *, mwi_state, NULL, ao2_cleanup); - RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); - struct stasis_topic *mailbox_specific_topic; + struct ast_mwi_state *mwi_state; + struct stasis_message *message; mwi_state = ast_mwi_create(mailbox, context); if (!mwi_state) { - return -1; + return NULL; } mwi_state->new_msgs = new_msgs; mwi_state->old_msgs = old_msgs; if (!ast_strlen_zero(channel_id)) { - RAII_VAR(struct stasis_message *, chan_message, - stasis_cache_get(ast_channel_cache(), - ast_channel_snapshot_type(), - channel_id), - ao2_cleanup); + struct stasis_message *chan_message; + + chan_message = stasis_cache_get(ast_channel_cache(), ast_channel_snapshot_type(), + channel_id); if (chan_message) { mwi_state->snapshot = stasis_message_data(chan_message); ao2_ref(mwi_state->snapshot, +1); } + ao2_cleanup(chan_message); } if (eid) { @@ -2860,16 +2875,34 @@ int ast_publish_mwi_state_full( } /* - * As far as stasis is concerned, all MWI events are internal. + * XXX As far as stasis is concerned, all MWI events are local. * - * We may in the future want to make MWI aggregate internal/external + * We may in the future want to make MWI aggregate local/remote * message counts similar to how device state aggregates state. */ message = stasis_message_create_full(ast_mwi_state_type(), mwi_state, &ast_eid_default); + ao2_cleanup(mwi_state); + return message; +} + +int ast_publish_mwi_state_full( + const char *mailbox, + const char *context, + int new_msgs, + int old_msgs, + const char *channel_id, + struct ast_eid *eid) +{ + struct ast_mwi_state *mwi_state; + RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup); + struct stasis_topic *mailbox_specific_topic; + + message = mwi_state_create_message(mailbox, context, new_msgs, old_msgs, channel_id, eid); if (!message) { return -1; } + mwi_state = stasis_message_data(message); mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid); if (!mailbox_specific_topic) { return -1; @@ -2880,6 +2913,54 @@ int ast_publish_mwi_state_full( return 0; } +int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid) +{ + RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup); + struct stasis_message *cached_msg; + struct stasis_message *clear_msg; + struct ast_mwi_state *mwi_state; + struct stasis_topic *mailbox_specific_topic; + + msg = mwi_state_create_message(mailbox, context, 0, 0, NULL, eid); + if (!msg) { + return -1; + } + + mwi_state = stasis_message_data(msg); + + /* + * XXX As far as stasis is concerned, all MWI events are local. + * + * For now, it is assumed that there is only one entity + * maintaining the state of a particular mailbox. + * + * If we ever have multiple MWI event entities maintaining + * the same mailbox that wish to delete their cached entry + * we will need to do something about the race condition + * potential between checking the cache and removing the + * cache entry. + */ + cached_msg = stasis_cache_get_by_eid(ast_mwi_state_cache(), + ast_mwi_state_type(), mwi_state->uniqueid, &ast_eid_default); + if (!cached_msg) { + /* Nothing to clear */ + return -1; + } + ao2_cleanup(cached_msg); + + mailbox_specific_topic = ast_mwi_topic(mwi_state->uniqueid); + if (!mailbox_specific_topic) { + return -1; + } + + clear_msg = stasis_cache_clear_create(msg); + if (clear_msg) { + stasis_publish(mailbox_specific_topic, clear_msg); + } + ao2_cleanup(clear_msg); + return 0; +} + static const char *mwi_state_get_id(struct stasis_message *message) { if (ast_mwi_state_type() == stasis_message_type(message)) { diff --git a/res/res_mwi_external.c b/res/res_mwi_external.c index a7531c5cbf652b4bea485d06488f5918817ea987..c3fc0eaf405c59ece461207099a66b7a242e9ebd 100644 --- a/res/res_mwi_external.c +++ b/res/res_mwi_external.c @@ -123,13 +123,13 @@ static void mwi_observe_delete(const void *obj) { const struct ast_mwi_mailbox_object *mailbox = obj; - if (!mailbox->msgs_new && !mailbox->msgs_old) { - /* No need to post a count clearing event. */ - return; + if (mailbox->msgs_new || mailbox->msgs_old) { + /* Post a count clearing event. */ + ast_publish_mwi_state(ast_sorcery_object_get_id(mailbox), NULL, 0, 0); } - /* Post a count clearing event. */ - ast_publish_mwi_state(ast_sorcery_object_get_id(mailbox), NULL, 0, 0); + /* Post a cache remove event. */ + ast_delete_mwi_state(ast_sorcery_object_get_id(mailbox), NULL); } static const struct ast_sorcery_observer mwi_observers = {