1require 'webrick'
2require 'drb/drb'
3require 'drb/http0'
4require 'thread'
5
6module DRb
7  module HTTP0
8
9    def self.open_server(uri, config)
10      unless /^http:/ =~ uri
11	raise(DRbBadScheme, uri) unless uri =~ /^http:/
12	raise(DRbBadURI, 'can\'t parse uri:' + uri)
13      end
14      Server.new(uri, config)
15    end
16
17    class Callback < WEBrick::HTTPServlet::AbstractServlet
18      def initialize(config, drb)
19	@config = config
20	@drb = drb
21	@queue = Queue.new
22      end
23
24      def do_POST(req, res)
25	@req = req
26	@res = res
27	@drb.push(self)
28	@res.body = @queue.pop
29	@res['content-type'] = 'application/octet-stream;'
30      end
31
32      def req_body
33	@req.body
34      end
35
36      def reply(body)
37	@queue.push(body)
38      end
39
40      def close
41	@queue.push('')
42      end
43    end
44
45    class Server
46      def initialize(uri, config)
47	@uri = uri
48	@config = config
49	@queue = Queue.new
50	setup_webrick(uri)
51      end
52      attr_reader :uri
53
54      def close
55	@server.shutdown if @server
56	@server = nil
57      end
58
59      def push(callback)
60	@queue.push(callback)
61      end
62
63      def accept
64	client = @queue.pop
65	ServerSide.new(client, @config)
66      end
67
68      def setup_webrick(uri)
69	logger = WEBrick::Log::new($stderr, WEBrick::Log::FATAL)
70	u = URI.parse(uri)
71	s = WEBrick::HTTPServer.new(:Port => u.port,
72				    :AddressFamily => Socket::AF_INET,
73				    :BindAddress => u.host,
74				    :Logger => logger,
75				    :ServerType => Thread)
76	s.mount(u.path, Callback, self)
77	@server = s
78	s.start
79      end
80    end
81
82    class ServerSide
83      def initialize(callback, config)
84	@callback = callback
85	@config = config
86	@msg = DRbMessage.new(@config)
87	@req_stream = StrStream.new(@callback.req_body)
88      end
89
90      def close
91	@callback.close if @callback
92	@callback = nil
93      end
94
95      def alive?; false; end
96
97      def recv_request
98	begin
99	  @msg.recv_request(@req_stream)
100	rescue
101	  close
102	  raise $!
103	end
104      end
105
106      def send_reply(succ, result)
107	begin
108	  return unless @callback
109	  stream = StrStream.new
110	  @msg.send_reply(stream, succ, result)
111	  @callback.reply(stream.buf)
112	rescue
113	  close
114	  raise $!
115	end
116      end
117    end
118  end
119end
120