0.1.0
This commit is contained in:
commit
54a825211e
58
Rakefile
Normal file
58
Rakefile
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
require 'rubygems'
|
||||||
|
require 'rake'
|
||||||
|
|
||||||
|
begin
|
||||||
|
require 'jeweler'
|
||||||
|
Jeweler::Tasks.new do |gem|
|
||||||
|
gem.name = "svdrpd"
|
||||||
|
gem.summary = %Q{Multiplexer for SVDRP}
|
||||||
|
gem.description = %Q{Allowes to more than one connection to communicate with VDR}
|
||||||
|
gem.email = "Denis.Knauf@gmail.com"
|
||||||
|
gem.homepage = "http://github.com/DenisKnauf/svdrpd"
|
||||||
|
gem.authors = ["Denis Knauf"]
|
||||||
|
gem.files = ["README.md", "VERSION", "bin/**/*", "lib/**/*.rb", "test/**/*.rb"]
|
||||||
|
gem.require_paths = ["bin"]
|
||||||
|
gem.add_dependency 'select'
|
||||||
|
end
|
||||||
|
Jeweler::GemcutterTasks.new
|
||||||
|
rescue LoadError
|
||||||
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
||||||
|
end
|
||||||
|
|
||||||
|
require 'rake/testtask'
|
||||||
|
Rake::TestTask.new(:test) do |test|
|
||||||
|
test.libs << 'lib' << 'test' << 'ext'
|
||||||
|
test.pattern = 'test/**/*_test.rb'
|
||||||
|
test.verbose = true
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
require 'rcov/rcovtask'
|
||||||
|
Rcov::RcovTask.new do |test|
|
||||||
|
test.libs << 'test'
|
||||||
|
test.pattern = 'test/**/*_test.rb'
|
||||||
|
test.verbose = true
|
||||||
|
end
|
||||||
|
rescue LoadError
|
||||||
|
task :rcov do
|
||||||
|
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
task :test => :check_dependencies
|
||||||
|
|
||||||
|
task :default => :test
|
||||||
|
|
||||||
|
require 'rake/rdoctask'
|
||||||
|
Rake::RDocTask.new do |rdoc|
|
||||||
|
if File.exist?('VERSION')
|
||||||
|
version = File.read('VERSION')
|
||||||
|
else
|
||||||
|
version = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
rdoc.rdoc_dir = 'rdoc'
|
||||||
|
rdoc.title = "sbdb #{version}"
|
||||||
|
rdoc.rdoc_files.include('README*')
|
||||||
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||||
|
end
|
263
bin/svdrpd
Executable file
263
bin/svdrpd
Executable file
|
@ -0,0 +1,263 @@
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
|
||||||
|
require 'socket'
|
||||||
|
require 'syslog'
|
||||||
|
require 'select'
|
||||||
|
|
||||||
|
module Kernel
|
||||||
|
def debug line
|
||||||
|
STDOUT.puts "#{caller[0]}: #{line}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SVDRPC <Select::Socket
|
||||||
|
def initialize opts
|
||||||
|
opts.update( :delimiter => /\r?\n/)
|
||||||
|
@vdr = opts[ :vdr] || raise( ArgumentError, "need VDR")
|
||||||
|
super opts
|
||||||
|
@sock.puts "220 #{ENV["HOSTNAME"]} SVDRP svdrpd 0.0.1; #{Time.now}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_line line
|
||||||
|
if /^\s*quit/i.match line
|
||||||
|
self.quit "quit"
|
||||||
|
else
|
||||||
|
@vdr.push self, line
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_write *args
|
||||||
|
self.close if super( *args).empty? && @quit
|
||||||
|
end
|
||||||
|
|
||||||
|
def quit reason = "unknown reason"
|
||||||
|
@sock.close_read
|
||||||
|
@select.del @sock, :read
|
||||||
|
@quit = true
|
||||||
|
puts "221 #{ENV["HOSTNAME"]} closing connection (#{reason})"
|
||||||
|
rescue IOError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class SVDRPD <Select::Server
|
||||||
|
def initialize opts
|
||||||
|
@vdr = opts[ :vdr] || raise( ArgumentError, "need VDR")
|
||||||
|
super opts
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_new_client sock
|
||||||
|
{ :vdr => @vdr, :clientclass => SVDRPC }
|
||||||
|
end
|
||||||
|
|
||||||
|
def quit reason = "unknown reason"
|
||||||
|
self.close
|
||||||
|
@clients.each do |i|
|
||||||
|
i.quit reason
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class VDR
|
||||||
|
Request = Struct.new :client, :str
|
||||||
|
attr_reader :sock, :serv, :port, :select, :firstline
|
||||||
|
|
||||||
|
def initialize host = 'localhost', port = 2001, select = Select.new
|
||||||
|
@host, @port, @select = host, port, select
|
||||||
|
@quit, @queue = false, []
|
||||||
|
end
|
||||||
|
|
||||||
|
def closed?
|
||||||
|
@sock.nil? || @sock.closed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def disconnect
|
||||||
|
@sock.close unless @sock.nil?
|
||||||
|
end
|
||||||
|
alias :close :disconnect
|
||||||
|
|
||||||
|
def connect
|
||||||
|
@sock = VDR::Socket.new :sock => TCPSocket.new( serv, port), :select => @select, :parent => self
|
||||||
|
@answer = FirstLine.new
|
||||||
|
rescue Errno::ECONNREFUSED
|
||||||
|
retry
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_answer line
|
||||||
|
# Kernel.debug "@answer=#{@answer}"
|
||||||
|
l = /^(\d\d\d)([ -])(.*?)[\n\r]*$/.match line
|
||||||
|
if l.nil?
|
||||||
|
# Kernel.debug "i don't understand this line: #{line}"
|
||||||
|
return
|
||||||
|
elsif l[ 1].to_i == 221
|
||||||
|
else
|
||||||
|
@answer.client.puts l[ 1..-1].to_s
|
||||||
|
self.next true if l[ 2] == ' '
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_client_closed client
|
||||||
|
@queue.unshift @answer unless @answer.nil?
|
||||||
|
@firstline = @sock = nil
|
||||||
|
self.next unless @queue.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def next clear_answer = false
|
||||||
|
# Kernel.debug "@queue = [#{@queue.collect{|i|i.to_s}.join ", "}]; @answer = #{@answer.inspect}"
|
||||||
|
@answer = nil if clear_answer
|
||||||
|
return self.close if @quit
|
||||||
|
return @answer if @answer
|
||||||
|
begin
|
||||||
|
@answer = @queue.shift
|
||||||
|
end while !@answer.nil? && @answer.client.closed?
|
||||||
|
if @answer.nil?
|
||||||
|
elsif self.closed?
|
||||||
|
@queue.unshift @answer
|
||||||
|
self.connect
|
||||||
|
else
|
||||||
|
@sock.puts @answer.str
|
||||||
|
end
|
||||||
|
@answer
|
||||||
|
end
|
||||||
|
|
||||||
|
def push client, str
|
||||||
|
r = Request.new client, str.strip
|
||||||
|
raise "Not a valid String: #{r.str.inject}" if !r.str.kind_of?( String) || r.str.empty?
|
||||||
|
@queue.unshift r
|
||||||
|
self.next
|
||||||
|
end
|
||||||
|
|
||||||
|
def quit
|
||||||
|
unless self.closed?
|
||||||
|
q = Class.new
|
||||||
|
class <<q
|
||||||
|
def client; self; end
|
||||||
|
def closed?; false; end
|
||||||
|
def str; "quit"; end
|
||||||
|
end
|
||||||
|
@queue.unshift q
|
||||||
|
self.next
|
||||||
|
end
|
||||||
|
@quit = true
|
||||||
|
self.closed?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class VDR::Socket <Select::Socket
|
||||||
|
def initialize opts
|
||||||
|
opts.update( :delimiter => /\r?\n/)
|
||||||
|
super opts
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_line line
|
||||||
|
@parent.event_answer line
|
||||||
|
end
|
||||||
|
|
||||||
|
def quit
|
||||||
|
@sock.puts "quit"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class VDR::FirstLine
|
||||||
|
attr_reader :line, :client, :str
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@client = self
|
||||||
|
@str = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def write line
|
||||||
|
@line = line
|
||||||
|
end
|
||||||
|
|
||||||
|
alias :print :write
|
||||||
|
alias :puts :write
|
||||||
|
alias :to_s :line
|
||||||
|
end
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# debug #######################################################################
|
||||||
|
###############################################################################
|
||||||
|
if %W{-D --debug}.include? ARGV[0]
|
||||||
|
ARGV.shift
|
||||||
|
$DEBUG = true
|
||||||
|
end
|
||||||
|
$DEBUG = true if ENV['DEBUG']
|
||||||
|
|
||||||
|
if $DEBUG
|
||||||
|
def debug_func c, f
|
||||||
|
ff = case f
|
||||||
|
when /^(.*)\?$/ then "#{$1}_f"
|
||||||
|
when /^(.*)\!$/ then "#{$1}_a"
|
||||||
|
when "<<" then "_s"
|
||||||
|
when "+" then "_p"
|
||||||
|
when "-" then "_m"
|
||||||
|
when "@+" then "_P"
|
||||||
|
when "@-" then "_M"
|
||||||
|
else "#{f}_n"
|
||||||
|
end
|
||||||
|
wf = "__wrapped_#{c.object_id.to_s.sub /^-/, "x"}_#{ff}__".intern
|
||||||
|
return "#{c}##{wf} already exists" if c.instance_methods.include? wf
|
||||||
|
pre = "\#{\"%x\"%self.hash.abs}:#{c}##{f}"
|
||||||
|
c.class_eval <<-EOF
|
||||||
|
alias :#{wf} :#{f}
|
||||||
|
def #{f} *args, &e
|
||||||
|
ret = if e
|
||||||
|
STDERR.puts "==>#{pre} \#{args.collect {|i| i.inspect }.join ", "}, &\#{e.inspect}"
|
||||||
|
#{wf} *args, &e
|
||||||
|
else
|
||||||
|
STDERR.puts "==>#{pre} \#{args.collect {|i| i.inspect }.join ", "}"
|
||||||
|
#{wf} *args
|
||||||
|
end
|
||||||
|
#STDERR.puts "<==#{pre}"
|
||||||
|
ret
|
||||||
|
rescue
|
||||||
|
STDERR.puts "<==#{pre} EXCEPTION: \#{$!.inspect}"
|
||||||
|
Kernel.raise
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
|
||||||
|
def debug_class c, fs
|
||||||
|
c.instance_methods.grep fs do |f|
|
||||||
|
debug_func c, f
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
debug_class Select, /_set|_del$/
|
||||||
|
debug_class Select::Socket, /^event_.*|write|print|init|close$/
|
||||||
|
debug_class Select::Server, /^event_.*|close|init$/
|
||||||
|
debug_class VDR, /^event_.*|next|push|connect|close|disconnect$/
|
||||||
|
debug_class VDR::Socket, /^event_.*|close|init$/
|
||||||
|
debug_class SVDRPD, /^event_.*|init$/
|
||||||
|
debug_class SVDRPC, /^event_.*|init$/
|
||||||
|
debug_class VDR::FirstLine, /^write|print|puts$/
|
||||||
|
end
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# main ########################################################################
|
||||||
|
###############################################################################
|
||||||
|
opts = {
|
||||||
|
:vdraddr => ARGV[0] || 'localhost',
|
||||||
|
:vdrport => ARGV[1] || 2002,
|
||||||
|
:servaddr => ARGV[2] || 'localhost',
|
||||||
|
:servport => ARGV[3] || 2001
|
||||||
|
}
|
||||||
|
|
||||||
|
Syslog.open 'svdrpd', Syslog::LOG_NDELAY | Syslog::LOG_PERROR,
|
||||||
|
Syslog::LOG_DAEMON
|
||||||
|
|
||||||
|
begin
|
||||||
|
$select = Select.new
|
||||||
|
$select.timeout 5*60
|
||||||
|
|
||||||
|
$vdr = VDR.new opts[ :vdraddr], opts[ :vdrport], $select
|
||||||
|
$serv = SVDRPD.new :vdr => $vdr, :sock => TCPServer.new( opts[ :servaddr], opts[ :servport]), :select => $select
|
||||||
|
$select.exit_on_empty = true
|
||||||
|
|
||||||
|
$serv.run
|
||||||
|
rescue Object
|
||||||
|
Syslog.err "#{$!} (#{$!.class}) -- #{$!.backtrace.join ' -- '}"
|
||||||
|
$serv.quit "server shuting down"
|
||||||
|
$vdr.quit
|
||||||
|
retry
|
||||||
|
end
|
44
svdrpd.gemspec
Normal file
44
svdrpd.gemspec
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# Generated by jeweler
|
||||||
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
|
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
|
Gem::Specification.new do |s|
|
||||||
|
s.name = %q{svdrpd}
|
||||||
|
s.version = "0.1.0"
|
||||||
|
|
||||||
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||||
|
s.authors = ["Denis Knauf"]
|
||||||
|
s.date = %q{2010-02-26}
|
||||||
|
s.default_executable = %q{svdrpd}
|
||||||
|
s.description = %q{Allowes to more than one connection to communicate with VDR}
|
||||||
|
s.email = %q{Denis.Knauf@gmail.com}
|
||||||
|
s.executables = ["svdrpd"]
|
||||||
|
s.extra_rdoc_files = [
|
||||||
|
"README.md"
|
||||||
|
]
|
||||||
|
s.files = [
|
||||||
|
"README.md",
|
||||||
|
"VERSION",
|
||||||
|
"bin/svdrpd"
|
||||||
|
]
|
||||||
|
s.homepage = %q{http://github.com/DenisKnauf/svdrpd}
|
||||||
|
s.rdoc_options = ["--charset=UTF-8"]
|
||||||
|
s.require_paths = ["bin"]
|
||||||
|
s.rubygems_version = %q{1.3.5}
|
||||||
|
s.summary = %q{Multiplexer for SVDRP}
|
||||||
|
|
||||||
|
if s.respond_to? :specification_version then
|
||||||
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
||||||
|
s.specification_version = 3
|
||||||
|
|
||||||
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
||||||
|
s.add_runtime_dependency(%q<select>, [">= 0"])
|
||||||
|
else
|
||||||
|
s.add_dependency(%q<select>, [">= 0"])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
s.add_dependency(%q<select>, [">= 0"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in a new issue