Webhooks: trigger callbacks for recording events too

This commit is contained in:
Leonardo Crauss Daronco 2014-11-14 16:53:46 -02:00
parent 81f5a109b6
commit 7efb3a18ab
6 changed files with 47 additions and 12 deletions

View File

@ -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
-----------

View File

@ -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

View File

@ -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

View File

@ -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: ->

View File

@ -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

View File

@ -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