Add endpoint to detect new recordings and update the interface

The endpoint receives events from BigBlueButton via webhooks or scripts
in the record and playback workflow.
For now it only treats the event for when a recording is ready.
When it happens, it uses action cable to update the interface dynamically
with the new recording.
This commit is contained in:
Leonardo Crauss Daronco
2016-12-07 16:20:10 -02:00
parent b518458622
commit e5efb05a01
11 changed files with 178 additions and 16 deletions

View File

@ -20,6 +20,9 @@ class BbbController < ApplicationController
before_action :authorize_recording_owner!, only: [:update_recordings, :delete_recordings]
before_action :load_and_authorize_room_owner!, only: [:end]
skip_before_action :verify_authenticity_token, only: :callback
before_action :validate_checksum, only: :callback
# GET /:resource/:id/join
def join
if params[:name].blank?
@ -39,7 +42,9 @@ class BbbController < ApplicationController
user_is_moderator: true
}
end
options[:meeting_logout_url] = "#{request.base_url}/#{params[:resource]}/#{params[:id]}"
base_url = "#{request.base_url}/#{params[:resource]}/#{params[:id]}"
options[:meeting_logout_url] = base_url
options[:hook_url] = "#{base_url}/callback"
bbb_res = bbb_join_url(
params[:id],
@ -55,6 +60,20 @@ class BbbController < ApplicationController
end
end
# POST /:resource/:id/callback
# Endpoint for webhook calls from BigBlueButton
def callback
begin
data = JSON.parse(read_body(request))
treat_callback_event(data["event"])
rescue Exception => e
logger.error "Error parsing webhook data. Data: #{data}, exception: #{e.inspect}"
# respond with 200 anyway so BigBlueButton knows the hook call was ok
render head(:ok)
end
end
# DELETE /rooms/:id/end
def end
load_and_authorize_room_owner!
@ -130,4 +149,61 @@ class BbbController < ApplicationController
@response = response
render status: @status
end
def read_body(request)
request.body.read.force_encoding("UTF-8")
end
def treat_callback_event(event)
# a recording is ready
if event['header']['name'] == "publish_ended"
token = event['payload']['metadata'][META_TOKEN]
record_id = event['payload']['meeting_id']
# the webhook event doesn't have all the data we need, so we need
# to send a getRecordings anyway
# TODO: if the webhooks included all data we wouldn't need this
rec_info = bbb_get_recordings(token, record_id)
rec_info = rec_info[:recordings].first
RecordingCreatedJob.perform_later(token, parse_recording_for_view(rec_info))
end
render head(:ok) && return
end
# Validates the checksum received in a callback call.
# If the checksum doesn't match, renders an ok and aborts execution.
def validate_checksum
secret = ENV['BIGBLUEBUTTON_SECRET']
checksum = params["checksum"]
data = read_body(request)
callback_url = uri_remove_param(request.url, "checksum")
checksum_str = "#{callback_url}#{data}#{secret}"
calculated_checksum = Digest::SHA1.hexdigest(checksum_str)
if calculated_checksum != checksum
logger.error "Checksum did not match. Calculated: #{calculated_checksum}, received: #{checksum}"
# respond with 200 anyway so BigBlueButton knows the hook call was ok
# but abort execution
render head(:ok) && return
end
end
# Removes parameters from an URI
def uri_remove_param(uri, params = nil)
return uri unless params
params = Array(params)
uri_parsed = URI.parse(uri)
return uri unless uri_parsed.query
new_params = uri_parsed.query.gsub(/&amp;/, '&').split('&').reject { |q| params.include?(q.split('=').first) }
uri = uri.split('?').first
if new_params.count > 0
"#{uri}?#{new_params.join('&')}"
else
uri
end
end
end