125 lines
3.8 KiB
Ruby
125 lines
3.8 KiB
Ruby
require 'json'
|
|
require 'resque'
|
|
|
|
require 'resque-lonely_job'
|
|
require 'net/http'
|
|
require 'digest/md5'
|
|
|
|
module JamRuby
|
|
|
|
# executes a mix of tracks, creating a final output mix
|
|
class IcecastConfigWriter
|
|
extend Resque::Plugins::LonelyJob
|
|
|
|
@@log = Logging.logger[IcecastConfigWriter]
|
|
|
|
attr_accessor :icecast_server_id
|
|
|
|
def self.queue
|
|
queue_name(::APP_CONFIG.icecast_server_id)
|
|
end
|
|
|
|
def self.queue_jobs_needing_retry
|
|
# if we haven't seen updated_at be tickled in 5 minutes, but config_changed is still set to TRUE, this record has gotten stale
|
|
IcecastServer.find_each(:conditions => "config_changed = 1 AND updated_at < (NOW() at time zone 'utc' - interval '#{APP_CONFIG.icecast_max_missing_check} second')", :batch_size => 100) do |server|
|
|
IcecastConfigWriter.enqueue(server.server_id)
|
|
end
|
|
end
|
|
|
|
def self.queue_name(server_id)
|
|
"icecast-#{server_id}"
|
|
end
|
|
|
|
def self.lock_timeout
|
|
# this should be enough time to make sure the job has finished, but not so long that the system isn't recovering from a abandoned job
|
|
60
|
|
end
|
|
|
|
def self.perform(icecast_server_id)
|
|
icecast = IcecastConfigWriter.new()
|
|
icecast.icecast_server_id = icecast_server_id
|
|
icecast.run
|
|
end
|
|
|
|
def self.enqueue(server_id)
|
|
begin
|
|
Resque.enqueue_to(queue_name(server_id), IcecastConfigWriter, server_id)
|
|
return true
|
|
rescue
|
|
@@log.error("unable to enqueue IceastConfigWriter(#{server_id}). #{$!}")
|
|
# implies redis is down
|
|
return false
|
|
end
|
|
end
|
|
|
|
def initialize
|
|
|
|
end
|
|
|
|
def validate
|
|
raise "icecast_server_id not spceified" unless icecast_server_id
|
|
raise "queue routing mismatch error. requested icecast_server_id: #{icecast_server_id}, configured icecast_server_id: #{APP_CONFIG.icecast_server_id}" unless icecast_server_id == APP_CONFIG.icecast_server_id
|
|
end
|
|
|
|
def execute(cmd)
|
|
system cmd
|
|
$?.exitstatus
|
|
end
|
|
|
|
def reload
|
|
cmd = APP_CONFIG.icecast_reload_cmd
|
|
result = execute(cmd)
|
|
raise "unable to execute icecast reload cmd=#{cmd}. result=#{$?}" unless result == 0
|
|
|
|
sleep APP_CONFIG.icecast_wait_after_reload
|
|
end
|
|
|
|
def run
|
|
validate
|
|
|
|
config_file = APP_CONFIG.icecast_config_file
|
|
|
|
# check if the config file is there at all; if it's not, we need to generate it regardless if config has changed
|
|
query = {server_id: icecast_server_id}
|
|
|
|
icecast_server = IcecastServer.where(server_id: icecast_server_id).first
|
|
|
|
raise "can not find icecast server with query #{query}" unless icecast_server
|
|
|
|
if File.exist?(config_file) && !icecast_server.config_changed
|
|
@@log.info("config not changed. skipping run for server: #{icecast_server.server_id}")
|
|
else
|
|
# don't try to write to the file if for some reason the model isn't valid
|
|
# this could happen if an admin mucks around in the db directly
|
|
raise "icecast_server.id=#{icecast_server.server_id} not valid. errors=#{icecast_server.errors.inspect}" unless icecast_server.valid?
|
|
|
|
# write the new config to a temporary location
|
|
tmp_config = Dir::Tmpname.make_tmpname(["#{Dir.tmpdir}/icecast", '.xml'], nil)
|
|
|
|
buffer = nil
|
|
# allow no write to the server while dumping XML
|
|
|
|
icecast_server.with_lock do
|
|
buffer = StringIO.new
|
|
icecast_server.dumpXml(buffer)
|
|
end
|
|
|
|
buffer.rewind
|
|
File.open(tmp_config, 'w') do |f|
|
|
f.write buffer.read
|
|
end
|
|
|
|
# if written successfully, overwrite the current file
|
|
FileUtils.mv tmp_config, config_file
|
|
|
|
# reload server
|
|
reload
|
|
|
|
icecast_server.config_updated
|
|
end
|
|
|
|
@@log.info("successful update of config for server: #{icecast_server.server_id}")
|
|
|
|
end
|
|
end
|
|
end |