From 7efb3a18ab7bb865a3b2a16dec65ad5390d2746d Mon Sep 17 00:00:00 2001 From: Leonardo Crauss Daronco Date: Fri, 14 Nov 2014 16:53:46 -0200 Subject: [PATCH] Webhooks: trigger callbacks for recording events too --- labs/bbb-callback/README.md | 2 +- labs/bbb-callback/config.coffee | 18 ++++++++++++++++-- labs/bbb-callback/config_local.coffee.example | 18 ++++++++++++++++-- labs/bbb-callback/hook.coffee | 6 +++++- labs/bbb-callback/web_hooks.coffee | 12 +++++++++--- labs/bbb-callback/web_server.coffee | 3 --- 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/labs/bbb-callback/README.md b/labs/bbb-callback/README.md index 46a4a3586a..1dc8e902a0 100644 --- a/labs/bbb-callback/README.md +++ b/labs/bbb-callback/README.md @@ -227,9 +227,9 @@ More details * Callbacks are always triggered for one event at a time and in order. They are ordered the same way they appear on pubsub (which might not exactly be the order indicated by their timestamps). The timestamps will almost always be ordered as well, but it's not guaranteed. * The application assumes that events are never duplicated on pubsub. If they happen to be duplicated, the callback calls will also be duplicated. * Hooks are only removed if a call to `/destroy` is made or if the callbacks for the hook fail too many times (~12) for a long period of time (~5min). They are never removed otherwise. Valid for both global hooks and hooks for specific meetings. -* If a meeting is created while the webhooks app is down, callbacks will never be triggered for this meeting. The app needs to detect the create event (`meeting_created_message`) to have a mapping of internal to external meeting IDs. * Mappings are removed after 24 hours of inactivity. If there are no events at all for a given meeting, it will be assumed dead. This is done to prevent data from being stored forever on redis. * External URLs are expected to respond with the HTTP status 200, 201 or 202. Anything different from these values will be considered an error and the callback will be called again. This includes URLs that redirect to some other place. +* If a meeting is created while the webhooks app is down, callbacks will never be triggered for this meeting. The app needs to detect the create event (`meeting_created_message`) to have a mapping of internal to external meeting IDs. Development ----------- diff --git a/labs/bbb-callback/config.coffee b/labs/bbb-callback/config.coffee index 40e0c455d2..74776f4e39 100644 --- a/labs/bbb-callback/config.coffee +++ b/labs/bbb-callback/config.coffee @@ -22,7 +22,21 @@ config.hooks.events or= [ { channel: "bigbluebutton:from-bbb-apps:meeting", name: "meeting_created_message" }, { channel: "bigbluebutton:from-bbb-apps:meeting", name: "meeting_destroyed_event" }, { channel: "bigbluebutton:from-bbb-apps:users", name: "user_joined_message" }, - { channel: "bigbluebutton:from-bbb-apps:users", name: "user_left_message" } + { channel: "bigbluebutton:from-bbb-apps:users", name: "user_left_message" }, + { channel: "bigbluebutton:from-rap", name: "sanity_started" }, + { channel: "bigbluebutton:from-rap", name: "sanity_ended" }, + { channel: "bigbluebutton:from-rap", name: "archive_started" }, + { channel: "bigbluebutton:from-rap", name: "archive_ended" }, + { channel: "bigbluebutton:from-rap", name: "post_archive_started" }, + { channel: "bigbluebutton:from-rap", name: "post_archive_ended" }, + { channel: "bigbluebutton:from-rap", name: "process_started" }, + { channel: "bigbluebutton:from-rap", name: "process_ended" }, + { channel: "bigbluebutton:from-rap", name: "post_process_started" }, + { channel: "bigbluebutton:from-rap", name: "post_process_ended" }, + { channel: "bigbluebutton:from-rap", name: "publish_started" }, + { channel: "bigbluebutton:from-rap", name: "publish_ended" }, + { channel: "bigbluebutton:from-rap", name: "post_publish_started" }, + { channel: "bigbluebutton:from-rap", name: "post_publish_ended" } ] # Retry intervals for failed attempts for perform callback calls. @@ -33,7 +47,7 @@ config.hooks.retryIntervals = [ # Mappings of internal to external meeting IDs config.mappings = {} -config.mappings.cleanupInterval = 1000 # in ms +config.mappings.cleanupInterval = 10000 # 10 secs, in ms config.mappings.timeout = 1000*60*60*24 # 24 hours, in ms # Redis diff --git a/labs/bbb-callback/config_local.coffee.example b/labs/bbb-callback/config_local.coffee.example index ec30a418bb..af67af1146 100644 --- a/labs/bbb-callback/config_local.coffee.example +++ b/labs/bbb-callback/config_local.coffee.example @@ -12,11 +12,25 @@ config.server.port = 3005 # Callbacks will be triggered for all the events in this list and only for these events. config.hooks = {} -config.hooks.events or= [ +config.hooks.events = [ { channel: "bigbluebutton:from-bbb-apps:meeting", name: "meeting_created_message" }, { channel: "bigbluebutton:from-bbb-apps:meeting", name: "meeting_destroyed_event" }, { channel: "bigbluebutton:from-bbb-apps:users", name: "user_joined_message" }, - { channel: "bigbluebutton:from-bbb-apps:users", name: "user_left_message" } + { channel: "bigbluebutton:from-bbb-apps:users", name: "user_left_message" }, + { channel: "bigbluebutton:from-rap", name: "sanity_started" }, + { channel: "bigbluebutton:from-rap", name: "sanity_ended" }, + { channel: "bigbluebutton:from-rap", name: "archive_started" }, + { channel: "bigbluebutton:from-rap", name: "archive_ended" }, + { channel: "bigbluebutton:from-rap", name: "post_archive_started" }, + { channel: "bigbluebutton:from-rap", name: "post_archive_ended" }, + { channel: "bigbluebutton:from-rap", name: "process_started" }, + { channel: "bigbluebutton:from-rap", name: "process_ended" }, + { channel: "bigbluebutton:from-rap", name: "post_process_started" }, + { channel: "bigbluebutton:from-rap", name: "post_process_ended" }, + { channel: "bigbluebutton:from-rap", name: "publish_started" }, + { channel: "bigbluebutton:from-rap", name: "publish_ended" }, + { channel: "bigbluebutton:from-rap", name: "post_publish_started" }, + { channel: "bigbluebutton:from-rap", name: "post_publish_ended" } ] module.exports = config diff --git a/labs/bbb-callback/hook.coffee b/labs/bbb-callback/hook.coffee index 8b2f6fe85f..8fd236ee26 100644 --- a/labs/bbb-callback/hook.coffee +++ b/labs/bbb-callback/hook.coffee @@ -23,7 +23,11 @@ nextID = 1 # Hooks can be global, receiving callback calls for events from all meetings on the # server, or for a specific meeting. If an `externalMeetingID` is set in the hook, # it will only receive calls related to this meeting, otherwise it will be global. -# TODO: at some point the queue needs to be cleared, or we need a size limit on it +# Events are kept in a queue to be sent in the order they are received. +# TODO: The queue should be cleared at some point. The hook is destroyed if too many +# callback attempts fail, after ~5min. So the queue is already protected in this case. +# But if the requests are going by but taking too long, the queue might be increasing +# faster than the callbacks are made. module.exports = class Hook constructor: -> diff --git a/labs/bbb-callback/web_hooks.coffee b/labs/bbb-callback/web_hooks.coffee index 2923f8f195..c0ee6c4e84 100644 --- a/labs/bbb-callback/web_hooks.coffee +++ b/labs/bbb-callback/web_hooks.coffee @@ -57,6 +57,8 @@ module.exports = class WebHooks _processEvent: (message) -> hooks = Hook.allGlobalSync() + # TODO: events that happen after the meeting ended will never trigger the hooks + # below, since the mapping is removed when the meeting ends # filter the hooks that need to receive this event # only global hooks or hooks for this specific meeting idFromMessage = message.payload?.meeting_id @@ -75,13 +77,17 @@ module.exports = class WebHooks Logger.info "WebHooks: subscribed to meetings channel ", channel @subscriberMeetings.on "message", (channel, message) => - Logger.info "WebHooks: got message on meetings channel [#{channel}]", message try message = JSON.parse(message) if message.header?.name is "meeting_created_message" + Logger.info "WebHooks: got create message on meetings channel [#{channel}]", message IDMapping.addOrUpdateMapping(message.payload?.meeting_id, message.payload?.external_meeting_id) - else if message.header?.name is "meeting_destroyed_event" - IDMapping.removeMapping(message.payload?.meeting_id) + + # TODO: Temporarily commented because we still need the mapping for recording events, + # after the meeting ended. + # else if message.header?.name is "meeting_destroyed_event" + # Logger.info "WebHooks: got destroy message on meetings channel [#{channel}]", message + # IDMapping.removeMapping(message.payload?.meeting_id) catch e Logger.error.log "WebHooks: error processing the message", JSON.stringify(message), ":", e diff --git a/labs/bbb-callback/web_server.coffee b/labs/bbb-callback/web_server.coffee index 6164f4ecad..0cb8d8600b 100644 --- a/labs/bbb-callback/web_server.coffee +++ b/labs/bbb-callback/web_server.coffee @@ -41,9 +41,6 @@ module.exports = class WebServer callbackURL = urlObj.query["callbackURL"] meetingID = urlObj.query["meetingID"] - # TODO: if meetingID is set in the url, check if the meeting exists, otherwise - # invalid("invalidMeetingIdentifier", "The meeting ID that you supplied did not match any existing meetings"); - unless callbackURL? respondWithXML(res, config.api.responses.missingParamCallbackURL) else