2014-11-11 21:58:28 +08:00
|
|
|
_ = require("lodash")
|
|
|
|
async = require("async")
|
|
|
|
redis = require("redis")
|
|
|
|
request = require("request")
|
|
|
|
|
|
|
|
config = require("./config")
|
|
|
|
Hook = require("./hook")
|
2014-11-13 22:15:20 +08:00
|
|
|
IDMapping = require("./id_mapping")
|
2014-11-15 00:12:37 +08:00
|
|
|
Logger = require("./logger")
|
2014-11-11 21:58:28 +08:00
|
|
|
|
|
|
|
# Web hooks will listen for events on redis coming from BigBlueButton and
|
|
|
|
# perform HTTP calls with them to all registered hooks.
|
|
|
|
module.exports = class WebHooks
|
|
|
|
|
|
|
|
constructor: ->
|
2017-09-08 01:27:03 +08:00
|
|
|
@subscriberEvents = config.redis.pubSubClient
|
2014-11-11 21:58:28 +08:00
|
|
|
|
|
|
|
start: ->
|
2014-11-12 02:43:41 +08:00
|
|
|
@_subscribeToEvents()
|
|
|
|
|
|
|
|
# Subscribe to the events on pubsub that might need to be sent in callback calls.
|
|
|
|
_subscribeToEvents: ->
|
2014-11-11 21:58:28 +08:00
|
|
|
@subscriberEvents.on "psubscribe", (channel, count) ->
|
2014-11-15 00:12:37 +08:00
|
|
|
Logger.info "WebHooks: subscribed to " + channel
|
2014-11-11 21:58:28 +08:00
|
|
|
|
|
|
|
@subscriberEvents.on "pmessage", (pattern, channel, message) =>
|
2014-11-25 00:34:03 +08:00
|
|
|
|
|
|
|
processMessage = =>
|
|
|
|
if @_filterMessage(channel, message)
|
|
|
|
Logger.info "WebHooks: processing message on [#{channel}]:", JSON.stringify(message)
|
|
|
|
@_processEvent(message)
|
|
|
|
|
2014-11-11 21:58:28 +08:00
|
|
|
try
|
2014-11-13 22:03:42 +08:00
|
|
|
message = JSON.parse(message)
|
|
|
|
if message?
|
2017-09-08 01:11:43 +08:00
|
|
|
id = @_findMeetingId(message)
|
2014-11-13 22:15:20 +08:00
|
|
|
IDMapping.reportActivity(id)
|
2014-11-13 22:03:42 +08:00
|
|
|
|
2014-11-25 00:34:03 +08:00
|
|
|
# First treat meeting events to add/remove ID mappings
|
2017-09-08 01:11:43 +08:00
|
|
|
if message.envelope?.name is "MeetingCreatedEvtMsg"
|
2014-11-25 00:34:03 +08:00
|
|
|
Logger.info "WebHooks: got create message on meetings channel [#{channel}]", message
|
2017-09-08 01:11:43 +08:00
|
|
|
meetingProp = message.core?.body?.props?.meetingProp
|
|
|
|
if meetingProp
|
|
|
|
IDMapping.addOrUpdateMapping meetingProp.intId, meetingProp.extId, (error, result) ->
|
|
|
|
# has to be here, after the meeting was created, otherwise create calls won't generate
|
|
|
|
# callback calls for meeting hooks
|
|
|
|
processMessage()
|
2014-11-25 00:34:03 +08:00
|
|
|
|
|
|
|
# TODO: Temporarily commented because we still need the mapping for recording events,
|
|
|
|
# after the meeting ended.
|
2017-09-08 01:11:43 +08:00
|
|
|
# else if message.envelope?.name is "MeetingEndedEvtMessage"
|
2014-11-25 00:34:03 +08:00
|
|
|
# Logger.info "WebHooks: got destroy message on meetings channel [#{channel}]", message
|
2017-09-08 01:11:43 +08:00
|
|
|
# IDMapping.removeMapping @_findMeetingId(message), (error, result) ->
|
2014-11-25 00:34:03 +08:00
|
|
|
# processMessage()
|
|
|
|
|
|
|
|
else
|
|
|
|
processMessage()
|
2014-11-11 21:58:28 +08:00
|
|
|
|
|
|
|
catch e
|
2014-11-15 00:12:37 +08:00
|
|
|
Logger.error "WebHooks: error processing the message", message, ":", e
|
2014-11-11 21:58:28 +08:00
|
|
|
|
2017-09-08 01:11:43 +08:00
|
|
|
# Subscribe to the neccesary channels.
|
|
|
|
for k, channel of config.hooks.channels
|
|
|
|
@subscriberEvents.psubscribe channel
|
2014-11-11 21:58:28 +08:00
|
|
|
|
|
|
|
# Returns whether the message read from redis should generate a callback
|
|
|
|
# call or not.
|
|
|
|
_filterMessage: (channel, message) ->
|
2017-09-08 01:11:43 +08:00
|
|
|
messageName = @_messageNameFromChannel(channel, message)
|
2014-11-11 21:58:28 +08:00
|
|
|
for event in config.hooks.events
|
2017-09-08 01:11:43 +08:00
|
|
|
if channel? and messageName? and
|
|
|
|
event.channel.match(channel) and event.name.match(messageName)
|
2014-11-11 21:58:28 +08:00
|
|
|
return true
|
2017-09-08 01:11:43 +08:00
|
|
|
false
|
|
|
|
|
|
|
|
# BigBlueButton 2.0 changed where the message name is located, but it didn't
|
|
|
|
# change for the Record and Playback events. Thus, we need to handle both.
|
|
|
|
_messageNameFromChannel: (channel, message) ->
|
|
|
|
if channel == 'bigbluebutton:from-rap'
|
|
|
|
return message.header?.name
|
|
|
|
message.envelope?.name
|
|
|
|
|
|
|
|
# Find the meetingId in the message.
|
|
|
|
# This is neccesary because the new message in BigBlueButton 2.0 have
|
|
|
|
# their meetingId in different locations.
|
|
|
|
_findMeetingId: (message) ->
|
|
|
|
# Various 2.0 meetingId locations.
|
|
|
|
return message.envelope.routing.meetingId if message.envelope?.routing?.meetingId?
|
|
|
|
return message.header.body.meetingId if message.header?.body?.meetingId?
|
|
|
|
return message.core.body.meetingId if message.core?.body?.meetingId?
|
|
|
|
return message.core.body.props.meetingProp.intId if message.core?.body?.props?.meetingProp?.intId?
|
|
|
|
# Record and Playback 1.1 meeting_id location.
|
|
|
|
return message.payload.meeting_id if message.payload?.meeting_id?
|
|
|
|
return undefined
|
|
|
|
|
2014-11-11 21:58:28 +08:00
|
|
|
# Processes an event received from redis. Will get all hook URLs that
|
|
|
|
# should receive this event and start the process to perform the callback.
|
|
|
|
_processEvent: (message) ->
|
2014-11-12 23:07:54 +08:00
|
|
|
hooks = Hook.allGlobalSync()
|
2014-11-12 20:53:49 +08:00
|
|
|
|
2014-11-15 02:53:46 +08:00
|
|
|
# TODO: events that happen after the meeting ended will never trigger the hooks
|
|
|
|
# below, since the mapping is removed when the meeting ends
|
2014-11-25 00:34:03 +08:00
|
|
|
|
2014-11-12 20:53:49 +08:00
|
|
|
# filter the hooks that need to receive this event
|
|
|
|
# only global hooks or hooks for this specific meeting
|
2017-09-08 01:11:43 +08:00
|
|
|
|
|
|
|
# All the messages have the meetingId in different locations now.
|
|
|
|
# Depending on the event, it could appear within header, core or envelope.
|
|
|
|
# It always appears in atleast one, so we just need to search for it.
|
|
|
|
idFromMessage = @_findMeetingId(message)
|
2014-11-12 21:28:49 +08:00
|
|
|
if idFromMessage?
|
2014-11-13 22:15:20 +08:00
|
|
|
eMeetingID = IDMapping.getExternalMeetingID(idFromMessage)
|
2014-11-12 23:07:54 +08:00
|
|
|
hooks = hooks.concat(Hook.findByExternalMeetingIDSync(eMeetingID))
|
2014-11-12 20:53:49 +08:00
|
|
|
|
2014-11-12 02:43:41 +08:00
|
|
|
hooks.forEach (hook) ->
|
2014-11-15 00:12:37 +08:00
|
|
|
Logger.info "WebHooks: enqueueing a message in the hook:", hook.callbackURL
|
2014-11-12 02:43:41 +08:00
|
|
|
hook.enqueue message
|