# A simple IPC server executing Ruby programs.
require 'thread'
-require 'stringio'
class RubyServ
+ module C
+ end
+
def initialize
- @buf = StringIO.new
+ @buf = ''
@que = Queue.new
@thr = Hash.new
+ @cnt = 0
end
def dispatch(line)
case line.chomp
when /\AD /
- @buf << unescape($')
+ @buf << $'
when /\A(\S+)\s*/
c = $1
r = $'
end
def dispatch_eval(c, r)
- name, code = r.split(/\s+/, 2)
- if @thr.include?(name) && @thr[name].alive?
- puts("ERR 105 Parameter error: \"#{name}\" is already in use\r\n")
- return
+ r = deq_data if r.empty?
+ name = nil
+ Thread.exclusive do
+ while @thr.include?(name = @cnt.to_s)
+ @cnt += 1
+ end
+ @thr[name] = Thread.current
end
- code = deq_data unless code
+ puts("S name #{name}\r\n")
puts("OK\r\n")
- @thr[name] = Thread.current
Thread.current[:rubyserv_name] = name
begin
Thread.current[:rubyserv_error] = false
- Thread.current[:rubyserv_response] = eval(code)
+ Thread.current[:rubyserv_response] = eval(r, C.module_eval('binding()'))
rescue Exception => e
Thread.current[:rubyserv_error] = true
Thread.current[:rubyserv_response] = e
end
- puts("# exited #{name}\r\n")
+ puts("# exit #{name}\r\n")
end
def dispatch_poll(c, r)
if !thr
puts("ERR 105 Parameter error: no such name \"#{r}\"\r\n")
elsif thr.alive?
- puts("S running\r\n")
+ puts("S running #{r}\r\n")
puts("OK\r\n")
else
- @thr.delete(r)
if thr[:rubyserv_error]
- puts("S exited\r\n")
+ puts("S exited #{r}\r\n")
else
- puts("S finished\r\n")
+ puts("S finished #{r}\r\n")
end
if d = thr[:rubyserv_response]
send_data(d.to_s)
end
end
+ def dispatch_exit(c, r)
+ thr = @thr[r]
+ if !thr
+ puts("ERR 105 Parameter error: no such name \"#{r}\"\r\n")
+ return
+ end
+ thr.kill if thr.alive?
+ @thr.delete(r)
+ puts("OK\r\n")
+ end
+
def escape(s)
s.gsub(/[%\r\n]/) {|m| '%%%02X' % m[0]}
end
end
def enq_data
- @que.enq(@buf.string)
+ d = unescape(@buf)
+ @buf = ''
+ @que.enq(d)
end
def deq_data