RaP: Clean up resque worker code, add worker for keep_events feature
I've moved the workers code into the `lib` subdirectory with other library-ish code; this puts it into the ruby load path used by most scripts so referencing files is easier. I've applied various style cleanups based on the rubocop config present. The `events` processing step has been integrated as a new worker `EventsWorker`, there is no longer a separate `events/events.rb` script. I've reworked the `rap-starter.rb` script to check for the done files in both the events and recorded status directories.
This commit is contained in:
parent
bc1b53f037
commit
c52a67186e
21
record-and-playback/core/lib/boot.rb
Normal file
21
record-and-playback/core/lib/boot.rb
Normal file
@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright © 2019 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
# BigBlueButton 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 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/>.
|
||||
|
||||
# Set up the load path for requiring recordandplayback modules
|
||||
$LOAD_PATH.unshift(__dir__) unless $LOAD_PATH.include?(__dir__)
|
4
record-and-playback/core/lib/recordandplayback.rb
Executable file → Normal file
4
record-and-playback/core/lib/recordandplayback.rb
Executable file → Normal file
@ -19,9 +19,7 @@
|
||||
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
|
||||
path = File.expand_path(File.join(File.dirname(__FILE__), '../lib'))
|
||||
$LOAD_PATH << path
|
||||
require_relative 'boot'
|
||||
|
||||
require 'recordandplayback/events_archiver'
|
||||
require 'recordandplayback/generators/events'
|
||||
|
@ -1,6 +1,6 @@
|
||||
# encoding: utf-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright ⓒ 2017 BigBlueButton Inc. and by respective authors.
|
||||
# Copyright © 2017 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
@ -17,9 +17,11 @@
|
||||
# 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 File.expand_path('../rap-base-worker.rb', __FILE__)
|
||||
require File.expand_path('../rap-archive-worker.rb', __FILE__)
|
||||
require File.expand_path('../rap-sanity-worker.rb', __FILE__)
|
||||
require File.expand_path('../rap-process-worker.rb', __FILE__)
|
||||
require File.expand_path('../rap-publish-worker.rb', __FILE__)
|
||||
require File.expand_path('../rap-captions-worker.rb', __FILE__)
|
||||
require 'recordandplayback/workers/base_worker'
|
||||
|
||||
require 'recordandplayback/workers/archive_worker'
|
||||
require 'recordandplayback/workers/captions_worker'
|
||||
require 'recordandplayback/workers/events_worker'
|
||||
require 'recordandplayback/workers/process_worker'
|
||||
require 'recordandplayback/workers/publish_worker'
|
||||
require 'recordandplayback/workers/sanity_worker'
|
@ -1,6 +1,6 @@
|
||||
# encoding: utf-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright ⓒ 2017 BigBlueButton Inc. and by respective authors.
|
||||
# Copyright © 2017 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
@ -17,8 +17,6 @@
|
||||
# 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 File.expand_path('../workers', __FILE__)
|
||||
|
||||
module BigBlueButton
|
||||
module Resque
|
||||
class ArchiveWorker < BaseWorker
|
||||
@ -31,7 +29,7 @@ module BigBlueButton
|
||||
|
||||
remove_status_files
|
||||
|
||||
script = File.expand_path('../../archive/archive.rb', __FILE__)
|
||||
script = File.expand_path('../archive/archive.rb', __dir__)
|
||||
if @break_timestamp.nil?
|
||||
ret, step_time = run_script(script, '-m', @meeting_id)
|
||||
else
|
||||
@ -44,11 +42,7 @@ module BigBlueButton
|
||||
!File.exist?(@archived_fail)
|
||||
)
|
||||
|
||||
@publisher.put_archive_ended(
|
||||
@meeting_id, {
|
||||
success: step_succeeded,
|
||||
step_time: step_time,
|
||||
})
|
||||
@publisher.put_archive_ended(@meeting_id, success: step_succeeded, step_time: step_time)
|
||||
|
||||
if step_succeeded
|
||||
@logger.info("Successfully archived #{@full_id}")
|
||||
@ -78,4 +72,3 @@ module BigBlueButton
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,7 +1,6 @@
|
||||
#!/usr/bin/ruby
|
||||
# encoding: utf-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright ⓒ 2017 BigBlueButton Inc. and by respective authors.
|
||||
# Copyright © 2017 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
@ -18,8 +17,7 @@
|
||||
# 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 File.expand_path('../../../lib/recordandplayback', __FILE__)
|
||||
require File.expand_path('../workers', __FILE__)
|
||||
require 'recordandplayback'
|
||||
require 'rubygems'
|
||||
require 'yaml'
|
||||
require 'fileutils'
|
||||
@ -44,12 +42,10 @@ module BigBlueButton
|
||||
success = yield
|
||||
@logger.info("Ended worker #{@step_name} for #{@meeting_id} with result #{success}")
|
||||
|
||||
if success
|
||||
schedule_next_step unless @single_step
|
||||
else
|
||||
raise "Worker #{@step_name} for #{@meeting_id} failed with result #{success}"
|
||||
end
|
||||
rescue Exception => e
|
||||
raise "Worker #{@step_name} for #{@meeting_id} failed with result #{success}" unless success
|
||||
|
||||
schedule_next_step unless @single_step
|
||||
rescue StandardError => e
|
||||
@logger.error(e.message)
|
||||
e.backtrace.each do |traceline|
|
||||
@logger.error(traceline)
|
||||
@ -62,8 +58,8 @@ module BigBlueButton
|
||||
Dir.glob(glob).sort.each do |post_script|
|
||||
match = %r{([^/]*).rb$}.match(post_script)
|
||||
post_type = match[1]
|
||||
@logger.info("Running post #{@step_name} script #{post_type}")
|
||||
|
||||
@logger.info("Running post #{@step_name} script #{post_type}")
|
||||
post_started_method(post_type, @meeting_id)
|
||||
|
||||
if @format_name.nil?
|
||||
@ -73,15 +69,8 @@ module BigBlueButton
|
||||
end
|
||||
step_succeeded = ret.zero?
|
||||
|
||||
post_ended_method(
|
||||
post_type, @meeting_id, {
|
||||
success: step_succeeded,
|
||||
step_time: step_time,
|
||||
})
|
||||
|
||||
unless step_succeeded
|
||||
@logger.warn("Post #{@step_name} script #{post_script}/#{post_type} failed")
|
||||
end
|
||||
@logger.warn("Post #{@step_name} script #{post_script}/#{post_type} failed") unless step_succeeded
|
||||
post_ended_method(post_type, @meeting_id, success: step_succeeded, step_time: step_time)
|
||||
end
|
||||
end
|
||||
|
||||
@ -147,12 +136,12 @@ module BigBlueButton
|
||||
end
|
||||
|
||||
def initialize(opts)
|
||||
props = BigBlueButton.read_props
|
||||
@props = BigBlueButton.read_props
|
||||
BigBlueButton.create_redis_publisher
|
||||
|
||||
@publisher = BigBlueButton.redis_publisher
|
||||
@log_dir = props['log_dir']
|
||||
@recording_dir = props['recording_dir']
|
||||
@log_dir = @props['log_dir']
|
||||
@recording_dir = @props['recording_dir']
|
||||
@meeting_id = opts['meeting_id']
|
||||
@break_timestamp = opts['break_timestamp']
|
||||
@single_step = opts['single_step'] || false
|
@ -1,6 +1,6 @@
|
||||
# encoding: utf-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright ⓒ 2017 BigBlueButton Inc. and by respective authors.
|
||||
# Copyright © 2017 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
@ -17,8 +17,6 @@
|
||||
# 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 File.expand_path('../workers', __FILE__)
|
||||
|
||||
module BigBlueButton
|
||||
module Resque
|
||||
class CaptionsWorker < BaseWorker
|
@ -0,0 +1,76 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright © 2019 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
# BigBlueButton 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 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/>.
|
||||
|
||||
module BigBlueButton
|
||||
module Resque
|
||||
class EventsWorker < BaseWorker
|
||||
@queue = 'rap:archive'
|
||||
|
||||
def store_events(target_dir)
|
||||
@logger.info("Keeping events for #{meeting_id}")
|
||||
redis = BigBlueButton::RedisWrapper.new(@props['redis_host'], @props['redis_port'], @props['redis_password'])
|
||||
events_archiver = BigBlueButton::RedisEventsArchiver.new(redis)
|
||||
|
||||
events_xml = "#{target_dir}/events.xml"
|
||||
events_archiver.store_events(@meeting_id, events_xml, @break_timestamp)
|
||||
|
||||
# When the events script is responsible for archiving events, the sanity script (which normally clears the events
|
||||
# from redis) will not get run, so we have to clear them here.
|
||||
events_archiver.delete_events(meeting_id) if @break_timestamp.nil?
|
||||
end
|
||||
|
||||
def perform
|
||||
super do
|
||||
@logger.info("Running events worker for #{@full_id}")
|
||||
unless File.exist(@ended_done)
|
||||
@logger.info("Events generation was not enabled for #{@full_id}, skipping")
|
||||
next true # We're inside a block and want to return to the block's caller, not return from perform
|
||||
end
|
||||
|
||||
target_dir = "#{@events_dir}/#{@meeting_id}"
|
||||
FileUtils.mkdir_p(target_dir)
|
||||
|
||||
if File.exist?(raw_events_xml)
|
||||
# This is a recorded meeting. The archive step should have already run, so copy the events.xml from the raw
|
||||
# recording directory.
|
||||
FileUtils.cp("#{@recording_dir}/raw/#{@meeting_id}/events.xml", "#{target_dir}/events.xml")
|
||||
else
|
||||
# This meeting was not recorded. We need to run the (incremental, if break_timestamp was provided) events archiving.
|
||||
store_events(target_dir)
|
||||
end
|
||||
|
||||
FileUtils.rm_f(@ended_done)
|
||||
|
||||
# Only run post events scripts after full meeting ends, not during segments
|
||||
run_post_scripts(@post_scripts_path) if @break_timestamp.nil?
|
||||
|
||||
@logger.info("Finished events worker for #{@full_id}")
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(opts)
|
||||
super(opts)
|
||||
@step_name = 'events'
|
||||
@events_dir = @props['events_dir']
|
||||
@post_scripts_path = File.expand_path('../post_events', __dir__)
|
||||
@ended_done = "#{@recording_dir}/status/ended/#{@full_id}.done"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
# encoding: utf-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright ⓒ 2017 BigBlueButton Inc. and by respective authors.
|
||||
# Copyright © 2017 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
@ -17,8 +17,6 @@
|
||||
# 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 File.expand_path('../workers', __FILE__)
|
||||
|
||||
module BigBlueButton
|
||||
module Resque
|
||||
class ProcessWorker < BaseWorker
|
||||
@ -48,11 +46,7 @@ module BigBlueButton
|
||||
File.exist?(@processed_done) && !File.exist?(@processed_fail)
|
||||
)
|
||||
|
||||
@publisher.put_process_ended(
|
||||
@format_name, @meeting_id, {
|
||||
success: step_succeeded,
|
||||
step_time: step_time,
|
||||
})
|
||||
@publisher.put_process_ended(@format_name, @meeting_id, success: step_succeeded, step_time: step_time)
|
||||
|
||||
if step_succeeded
|
||||
@logger.info("Process format succeeded for #{@full_id}:#{@format_name}")
|
||||
@ -85,11 +79,10 @@ module BigBlueButton
|
||||
super(opts)
|
||||
@step_name = 'process'
|
||||
@format_name = opts['format_name']
|
||||
@post_scripts_path = File.expand_path('../../post_process', __FILE__)
|
||||
@post_scripts_path = File.expand_path('../post_process', __dir__)
|
||||
@processed_done = "#{@recording_dir}/status/processed/#{@meeting_id}-#{@format_name}.done"
|
||||
@processed_fail = "#{@recording_dir}/status/processed/#{@meeting_id}-#{@format_name}.fail"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
# encoding: utf-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright ⓒ 2017 BigBlueButton Inc. and by respective authors.
|
||||
# Copyright © 2017 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
@ -17,7 +17,6 @@
|
||||
# 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 File.expand_path('../workers', __FILE__)
|
||||
require 'custom_hash'
|
||||
|
||||
module BigBlueButton
|
||||
@ -49,8 +48,7 @@ module BigBlueButton
|
||||
File.exist?(@published_done) && !File.exist?(@published_fail)
|
||||
)
|
||||
|
||||
props = BigBlueButton.read_props
|
||||
published_dir = props['published_dir']
|
||||
published_dir = @props['published_dir']
|
||||
|
||||
playback = {}
|
||||
metadata = {}
|
||||
@ -68,7 +66,7 @@ module BigBlueButton
|
||||
raw_size = doc[:recording][:raw_size] unless doc[:recording][:raw_size].nil?
|
||||
start_time = doc[:recording][:start_time] unless doc[:recording][:start_time].nil?
|
||||
end_time = doc[:recording][:end_time] unless doc[:recording][:end_time].nil?
|
||||
rescue Exception => e
|
||||
rescue StandardError => e
|
||||
BigBlueButton.logger.warn 'An exception occurred while loading the extra information for the publish event'
|
||||
BigBlueButton.logger.warn e.message
|
||||
e.backtrace.each do |traceline|
|
||||
@ -80,16 +78,16 @@ module BigBlueButton
|
||||
end
|
||||
|
||||
@publisher.put_publish_ended(
|
||||
@format_name, @meeting_id, {
|
||||
'success': step_succeeded,
|
||||
'step_time': step_time,
|
||||
'playback': playback,
|
||||
'metadata': metadata,
|
||||
'download': download,
|
||||
'raw_size': raw_size,
|
||||
'start_time': start_time,
|
||||
'end_time': end_time,
|
||||
})
|
||||
@format_name, @meeting_id,
|
||||
'success': step_succeeded,
|
||||
'step_time': step_time,
|
||||
'playback': playback,
|
||||
'metadata': metadata,
|
||||
'download': download,
|
||||
'raw_size': raw_size,
|
||||
'start_time': start_time,
|
||||
'end_time': end_time
|
||||
)
|
||||
else
|
||||
@logger.warn("Processed recording found for #{@meeting_id}/#{@format_name}, but no publish script exists")
|
||||
step_succeeded = true
|
||||
@ -119,11 +117,10 @@ module BigBlueButton
|
||||
super(opts)
|
||||
@step_name = 'publish'
|
||||
@format_name = opts['format_name']
|
||||
@post_scripts_path = File.expand_path('../../post_publish', __FILE__)
|
||||
@post_scripts_path = File.expand_path('../post_publish', __dir__)
|
||||
@published_done = "#{@recording_dir}/status/published/#{@meeting_id}-#{@format_name}.done"
|
||||
@published_fail = "#{@recording_dir}/status/published/#{@meeting_id}-#{@format_name}.fail"
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
# encoding: utf-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright ⓒ 2017 BigBlueButton Inc. and by respective authors.
|
||||
# Copyright © 2017 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
@ -17,8 +17,6 @@
|
||||
# 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 File.expand_path('../workers', __FILE__)
|
||||
|
||||
module BigBlueButton
|
||||
module Resque
|
||||
class SanityWorker < BaseWorker
|
||||
@ -31,7 +29,7 @@ module BigBlueButton
|
||||
|
||||
remove_status_files
|
||||
|
||||
script = File.expand_path('../../sanity/sanity.rb', __FILE__)
|
||||
script = File.expand_path('../sanity/sanity.rb', __dir__)
|
||||
if @break_timestamp.nil?
|
||||
ret, step_time = run_script(script, '-m', @meeting_id)
|
||||
else
|
||||
@ -39,11 +37,7 @@ module BigBlueButton
|
||||
end
|
||||
step_succeeded = (ret.zero? && File.exist?(@sanity_done))
|
||||
|
||||
@publisher.put_sanity_ended(
|
||||
@meeting_id, {
|
||||
success: step_succeeded,
|
||||
step_time: step_time,
|
||||
})
|
||||
@publisher.put_sanity_ended(@meeting_id, success: step_succeeded, step_time: step_time)
|
||||
|
||||
if step_succeeded
|
||||
@logger.info("Successfully sanity checked #{@full_id}")
|
||||
@ -65,7 +59,7 @@ module BigBlueButton
|
||||
def initialize(opts)
|
||||
super(opts)
|
||||
@step_name = 'sanity'
|
||||
@post_scripts_path = File.expand_path('../../post_archive', __FILE__)
|
||||
@post_scripts_path = File.expand_path('../post_archive', __dir__)
|
||||
@sanity_fail = "#{@recording_dir}/status/sanity/#{@meeting_id}.fail"
|
||||
@sanity_done = "#{@recording_dir}/status/sanity/#{@meeting_id}.done"
|
||||
end
|
@ -1,98 +0,0 @@
|
||||
# Set encoding to utf-8
|
||||
# encoding: UTF-8
|
||||
#
|
||||
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
|
||||
#
|
||||
# Copyright (c) 2018 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 'logger'
|
||||
require 'trollop'
|
||||
require 'yaml'
|
||||
|
||||
def keep_events(meeting_id, redis_host, redis_port, redis_password, events_dir, break_timestamp)
|
||||
BigBlueButton.logger.info("Keeping events for #{meeting_id}")
|
||||
redis = BigBlueButton::RedisWrapper.new(redis_host, redis_port, redis_password)
|
||||
events_archiver = BigBlueButton::RedisEventsArchiver.new redis
|
||||
|
||||
target_dir = "#{events_dir}/#{meeting_id}"
|
||||
if not FileTest.directory?(target_dir)
|
||||
FileUtils.mkdir_p target_dir
|
||||
end
|
||||
|
||||
events_xml = "#{target_dir}/events.xml"
|
||||
events = events_archiver.store_events(meeting_id, events_xml, break_timestamp)
|
||||
end
|
||||
|
||||
################## START ################################
|
||||
|
||||
opts = Trollop::options do
|
||||
opt :meeting_id, "Meeting id with events to keep", type: :string
|
||||
opt :break_timestamp, "Chapter break end timestamp", type: :integer
|
||||
end
|
||||
Trollop::die :meeting_id, "must be provided" if opts[:meeting_id].nil?
|
||||
|
||||
meeting_id = opts[:meeting_id]
|
||||
break_timestamp = opts[:break_timestamp]
|
||||
|
||||
# This script lives in scripts/archive/steps while bigbluebutton.yml lives in scripts/
|
||||
props = YAML::load(File.open('bigbluebutton.yml'))
|
||||
recording_dir = props['recording_dir']
|
||||
raw_archive_dir = "#{recording_dir}/raw"
|
||||
events_dir = props['events_dir']
|
||||
redis_host = props['redis_host']
|
||||
redis_port = props['redis_port']
|
||||
redis_password = props['redis_password']
|
||||
log_dir = props['log_dir']
|
||||
|
||||
raw_events_xml = "#{raw_archive_dir}/#{meeting_id}/events.xml"
|
||||
ended_done_file = "#{recording_dir}/status/ended/#{meeting_id}.done"
|
||||
recorded_done_file = "#{recording_dir}/status/recorded/#{meeting_id}.done"
|
||||
|
||||
BigBlueButton.logger = Logger.new("#{log_dir}/events.log", 'daily')
|
||||
|
||||
# Be aware of this section! This is used as a synchronization between
|
||||
# rap-archive-worker and rap-events-worker for meetings that are recorded.
|
||||
# We want the archive step to finish to make sure that the events.xml
|
||||
# has already been written in raw directory before copying into the events
|
||||
# directory. (ralam July 5, 2019)
|
||||
if File.exist? recorded_done_file
|
||||
BigBlueButton.logger.info("Temporarily skipping #{meeting_id} for archive to finish")
|
||||
exit 0
|
||||
end
|
||||
|
||||
target_dir = "#{events_dir}/#{meeting_id}"
|
||||
if not FileTest.directory?(target_dir)
|
||||
FileUtils.mkdir_p target_dir
|
||||
if File.exist? raw_events_xml
|
||||
# This is a recorded meetings. Therefore, copy the events.xml
|
||||
# from raw directory instead of collecting the events from redis.
|
||||
# (ralam July 5, 2019)
|
||||
BigBlueButton.logger.info("Copying events from #{raw_events_xml}")
|
||||
events_xml = "#{events_dir}/#{meeting_id}/events.xml"
|
||||
FileUtils.cp(raw_events_xml, events_xml)
|
||||
else
|
||||
keep_events(meeting_id, redis_host, redis_port, redis_password, events_dir, break_timestamp)
|
||||
# we need to delete the keys here because the sanity phase might not
|
||||
# automatically happen for this recording
|
||||
BigBlueButton.logger.info("Deleting redis keys")
|
||||
redis = BigBlueButton::RedisWrapper.new(redis_host, redis_port, redis_password)
|
||||
events_archiver = BigBlueButton::RedisEventsArchiver.new(redis)
|
||||
events_archiver.delete_events(meeting_id)
|
||||
end
|
||||
FileUtils.rm ended_done_file
|
||||
end
|
@ -1,97 +0,0 @@
|
||||
#!/usr/bin/ruby
|
||||
# encoding: utf-8
|
||||
|
||||
# Copyright ⓒ 2017 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
# BigBlueButton 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 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 run_post_events_script(meeting_id)
|
||||
Dir.glob('post_events/*.rb').sort.each do |post_event_script|
|
||||
match = %r{([^/]*).rb$}.match(post_event_script)
|
||||
post_type = match[1]
|
||||
BigBlueButton.logger.info("Running post event script #{post_type}")
|
||||
|
||||
# step_start_time = BigBlueButton.monotonic_clock
|
||||
ret = BigBlueButton.exec_ret('ruby', post_event_script, '-m', meeting_id)
|
||||
# step_stop_time = BigBlueButton.monotonic_clock
|
||||
# step_time = step_stop_time - step_start_time
|
||||
step_succeeded = ret.zero?
|
||||
|
||||
unless step_succeeded
|
||||
BigBlueButton.logger.warn("Post event script #{post_event_script} failed")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def keep_meeting_events(recording_dir, ended_done_file)
|
||||
ended_done_base = File.basename(ended_done_file, '.done')
|
||||
meeting_id = nil
|
||||
break_timestamp = nil
|
||||
|
||||
if match = /^([0-9a-f]+-[0-9]+)$/.match(ended_done_base)
|
||||
meeting_id = match[1]
|
||||
elsif match = /^([0-9a-f]+-[0-9]+)-([0-9]+)$/.match(ended_done_base)
|
||||
meeting_id = match[1]
|
||||
break_timestamp = match[2]
|
||||
else
|
||||
BigBlueButton.logger.warn("Ended done file for #{ended_done_base} has invalid format")
|
||||
end
|
||||
|
||||
return if meeting_id.nil?
|
||||
|
||||
if !break_timestamp.nil?
|
||||
BigBlueButton.exec_ret('ruby', 'events/events.rb', '-m', meeting_id, '-b', break_timestamp)
|
||||
else
|
||||
BigBlueButton.exec_ret('ruby', 'events/events.rb', '-m', meeting_id)
|
||||
|
||||
# Need to only run post events scripts after meeting ends not during segments.
|
||||
run_post_events_script(meeting_id)
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
props = YAML.safe_load(File.open('bigbluebutton.yml'))
|
||||
redis_host = props['redis_host']
|
||||
redis_port = props['redis_port']
|
||||
redis_password = props['redis_password']
|
||||
BigBlueButton.redis_publisher = BigBlueButton::RedisWrapper.new(redis_host, redis_port, redis_password)
|
||||
|
||||
log_dir = props['log_dir']
|
||||
recording_dir = props['recording_dir']
|
||||
|
||||
logger = Logger.new("#{log_dir}/bbb-rap-worker.log")
|
||||
# logger = Logger.new(STDOUT)
|
||||
logger.level = Logger::INFO
|
||||
BigBlueButton.logger = logger
|
||||
|
||||
BigBlueButton.logger.info('Running rap-events-worker...')
|
||||
ended_done_files = Dir.glob("#{recording_dir}/status/ended/*.done")
|
||||
ended_done_files.each do |ended_done|
|
||||
keep_meeting_events(recording_dir, ended_done)
|
||||
end
|
||||
BigBlueButton.logger.debug('rap-events-worker done')
|
||||
|
||||
rescue Exception => e
|
||||
BigBlueButton.logger.error(e.message)
|
||||
e.backtrace.each do |traceline|
|
||||
BigBlueButton.logger.error(traceline)
|
||||
end
|
||||
end
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/ruby
|
||||
# encoding: utf-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Copyright ⓒ 2017 BigBlueButton Inc. and by respective authors.
|
||||
# Copyright © 2017 BigBlueButton Inc. and by respective authors.
|
||||
#
|
||||
# This file is part of BigBlueButton open source conferencing system.
|
||||
#
|
||||
@ -18,8 +18,9 @@
|
||||
# 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 File.expand_path('../../lib/recordandplayback', __FILE__)
|
||||
require File.expand_path('../workers/workers', __FILE__)
|
||||
require_relative '../lib/recordandplayback'
|
||||
|
||||
require 'recordandplayback/workers'
|
||||
require 'rubygems'
|
||||
require 'yaml'
|
||||
require 'fileutils'
|
||||
@ -29,72 +30,96 @@ require 'rb-inotify'
|
||||
class StopSignalException < StandardError
|
||||
end
|
||||
|
||||
def archive_recorded_meetings(recording_dir, done_file)
|
||||
FileUtils.mkdir_p("#{recording_dir}/status/archived")
|
||||
meeting_id = nil
|
||||
break_timestamp = nil
|
||||
|
||||
if match = /^([0-9a-f]+-[0-9]+)$/.match(done_file)
|
||||
meeting_id = match[1]
|
||||
elsif match = /^([0-9a-f]+-[0-9]+)-([0-9]+)$/.match(done_file)
|
||||
meeting_id = match[1]
|
||||
break_timestamp = match[2]
|
||||
def parse_meeting_id(done_file)
|
||||
id = File.basename(done_file, '.done')
|
||||
if (match = /^([0-9a-f]+-[0-9]+)$/.match(id))
|
||||
{ meeting_id: match[1], break_timestamp: nil }
|
||||
elsif (match = /^([0-9a-f]+-[0-9]+)-([0-9]+)$/.match(id))
|
||||
{ meeting_id: match[1], break_timestamp: match[2] }
|
||||
else
|
||||
BigBlueButton.logger.warn("Recording done file for #{done_file} has invalid format")
|
||||
BigBlueButton.logger.warn("Recording done file #{done_file} has invalid format")
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def keep_meeting_events(recording_dir, ended_done_file)
|
||||
id = File.basename(ended_done_file, '.done')
|
||||
BigBlueButton.logger.debug("Seen new ended done file for #{id}")
|
||||
attrs = parse_meeting_id(id)
|
||||
return if attrs.nil?
|
||||
|
||||
# If a meeting was recorded, the events will be archived by the archive step, and
|
||||
# the events script will be run after that (it'll grab the already archived events
|
||||
# from the recording raw directory)
|
||||
if File.exist?("#{recording_dir}/status/recorded/#{id}.done") || File.exist?("#{recording_dir}/raw/#{attrs[:meeting_id]}")
|
||||
BigBlueButton.logger.info("Meeting #{id} had recording enabled, events will be handled after recording archive")
|
||||
return
|
||||
end
|
||||
|
||||
attrs = {
|
||||
'meeting_id': meeting_id,
|
||||
'break_timestamp': break_timestamp,
|
||||
}
|
||||
BigBlueButton.logger.info("Enqueueing job to keep events #{attrs.inspect}")
|
||||
Resque.enqueue(BigBlueButton::Resque::EventsWorker, attrs)
|
||||
FileUtils.rm_f(ended_done_file)
|
||||
end
|
||||
|
||||
def archive_recorded_meetings(recording_dir, done_file)
|
||||
id = File.basename(done_file, '.done')
|
||||
BigBlueButton.logger.debug("Seen new recorded done file for #{id}")
|
||||
attrs = parse_meeting_id(id)
|
||||
return if attrs.nil?
|
||||
|
||||
# The keep events stuff uses this directory presence to check if a meeting is
|
||||
# recorded when the recorded done file is gone
|
||||
FileUtils.mkdir_p("#{recording_dir}/raw/#{attrs[:meeting_id]}")
|
||||
|
||||
BigBlueButton.logger.info("Enqueuing job to archive #{attrs.inspect}")
|
||||
Resque.enqueue(BigBlueButton::Resque::ArchiveWorker, attrs)
|
||||
FileUtils.rm_f(recorded_done_file)
|
||||
end
|
||||
|
||||
begin
|
||||
props = BigBlueButton.read_props
|
||||
log_dir = props['log_dir']
|
||||
|
||||
redis_host = props['redis_workers_host'] || props['redis_host']
|
||||
redis_port = props['redis_workers_port'] || props['redis_port']
|
||||
Resque.redis = "#{redis_host}:#{redis_port}"
|
||||
|
||||
BigBlueButton.logger.debug('Running rap-trigger...')
|
||||
BigBlueButton.logger.debug('Running rap-starter...')
|
||||
|
||||
recording_dir = props['recording_dir']
|
||||
watch_dir = "#{recording_dir}/status/recorded/"
|
||||
ended_status_dir = "#{recording_dir}/status/ended"
|
||||
recorded_status_dir = "#{recording_dir}/status/recorded"
|
||||
|
||||
# start the process for all .done files already there
|
||||
done_files = Dir.glob("#{watch_dir}*.done")
|
||||
done_files.each do |file|
|
||||
id = File.basename(file, '.done')
|
||||
BigBlueButton.logger.info "Detected recording #{id}, starting the processing"
|
||||
archive_recorded_meetings(recording_dir, id)
|
||||
FileUtils.rm_f(file)
|
||||
# Check for missed "ended" .done files
|
||||
ended_done_files = Dir.glob("#{ended_status_dir}/*.done")
|
||||
ended_done_files.each do |ended_done_file|
|
||||
keep_meeting_events(recording_id, ended_done_file)
|
||||
end
|
||||
|
||||
# Listen the directory for when new files are created
|
||||
BigBlueButton.logger.info("Setting up inotify watch on #{watch_dir}")
|
||||
# Check for missed "recorded" .done files
|
||||
recorded_done_files = Dir.glob("#{recorded_status_dir}/*.done")
|
||||
recorded_done_files.each do |recorded_done_file|
|
||||
archive_recorded_meetings(recording_dir, recorded_done_file)
|
||||
end
|
||||
|
||||
# Listen the directories for when new files are created
|
||||
BigBlueButton.logger.info("Setting up inotify watch on #{ended_status_dir}")
|
||||
notifier = INotify::Notifier.new
|
||||
notifier.watch(watch_dir, :moved_to, :create) do |event|
|
||||
notifier.watch(ended_status_dir, :moved_to, :create) do |event|
|
||||
next unless event.name.end_with?('.done')
|
||||
|
||||
id = File.basename(event.name, '.done')
|
||||
BigBlueButton.logger.info "Detected recording #{id}, starting the processing"
|
||||
archive_recorded_meetings(recording_dir, id)
|
||||
FileUtils.rm_f(event.absolute_name)
|
||||
keep_meeting_events(recording_dir, event.absolute_name)
|
||||
end
|
||||
BigBlueButton.logger.info("Setting up inotify watch on #{recorded_status_dir}")
|
||||
notifier.watch(recorded_status_dir, :moved_to, :create) do |event|
|
||||
next unless event.name.end_with?('.done')
|
||||
|
||||
archive_recorded_meetings(recording_dir, event.absolute_name)
|
||||
end
|
||||
|
||||
BigBlueButton.logger.info('Waiting for new recordings...')
|
||||
Signal.trap('INT') { raise StopSignalException.new }
|
||||
Signal.trap('TERM') { raise StopSignalException.new }
|
||||
Signal.trap('INT') { raise StopSignalException, 'INT' }
|
||||
Signal.trap('TERM') { raise StopSignalException, 'TERM' }
|
||||
notifier.run
|
||||
rescue StopSignalException
|
||||
notifier.stop
|
||||
rescue Exception => e
|
||||
BigBlueButton.logger.error(e.message)
|
||||
e.backtrace.each do |traceline|
|
||||
BigBlueButton.logger.error(traceline)
|
||||
end
|
||||
end
|
||||
|
@ -1,10 +0,0 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton recording and playback events worker
|
||||
ConditionPathExistsGlob=/var/bigbluebutton/recording/status/ended/*.done
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bigbluebutton/core/scripts/rap-events-worker.rb
|
||||
WorkingDirectory=/usr/local/bigbluebutton/core/scripts
|
||||
User=bigbluebutton
|
||||
Slice=bbb_record_core.slice
|
@ -1,4 +0,0 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton recording & playback processing
|
||||
Wants=bbb-rap-events-worker.service
|
||||
StopWhenUnneeded=true
|
@ -1,10 +0,0 @@
|
||||
[Unit]
|
||||
Description=BigBlueButton record & playback processing timer
|
||||
|
||||
[Timer]
|
||||
OnActiveSec=0
|
||||
OnUnitInactiveSec=30s
|
||||
Unit=bbb-record-core.target
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
Loading…
Reference in New Issue
Block a user