#!/usr/bin/env ruby require 'pathname' require 'optparse' require 'optparse/time' require 'ostruct' require 'socket' require 'yaml' class Pathname def extname= (extension) @path = @path[0..@path.length-extname.length-1] if extension.length > 0 @path << '.' if extension[0] != '.' @path << extension.to_s end end def chext (extension) res = self.clone res.extname = extension res end end APP_VERSION = 'BECHA-server v1.0.4' ARGV_COUNT = 1 DEFAULT_PLAYLIST_PATH = './becha.playlist.conf' DEFAULT_LOG_PATH = './becha.log' DEFAULT_ERRLOG_PATH = './becha.error.log' DEFAULT_PORT = 2014 def parse_options(args) options = OpenStruct.new opt_parser = OptionParser.new do |opts| opts.banner = "Usage: bechad [options] cmd [args]\n\n" + "Avalaible commands:\n" + " start\t\t- Power ON the tape recorder\n" + " stop\t\t- Power OFF the tape recorder\n" + " record track-path\t\t- Record track into the tape recorder" options.verbose = false options.playlist_path = Pathname.new(DEFAULT_PLAYLIST_PATH).expand_path options.log_path = Pathname.new(DEFAULT_LOG_PATH).expand_path options.errlog_path = Pathname.new(DEFAULT_ERRLOG_PATH).expand_path options.port = DEFAULT_PORT opts.separator "" opts.separator "Common options:" opts.on("-l", "--playlist path", String, "Define playlist path (default - " + DEFAULT_PLAYLIST_PATH.to_s + ")") do |path| options.playlist_path = Pathname.new path end opts.on("-p", "--port num", Integer, "Define UDP port number (default - " + DEFAULT_PORT.to_s + ")") do |port| options.port = port end opts.on("-e", "--log path", String, "Define log file (default - " + DEFAULT_LOG_PATH.to_s + ")") do |path| options.log_path = Pathname.new path end opts.on("-E", "--errlog path", String, "Define log file for errors (default - " + DEFAULT_ERRLOG_PATH.to_s + ")") do |path| options.errlog_path = Pathname.new path end opts.on("--verbose", "Print extra information") do options.verbose = true end opts.on_tail("-h", "--help", "Show this message") do puts opts exit end opts.on_tail("--version", "Show version") do puts APP_VERSION exit end end opt_parser.parse!(args) [options, opt_parser] end res = parse_options(ARGV) options = res[0] opt_parser = res[1] if ARGV.count < ARGV_COUNT p opt_parser exit 1 end argv = ARGV.reverse cmd = argv.pop case cmd when 'start' playlist_path = Pathname.new(options.playlist_path.expand_path) playlist = YAML::load(IO.read playlist_path.expand_path) raise 'Config file is corrupted' unless playlist.class == Hash puts "Starting daemon..." Process.daemon STDOUT.reopen options.log_path.expand_path, 'a' STDERR.reopen options.errlog_path.expand_path, 'a' $stdout = STDOUT $stderr = STDERR STDOUT.sync = true STDERR.sync = true sock = UDPSocket.new sock.bind '', options.port puts "[#{Time.now}] Server started!" loop do packet = sock.recvfrom 32 if packet[0] == "quit" puts "[#{Time.now}] Exiting..." Process.kill "KILL", $mplayer_pid unless $mplayer_pid.nil? exit 0 end puts "[#{Time.now}] Received data: #{packet[0].to_s}" if playlist.has_key? packet[0].to_s puts "[#{Time.now}] Start playing: #{playlist[packet[0].to_s]}" begin Process.kill "KILL", $mplayer_pid unless $mplayer_pid.nil? $mplayer_pid = fork do `mplayer "#{playlist[packet[0].to_s]}"` end rescue => error puts 'Error playing' p error p "#{playlist[packet[0].to_s]}" $mplayer_pid = nil end else puts "[#{Time.now}] Item not found" begin Process.kill "KILL", $mplayer_pid unless $mplayer_pid.nil? $mplayer_pid = nil rescue $mplayer_pid = nil end end end loop { } when 'stop' sock = UDPSocket.new sock.send 'quit', 0, 'localhost', options.port when 'record' playlist_path = Pathname.new options.playlist_path.expand_path begin playlist = YAML::load IO.read playlist_path.expand_path rescue playlist = {} end raise 'Config file is corrupted' unless playlist.class == Hash track_path = argv.pop p opt_parser if track_path.nil? track_path = Pathname.new(track_path).expand_path sock = UDPSocket.new sock.bind '', options.port loop do packet = sock.recvfrom 32 if packet[0].length == 0 puts "Received error packet, retrying..." else playlist[packet[0]] = track_path IO.write playlist_path.expand_path, YAML::dump(playlist) if playlist == YAML::load(IO.read playlist_path.expand_path) puts "Recording successful: #{packet[0]} -> #{track_path}" break else puts "Recording error!" p playlist p '---' p YAML::load(IO.read playlist_path.expand_path) end end end else p 'Undefined command' p opt_parser exit 1 end exit 0