efb44c9dd9
It now does much less directory reading, and performance should scale far better with large numbers of recordings. Semantics should be mostly unchanged, but there's greater use of '.fail' files to mark errors, and '.done' files are now removed after all of the following processing steps complete. The rap worker no longer relies on processing scripts leaving behind empty directories; those are now removed where appropriate.
223 lines
7.6 KiB
Ruby
Executable File
223 lines
7.6 KiB
Ruby
Executable File
#!/usr/bin/ruby
|
|
# encoding: UTF-8
|
|
|
|
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
|
#
|
|
# Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
|
|
# This program is free software; you can redistribute it and/or modify it under
|
|
# the terms of the GNU Lesser General Public License as published by the Free
|
|
# Software Foundation; either version 3.0 of the License, or (at your option)
|
|
# any later version.
|
|
#
|
|
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License along
|
|
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
require '../lib/recordandplayback'
|
|
require 'rubygems'
|
|
require 'yaml'
|
|
require 'fileutils'
|
|
|
|
|
|
def archive_recorded_meeting(recording_dir)
|
|
recorded_done_files = Dir.glob("#{recording_dir}/status/recorded/*.done")
|
|
|
|
recorded_done_files.each do |recorded_done|
|
|
match = /([^\/]*).done$/.match(recorded_done)
|
|
meeting_id = match[1]
|
|
|
|
archived_done = "#{recording_dir}/status/archived/#{meeting_id}.done"
|
|
next if File.exists?(archived_done)
|
|
|
|
archived_fail = "#{recording_dir}/status/archived/#{meeting_id}.fail"
|
|
next if File.exists?(archived_fail)
|
|
|
|
ret = BigBlueButton.exec_ret("ruby", "archive/archive.rb", "-m", meeting_id)
|
|
|
|
if ret == 0 && File.exists?(archived_done)
|
|
BigBlueButton.logger.info("Successfully archived #{meeting_id}")
|
|
FileUtils.rm(recorded_done)
|
|
else
|
|
BigBlueButton.logger.error("Failed to archive #{meeting_id}")
|
|
FileUtils.touch(archived_fail)
|
|
end
|
|
end
|
|
end
|
|
|
|
def sanity_archived_meeting(recording_dir)
|
|
archived_done_files = Dir.glob("#{recording_dir}/status/archived/*.done")
|
|
|
|
archived_done_files.each do |archived_done|
|
|
match = /([^\/]*).done$/.match(archived_done)
|
|
meeting_id = match[1]
|
|
|
|
sanity_done = "#{recording_dir}/status/sanity/#{meeting_id}.done"
|
|
next if File.exists?(sanity_done)
|
|
|
|
sanity_fail = "#{recording_dir}/status/sanity/#{meeting_id}.fail"
|
|
next if File.exists?(sanity_fail)
|
|
|
|
ret = BigBlueButton.exec_ret("ruby", "sanity/sanity.rb", "-m", meeting_id)
|
|
|
|
if ret == 0 && File.exists?(sanity_done)
|
|
BigBlueButton.logger.info("Successfully sanity checked #{meeting_id}")
|
|
post_archive(meeting_id)
|
|
FileUtils.rm(archived_done)
|
|
else
|
|
BigBlueButton.logger.error("Sanity check failed on #{meeting_id}")
|
|
FileUtils.touch(sanity_fail)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
def process_archived_meeting(recording_dir)
|
|
sanity_done_files = Dir.glob("#{recording_dir}/status/sanity/*.done")
|
|
|
|
sanity_done_files.each do |sanity_done|
|
|
match = /([^\/]*).done$/.match(sanity_done)
|
|
meeting_id = match[1]
|
|
|
|
process_succeeded = true
|
|
|
|
# Iterate over the list of recording processing scripts to find available types
|
|
# For now, we look for the ".rb" extension - TODO other scripting languages?
|
|
Dir.glob("process/*.rb").sort.each do |process_script|
|
|
match2 = /([^\/]*).rb$/.match(process_script)
|
|
process_type = match2[1]
|
|
|
|
processed_done = "#{recording_dir}/status/processed/#{meeting_id}-#{process_type}.done"
|
|
next if File.exists?(processed_done)
|
|
|
|
processed_fail = "#{recording_dir}/status/processed/#{meeting_id}-#{process_type}.fail"
|
|
if File.exists?(processed_fail)
|
|
process_succeeded = false
|
|
next
|
|
end
|
|
|
|
# If the process directory doesn't exist, the script does nothing
|
|
FileUtils.rm_rf("#{recording_dir}/process/#{process_type}/#{meeting_id}")
|
|
|
|
process_start = Time.now
|
|
ret = BigBlueButton.exec_ret("ruby", process_script, "-m", meeting_id)
|
|
process_stop = Time.now
|
|
|
|
process_time = ((process_stop - process_start) * 1000).to_i
|
|
IO.write("#{recording_dir}/process/#{process_type}/#{meeting_id}/processing_time", process_time)
|
|
if ret == 0 and File.exists?(processed_done)
|
|
BigBlueButton.logger.info("Process format #{process_type} succeeded for #{meeting_id}")
|
|
BigBlueButton.logger.info("Process took #{process_time}ms")
|
|
else
|
|
BigBlueButton.logger.info("Process format #{process_type} failed for #{meeting_id}")
|
|
BigBlueButton.logger.info("Process took #{process_time}ms")
|
|
FileUtils.touch(processed_fail)
|
|
process_succeeded = false
|
|
end
|
|
end
|
|
|
|
if process_succeeded
|
|
post_process(meeting_id)
|
|
FileUtils.rm(sanity_done)
|
|
end
|
|
end
|
|
end
|
|
|
|
def publish_processed_meeting(recording_dir)
|
|
processed_done_files = Dir.glob("#{recording_dir}/status/processed/*.done")
|
|
|
|
processed_done_files.each do |processed_done|
|
|
match = /([^\/]*)-([^\/-]*).done$/.match(processed_done)
|
|
meeting_id = match[1]
|
|
process_type = match[2]
|
|
|
|
publish_succeeded = true
|
|
|
|
Dir.glob("publish/*.rb").sort.each do |publish_script|
|
|
match2 = /([^\/]*).rb$/.match(publish_script)
|
|
publish_type = match2[1]
|
|
|
|
published_done = "#{recording_dir}/status/published/#{meeting_id}-#{publish_type}.done"
|
|
next if File.exists?(published_done)
|
|
|
|
published_fail = "#{recording_dir}/status/published/#{meeting_id}-#{publish_type}.fail"
|
|
if File.exists?(published_fail)
|
|
publish_succeeded = false
|
|
next
|
|
end
|
|
|
|
# If the publish directory doesn't exist, the script does nothing
|
|
FileUtils.rm_rf("#{recording_dir}/publish/#{publish_type}/#{meeting_id}")
|
|
|
|
# For legacy reasons, the meeting ID passed to the publish script contains
|
|
# the playback format name.
|
|
ret = BigBlueButton.exec_ret("ruby", publish_script, "-m", "#{meeting_id}-#{publish_type}")
|
|
|
|
if ret == 0 and File.exists?(published_done)
|
|
BigBlueButton.logger.info("Publish format #{publish_type} succeeded for #{meeting_id}")
|
|
else
|
|
BigBlueButton.logger.info("Publish format #{publish_type} failed for #{meeting_id}")
|
|
FileUtils.touch(published_fail)
|
|
publish_succeeded = false
|
|
end
|
|
end
|
|
|
|
if publish_succeeded
|
|
post_publish(meeting_id)
|
|
processed_done_files.each do |processed_done|
|
|
FileUtils.rm(processed_done)
|
|
end
|
|
# Also clean up the publish and process work files
|
|
Dir.glob("process/*.rb").sort.each do |process_script|
|
|
match2 = /([^\/]*).rb$/.match(process_script)
|
|
process_type = match2[1]
|
|
FileUtils.rm_rf("#{recording_dir}/process/#{process_type}/#{meeting_id}")
|
|
end
|
|
Dir.glob("publish/*.rb").sort.each do |publish_script|
|
|
match2 = /([^\/]*).rb$/.match(publish_script)
|
|
publish_type = match2[1]
|
|
FileUtils.rm_rf("#{recording_dir}/publish/#{publish_type}/#{meeting_id}")
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
def post_archive(meeting_id)
|
|
BigBlueButton.exec_ret("ruby", "post_scripts/post_archive.rb", "-m", meeting_id)
|
|
end
|
|
|
|
def post_process(meeting_id)
|
|
BigBlueButton.exec_ret("ruby", "post_scripts/post_process.rb", "-m", meeting_id)
|
|
end
|
|
|
|
def post_publish(meeting_id)
|
|
BigBlueButton.exec_ret("ruby", "post_scripts/post_publish.rb", "-m", meeting_id)
|
|
end
|
|
|
|
begin
|
|
props = YAML::load(File.open('bigbluebutton.yml'))
|
|
|
|
log_dir = props['log_dir']
|
|
recording_dir = props['recording_dir']
|
|
|
|
logger = Logger.new("#{log_dir}/bbb-rap-worker.log",'daily' )
|
|
logger.level = Logger::DEBUG
|
|
BigBlueButton.logger = logger
|
|
|
|
BigBlueButton.logger.debug("Running rap-worker...")
|
|
|
|
archive_recorded_meeting(recording_dir)
|
|
sanity_archived_meeting(recording_dir)
|
|
process_archived_meeting(recording_dir)
|
|
publish_processed_meeting(recording_dir)
|
|
rescue Exception => e
|
|
BigBlueButton.logger.error(e.message)
|
|
e.backtrace.each do |traceline|
|
|
BigBlueButton.logger.error(traceline)
|
|
end
|
|
end
|