# # # = Jeeves Scheduler # # == Schedule Jeeves related tasks from recordings to shutdowns and wakeups # # Author:: Robert Sharp # Copyright:: Copyright (c) 2011 Robert Sharp # License:: Open Software Licence v3.0 # # This software is licensed for use under the Open Software Licence v. 3.0 # The terms of this licence can be found at http://www.opensource.org/licenses/osl-3.0.php # and in the file copyright.txt. Under the terms of this licence, all derivative works # must themselves be licensed under the Open Software Licence v. 3.0 # # This scheduler will schedule at jobs and use wolly to schedule wakeups. It is a Jerbil # service. # require 'jerbil/jerbil_service/base' require 'jerbil/jerbil_service/support' require 'jerbil/support' require 'jeeves/config' require 'jeeves/errors' require 'open3' # # == Jeeves Service # # Synopsis of the whole service # module Jscheduler # add generic class methods extend JerbilService::Support # inherit the Jeeves config file class Config < Jeeves::Config; end # === Jeeves Service class # # Description of how the service class works # class Service < JerbilService::Base # Document the constructor as required. # # pkey:: string - private key that must be used for # supervision calls (e.g. stop_callback) # options:: hash of options, preferably as created by Jeckyl. See documentation # on JerbilService::Base for assumed options re logging etc # def initialize(pkey, options) @tuner = options[:tuner] raise InvalidTuner("Tuner is not recognized: #{@tuner}") unless Schedulers.has_key?(@tuner) # do things that cannot be done when $SAFE > 0 # the symbol should be the app name and must correspond to a service in /etc/services super(:jschedule, pkey, options) # DRb is now working, this process may have daemonized and $SAFE = 1 @logger.verbose("Started scheduler for tuner #{@tuner}") end # # define additional class methods to make things happen # def schedule(params={}) [:filename, :channel, :start, :duration].each do |param| raise Jeeves::MissingParam, "Schedule method must specify #{param}" unless params.has_key?(param) end mode = params[:mode] || :avi raise InvalidMode, "Tuner #{@tuner} does not have mode: #{mode}" unless Schedulers[@tuner].has_key?(mode) scheduler = Schedulers[@tuner][mode] startParam = params[:start].strftime("%H:%M %b %d") command = "#{scheduler} #{params[:channel]} #{params[:duration]} #{params[:filename]}" @logger.debug "About to schedule: #{command}" # need open3 to get the full communication with at inpipe, outpipe, errpipe = Open3.popen3("/usr/bin/at #{startParam}") inpipe.puts command inpipe.close response = errpipe.readlines outpipe.close errpipe.close # get the job id and return it to the caller jobnum = nil job_re = /job (\d+) at/ response.each do |resp| @logger.debug "Response includes: " + resp if results = job_re.match(resp) then @logger.debug "Recognised Job: " + results[1] jobnum = results[1].clone end end @logger.info "Scheduled recording on #{params[:channel]} at #{startParam} for #{params[:duration]} with job no: #{jobnum}" # set a wol timer here return jobnum rescue Jeeves::JeevesError raise rescue @logger.exception($!) return '0' end # deletes the at job with the given job number # assume that the given jobnum is valid def delete_schedule(jobnum) begin @logger.info "Removing job: #{jobnum}" system("/usr/bin/atrm #{jobnum.to_s}") rescue @logger.exception($!) end end # do not redefine the superclass methods unless you are absolutely sure you know # what you are doing. protected Schedulers = { :dvb=>{ :avi=>'/usr/local/bin/virea-dvb-record.sh', :ts=>'/usr/local/bin/virea-dvb-record-ts.sh' }, :pvr=>{ :avi=>'/usr/local/bin/virea-pvr-record.sh', :ts=>'/usr/local/bin/virea-pvr-record-ts.sh' } } end end