Fixed.
[riece] / lisp / rubyserv.rb
1 # A simple IPC server executing arbitrary Ruby program.
2
3 # The protocol is based on Assuan protocol of GnuPG.
4 # http://www.gnupg.org/(en)/related_software/libassuan/index.html
5
6 require 'thread'
7 require 'stringio'
8
9 class RubyServ
10   def initialize
11     @buf = StringIO.new
12     @que = Queue.new
13   end
14
15   def dispatch(line)
16     case line.chomp
17     when /\AD /
18       @buf << unescape($')
19     when /\A(\S+)\s*/
20       c = $1
21       r = $'
22       d = "dispatch_#{c.downcase}"
23       if respond_to?(d, true)
24         Thread.start do
25           self.send(d, c, r)
26         end
27       else
28         puts("ERR 103 Unknown command\r\n")
29       end
30     end
31   end
32
33   def dispatch_cancel(c, r)
34     puts("ERR 100 Not implemented\r\n")
35   end
36
37   def dispatch_bye(c, r)
38     puts("ERR 100 Not implemented\r\n")
39   end
40
41   def dispatch_auth(c, r)
42     puts("ERR 100 Not implemented\r\n")
43   end
44
45   def dispatch_reset(c, r)
46     puts("ERR 100 Not implemented\r\n")
47   end
48
49   def dispatch_end(c, r)
50     enq_data
51   end
52
53   def dispatch_help(c, r)
54     puts("ERR 100 Not implemented\r\n")
55   end
56
57   def dispatch_quit(c, r)
58     puts("ERR 100 Not implemented\r\n")
59   end
60
61   def dispatch_eval(c, r)
62     r = deq_data if r.empty?
63     open('|-') do |f|
64       if f
65         d = f.read
66         Process.wait
67         send_data(d) if d
68         if $?.success?
69           puts("OK\r\n")
70         else
71           puts("ERR #{$?.exitstatus}\r\n")
72         end
73       else
74         eval(r)
75         exit
76       end
77     end
78   end
79
80   def escape(s)
81     s.gsub(/[%\r\n]/) {|m| '%%%02X' % m[0]}
82   end
83
84   def unescape(s)
85     s.gsub(/%([0-9A-Z][0-9A-Z])/, ['\1'].pack('H*'))
86   end
87
88   def send_data(d)
89     d = escape(d)
90     begin
91       len = [d.length, 998].min   # 998 = 1000 - "D "
92       puts("D #{d[0 ... len]}\r\n")
93       d = d[len .. -1]
94     end until d.empty?
95   end
96
97   def enq_data
98     @que.enq(@buf.string)
99   end
100
101   def deq_data
102     @que.deq
103   end
104 end
105
106 if $0 == __FILE__
107   serv = RubyServ.new
108   while gets
109     serv.dispatch($_)
110   end
111 end