summaryrefslogtreecommitdiff
path: root/sample/drb/http0serv.rb
blob: 2e853312e12a6c62e2cf38e48e45367d626aa619 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
require 'webrick'
require 'drb/drb'
require_relative 'http0'

module DRb
  module HTTP0

    def self.open_server(uri, config)
      unless /^http:/ =~ uri
        raise(DRbBadScheme, uri) unless uri =~ /^http:/
        raise(DRbBadURI, 'can\'t parse uri:' + uri)
      end
      Server.new(uri, config)
    end

    class Callback < WEBrick::HTTPServlet::AbstractServlet
      def initialize(config, drb)
        @config = config
        @drb = drb
        @queue = Thread::Queue.new
      end

      def do_POST(req, res)
        @req = req
        @res = res
        @drb.push(self)
        @res.body = @queue.pop
        @res['content-type'] = 'application/octet-stream;'
      end

      def req_body
        @req.body
      end

      def reply(body)
        @queue.push(body)
      end

      def close
        @queue.push('')
      end
    end

    class Server
      def initialize(uri, config)
        @uri = uri
        @config = config
        @queue = Thread::Queue.new
        setup_webrick(uri)
      end
      attr_reader :uri

      def close
        @server.shutdown if @server
        @server = nil
      end

      def push(callback)
        @queue.push(callback)
      end

      def accept
        client = @queue.pop
        ServerSide.new(uri, client, @config)
      end

      def setup_webrick(uri)
        logger = WEBrick::Log::new($stderr, WEBrick::Log::FATAL)
        u = URI.parse(uri)
        s = WEBrick::HTTPServer.new(:Port => u.port,
          :AddressFamily => Socket::AF_INET,
          :BindAddress => u.host,
          :Logger => logger,
          :ServerType => Thread)
        s.mount(u.path, Callback, self)
        @server = s
        s.start
      end
    end

    class ServerSide
      def initialize(uri, callback, config)
        @uri = uri
        @callback = callback
        @config = config
        @msg = DRbMessage.new(@config)
        @req_stream = StrStream.new(@callback.req_body)
      end
      attr_reader :uri

      def close
        @callback.close if @callback
        @callback = nil
      end

      def alive?; false; end

      def recv_request
        begin
          @msg.recv_request(@req_stream)
        rescue
          close
          raise $!
        end
      end

      def send_reply(succ, result)
        begin
          return unless @callback
          stream = StrStream.new
          @msg.send_reply(stream, succ, result)
          @callback.reply(stream.buf)
        rescue
          close
          raise $!
        end
      end
    end
  end
end