* rubyserv.rb: New file.
authorDaiki Ueno <ueno@unixuser.org>
Tue, 22 Mar 2005 08:57:10 +0000 (08:57 +0000)
committerDaiki Ueno <ueno@unixuser.org>
Tue, 22 Mar 2005 08:57:10 +0000 (08:57 +0000)
lisp/ChangeLog
lisp/rubyserv.rb [new file with mode: 0644]

index be8b40d..7036259 100644 (file)
@@ -1,3 +1,7 @@
+2005-03-22  Daiki Ueno  <ueno@unixuser.org>
+
+       * rubyserv.rb: New file.
+
 2005-03-20  Daiki Ueno  <ueno@unixuser.org>
 
        * riece-toolbar.el [XEmacs] (riece-make-toolbar-from-menu):
diff --git a/lisp/rubyserv.rb b/lisp/rubyserv.rb
new file mode 100644 (file)
index 0000000..d3a82ff
--- /dev/null
@@ -0,0 +1,112 @@
+# A simple IPC server for executing arbitrary Ruby program.
+# The protocol is based on Assuan protocol of GnuPG.
+
+require 'thread'
+require 'stringio'
+
+class RubyServ
+  def initialize
+    @buf = StringIO.new
+    @que = Queue.new
+  end
+
+  def dispatch(line)
+    case line.chomp
+    when /\AD /
+      return @buf << unescape($')
+    when /\A(\S+)\s*/
+      c = $1
+      r = $'
+      d = "dispatch_#{c.downcase}"
+      if respond_to?(d, true)
+        Thread.start do
+          self.send(d, c, r)
+        end
+      else
+        puts("ERR 103 Unknown command\r\n")
+      end
+    end
+  end
+
+  def dispatch_cancel(c, r)
+    puts("ERR 100 Not implemented\r\n")
+  end
+
+  def dispatch_bye(c, r)
+    puts("ERR 100 Not implemented\r\n")
+  end
+
+  def dispatch_auth(c, r)
+    puts("ERR 100 Not implemented\r\n")
+  end
+
+  def dispatch_reset(c, r)
+    puts("ERR 100 Not implemented\r\n")
+  end
+
+  def dispatch_end(c, r)
+    enq_data
+  end
+
+  def dispatch_help(c, r)
+    puts("ERR 100 Not implemented\r\n")
+  end
+
+  def dispatch_quit(c, r)
+    puts("ERR 100 Not implemented\r\n")
+  end
+
+  def dispatch_eval(c, r)
+    r = deq_data if r.empty?
+    p r
+    open('|-') do |f|
+      if f
+        d = f.read
+        Process.wait
+        send_data(d)
+        if $?.success?
+          puts("OK\r\n")
+        else
+          puts("ERR #{$?.exitstatus}\r\n")
+        end
+      else
+        eval(r)
+        exit
+      end
+    end
+  end
+
+  def escape(s)
+    s.gsub(/[%\r\n]/) {|m| '%%%02X' % m[0]}
+  end
+
+  def unescape(s)
+    s.gsub(/%([0-9A-Z][0-9A-Z])/, ['\1'].pack('H*'))
+  end
+
+  def send_data(d)
+    begin
+      r = [d.length, 998].min   # 998 = 1000 - CRLF
+      (0 ... r).each do |i|
+        r -= 2 if d[i] =~ /[%\r\n]/
+      end
+      puts("D #{escape(d[0 ... r])}\r\n")
+      d = d[r .. -1]
+    end until d.empty?
+  end
+
+  def enq_data
+    @que.enq(@buf.string)
+  end
+
+  def deq_data
+    @que.deq
+  end
+end
+
+if $0 == __FILE__
+  serv = RubyServ.new
+  while gets
+    serv.dispatch($_)
+  end
+end