eventmachine 0.12.6 → 0.12.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/{docs/README → README} +21 -13
  2. data/Rakefile +14 -4
  3. data/docs/DEFERRABLES +0 -5
  4. data/docs/INSTALL +2 -4
  5. data/docs/LEGAL +1 -1
  6. data/docs/LIGHTWEIGHT_CONCURRENCY +0 -2
  7. data/docs/PURE_RUBY +0 -2
  8. data/docs/RELEASE_NOTES +0 -2
  9. data/docs/SMTP +0 -7
  10. data/docs/SPAWNED_PROCESSES +0 -4
  11. data/docs/TODO +0 -2
  12. data/eventmachine.gemspec +17 -8
  13. data/examples/ex_channel.rb +43 -0
  14. data/examples/ex_queue.rb +2 -0
  15. data/examples/helper.rb +2 -0
  16. data/ext/cmain.cpp +119 -20
  17. data/ext/cplusplus.cpp +15 -6
  18. data/ext/ed.cpp +303 -93
  19. data/ext/ed.h +49 -22
  20. data/ext/em.cpp +368 -42
  21. data/ext/em.h +43 -6
  22. data/ext/eventmachine.h +21 -8
  23. data/ext/eventmachine_cpp.h +1 -0
  24. data/ext/extconf.rb +4 -0
  25. data/ext/kb.cpp +1 -2
  26. data/ext/pipe.cpp +1 -3
  27. data/ext/project.h +21 -0
  28. data/ext/rubymain.cpp +232 -32
  29. data/ext/ssl.cpp +38 -1
  30. data/ext/ssl.h +5 -1
  31. data/java/src/com/rubyeventmachine/Application.java +7 -3
  32. data/java/src/com/rubyeventmachine/EmReactor.java +16 -1
  33. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +25 -3
  34. data/lib/{protocols → em}/buftok.rb +16 -5
  35. data/lib/em/callback.rb +26 -0
  36. data/lib/em/channel.rb +57 -0
  37. data/lib/em/connection.rb +505 -0
  38. data/lib/em/deferrable.rb +144 -165
  39. data/lib/em/file_watch.rb +54 -0
  40. data/lib/em/future.rb +24 -25
  41. data/lib/em/messages.rb +1 -1
  42. data/lib/em/process_watch.rb +44 -0
  43. data/lib/em/processes.rb +58 -52
  44. data/lib/em/protocols.rb +35 -0
  45. data/lib/em/protocols/header_and_content.rb +138 -0
  46. data/lib/em/protocols/httpclient.rb +263 -0
  47. data/lib/em/protocols/httpclient2.rb +582 -0
  48. data/lib/{protocols → em/protocols}/line_and_text.rb +2 -2
  49. data/lib/em/protocols/linetext2.rb +160 -0
  50. data/lib/{protocols → em/protocols}/memcache.rb +37 -7
  51. data/lib/em/protocols/object_protocol.rb +39 -0
  52. data/lib/em/protocols/postgres3.rb +247 -0
  53. data/lib/em/protocols/saslauth.rb +175 -0
  54. data/lib/em/protocols/smtpclient.rb +331 -0
  55. data/lib/em/protocols/smtpserver.rb +547 -0
  56. data/lib/em/protocols/stomp.rb +200 -0
  57. data/lib/{protocols → em/protocols}/tcptest.rb +21 -25
  58. data/lib/em/queue.rb +61 -0
  59. data/lib/em/spawnable.rb +53 -56
  60. data/lib/em/streamer.rb +92 -74
  61. data/lib/em/timers.rb +55 -0
  62. data/lib/em/version.rb +3 -0
  63. data/lib/eventmachine.rb +1008 -1298
  64. data/lib/evma.rb +1 -1
  65. data/lib/jeventmachine.rb +106 -101
  66. data/lib/pr_eventmachine.rb +47 -36
  67. data/tasks/project.rake +2 -1
  68. data/tests/client.crt +31 -0
  69. data/tests/client.key +51 -0
  70. data/tests/test_attach.rb +18 -0
  71. data/tests/test_basic.rb +108 -54
  72. data/tests/test_channel.rb +63 -0
  73. data/tests/test_connection_count.rb +2 -2
  74. data/tests/test_epoll.rb +109 -110
  75. data/tests/test_errors.rb +36 -36
  76. data/tests/test_exc.rb +22 -25
  77. data/tests/test_file_watch.rb +49 -0
  78. data/tests/test_futures.rb +77 -93
  79. data/tests/test_hc.rb +2 -2
  80. data/tests/test_httpclient.rb +55 -52
  81. data/tests/test_httpclient2.rb +110 -112
  82. data/tests/test_inactivity_timeout.rb +30 -0
  83. data/tests/test_kb.rb +8 -9
  84. data/tests/test_ltp2.rb +274 -277
  85. data/tests/test_next_tick.rb +91 -65
  86. data/tests/test_object_protocol.rb +37 -0
  87. data/tests/test_process_watch.rb +48 -0
  88. data/tests/test_processes.rb +56 -23
  89. data/tests/test_proxy_connection.rb +92 -0
  90. data/tests/test_pure.rb +1 -5
  91. data/tests/test_queue.rb +44 -0
  92. data/tests/test_running.rb +9 -14
  93. data/tests/test_sasl.rb +32 -34
  94. data/tests/test_send_file.rb +175 -176
  95. data/tests/test_servers.rb +37 -41
  96. data/tests/test_smtpserver.rb +47 -55
  97. data/tests/test_spawn.rb +284 -291
  98. data/tests/test_ssl_args.rb +1 -1
  99. data/tests/test_ssl_methods.rb +1 -1
  100. data/tests/test_ssl_verify.rb +82 -0
  101. data/tests/test_timers.rb +81 -88
  102. data/tests/test_ud.rb +0 -7
  103. data/tests/testem.rb +1 -1
  104. metadata +68 -39
  105. data/lib/em/eventable.rb +0 -39
  106. data/lib/eventmachine_version.rb +0 -31
  107. data/lib/protocols/header_and_content.rb +0 -129
  108. data/lib/protocols/httpcli2.rb +0 -803
  109. data/lib/protocols/httpclient.rb +0 -270
  110. data/lib/protocols/linetext2.rb +0 -161
  111. data/lib/protocols/postgres.rb +0 -261
  112. data/lib/protocols/saslauth.rb +0 -179
  113. data/lib/protocols/smtpclient.rb +0 -308
  114. data/lib/protocols/smtpserver.rb +0 -556
  115. data/lib/protocols/stomp.rb +0 -153
  116. data/tests/test_eventables.rb +0 -77
@@ -1,4 +1,4 @@
1
- # $Id$
1
+ #--
2
2
  #
3
3
  # Author:: Francis Cianfrocca (gmail: blackhedd)
4
4
  # Homepage:: http://rubyeventmachine.com
@@ -23,7 +23,7 @@
23
23
  #
24
24
  #
25
25
  #
26
- require File.dirname(__FILE__) + '/buftok'
26
+ require File.dirname(__FILE__) + '/../buftok'
27
27
 
28
28
  module EventMachine
29
29
  module Protocols
@@ -0,0 +1,160 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 15 November 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ module EventMachine
27
+ module Protocols
28
+ # In the grand, time-honored tradition of re-inventing the wheel, we offer
29
+ # here YET ANOTHER protocol that handles line-oriented data with interspersed
30
+ # binary text. This one trades away some of the performance optimizations of
31
+ # EventMachine::Protocols::LineAndTextProtocol in order to get better correctness
32
+ # with regard to binary text blocks that can switch back to line mode. It also
33
+ # permits the line-delimiter to change in midstream.
34
+ # This was originally written to support Stomp.
35
+ module LineText2
36
+ # TODO! We're not enforcing the limits on header lengths and text-lengths.
37
+ # When we get around to that, call #receive_error if the user defined it, otherwise
38
+ # throw exceptions.
39
+
40
+ MaxLineLength = 16*1024
41
+ MaxBinaryLength = 32*1024*1024
42
+
43
+ #--
44
+ # Will be called recursively until there's no data to read.
45
+ # That way the user-defined handlers we call can modify the
46
+ # handling characteristics on a per-token basis.
47
+ #
48
+ def receive_data data
49
+ return unless (data and data.length > 0)
50
+
51
+ # Do this stuff in lieu of a constructor.
52
+ @lt2_mode ||= :lines
53
+ @lt2_delimiter ||= "\n"
54
+ @lt2_linebuffer ||= []
55
+
56
+ if @lt2_mode == :lines
57
+ if ix = data.index( @lt2_delimiter )
58
+ @lt2_linebuffer << data[0...ix]
59
+ ln = @lt2_linebuffer.join
60
+ @lt2_linebuffer.clear
61
+ if @lt2_delimiter == "\n"
62
+ ln.chomp!
63
+ end
64
+ receive_line ln
65
+ receive_data data[(ix+@lt2_delimiter.length)..-1]
66
+ else
67
+ @lt2_linebuffer << data
68
+ end
69
+ elsif @lt2_mode == :text
70
+ if @lt2_textsize
71
+ needed = @lt2_textsize - @lt2_textpos
72
+ will_take = if data.length > needed
73
+ needed
74
+ else
75
+ data.length
76
+ end
77
+
78
+ @lt2_textbuffer << data[0...will_take]
79
+ tail = data[will_take..-1]
80
+
81
+ @lt2_textpos += will_take
82
+ if @lt2_textpos >= @lt2_textsize
83
+ # Reset line mode (the default behavior) BEFORE calling the
84
+ # receive_binary_data. This makes it possible for user code
85
+ # to call set_text_mode, enabling chains of text blocks
86
+ # (which can possibly be of different sizes).
87
+ set_line_mode
88
+ receive_binary_data @lt2_textbuffer.join
89
+ receive_end_of_binary_data
90
+ end
91
+
92
+ receive_data tail
93
+ else
94
+ receive_binary_data data
95
+ end
96
+ end
97
+ end
98
+
99
+
100
+ def set_delimiter delim
101
+ @lt2_delimiter = delim.to_s
102
+ end
103
+
104
+ # Called internally but also exposed to user code, for the case in which
105
+ # processing of binary data creates a need to transition back to line mode.
106
+ # We support an optional parameter to "throw back" some data, which might
107
+ # be an umprocessed chunk of the transmitted binary data, or something else
108
+ # entirely.
109
+ def set_line_mode data=""
110
+ @lt2_mode = :lines
111
+ (@lt2_linebuffer ||= []).clear
112
+ receive_data data.to_s
113
+ end
114
+
115
+ def set_text_mode size=nil
116
+ if size == 0
117
+ set_line_mode
118
+ else
119
+ @lt2_mode = :text
120
+ (@lt2_textbuffer ||= []).clear
121
+ @lt2_textsize = size # which can be nil, signifying no limit
122
+ @lt2_textpos = 0
123
+ end
124
+ end
125
+
126
+ # Alias for #set_text_mode, added for back-compatibility with LineAndTextProtocol.
127
+ def set_binary_mode size=nil
128
+ set_text_mode size
129
+ end
130
+
131
+ # In case of a dropped connection, we'll send a partial buffer to user code
132
+ # when in sized text mode. User overrides of #receive_binary_data need to
133
+ # be aware that they may get a short buffer.
134
+ def unbind
135
+ if @lt2_mode == :text and @lt2_textpos > 0
136
+ receive_binary_data @lt2_textbuffer.join
137
+ end
138
+ end
139
+
140
+ # Stub. Should be subclassed by user code.
141
+ def receive_line ln
142
+ # no-op
143
+ end
144
+
145
+ # Stub. Should be subclassed by user code.
146
+ def receive_binary_data data
147
+ # no-op
148
+ end
149
+
150
+ # Stub. Should be subclassed by user code.
151
+ # This is called when transitioning internally from text mode
152
+ # back to line mode. Useful when client code doesn't want
153
+ # to keep track of how much data it's received.
154
+ def receive_end_of_binary_data
155
+ # no-op
156
+ end
157
+ end
158
+ end
159
+ end
160
+
@@ -32,6 +32,7 @@ module EventMachine
32
32
  ##
33
33
  # constants
34
34
 
35
+ # :stopdoc:
35
36
  unless defined? Cempty
36
37
  Cstored = 'STORED'.freeze
37
38
  Cend = 'END'.freeze
@@ -42,10 +43,16 @@ module EventMachine
42
43
  Cempty = ''.freeze
43
44
  Cdelimiter = "\r\n".freeze
44
45
  end
46
+ # :startdoc:
45
47
 
46
48
  ##
47
49
  # commands
48
50
 
51
+ # Get the value associated with one or multiple keys
52
+ #
53
+ # cache.get(:a){ |v| p v }
54
+ # cache.get(:a,:b,:c,:d){ |a,b,c,d| p [a,b,c,d] }
55
+ #
49
56
  def get *keys
50
57
  raise ArgumentError unless block_given?
51
58
 
@@ -58,6 +65,11 @@ module EventMachine
58
65
  }
59
66
  end
60
67
 
68
+ # Set the value for a given key
69
+ #
70
+ # cache.set :a, 'hello'
71
+ # cache.set(:missing, 'abc'){ puts "stored the value!" }
72
+ #
61
73
  def set key, val, exptime = 0, &cb
62
74
  callback{
63
75
  val = val.to_s
@@ -68,6 +80,10 @@ module EventMachine
68
80
  }
69
81
  end
70
82
 
83
+ # Gets multiple values as a hash
84
+ #
85
+ # cache.get_hash(:a, :b, :c, :d){ |h| puts h[:a] }
86
+ #
71
87
  def get_hash *keys
72
88
  raise ArgumentError unless block_given?
73
89
 
@@ -76,6 +92,11 @@ module EventMachine
76
92
  end
77
93
  end
78
94
 
95
+ # Delete the value associated with a key
96
+ #
97
+ # cache.del :a
98
+ # cache.del(:b){ puts "deleted the value!" }
99
+ #
79
100
  def delete key, expires = 0, &cb
80
101
  callback{
81
102
  send_data "delete #{key} #{expires}#{cb ? '' : ' noreply'}\r\n"
@@ -84,7 +105,14 @@ module EventMachine
84
105
  end
85
106
  alias del delete
86
107
 
87
- def send_cmd cmd, key, flags = 0, exptime = 0, bytes = 0, noreply = false
108
+ # Connect to a memcached server (must support NOREPLY, memcached >= 1.2.4)
109
+ def self.connect host = 'localhost', port = 11211
110
+ EM.connect host, port, self, host, port
111
+ end
112
+
113
+ # :stopdoc:
114
+
115
+ def send_cmd cmd, key, flags = 0, exptime = 0, bytes = 0, noreply = false # :nodoc:
88
116
  send_data "#{cmd} #{key} #{flags} #{exptime} #{bytes}#{noreply ? ' noreply' : ''}\r\n"
89
117
  end
90
118
  private :send_cmd
@@ -92,15 +120,12 @@ module EventMachine
92
120
  ##
93
121
  # errors
94
122
 
95
- class ParserError < StandardError; end
123
+ class ParserError < StandardError
124
+ end
96
125
 
97
126
  ##
98
127
  # em hooks
99
128
 
100
- def self.connect host = 'localhost', port = 11211
101
- EM.connect host, port, self, host, port
102
- end
103
-
104
129
  def initialize host, port = 11211
105
130
  @host, @port = host, port
106
131
  end
@@ -119,6 +144,7 @@ module EventMachine
119
144
  # set_line_mode
120
145
  end
121
146
 
147
+ #--
122
148
  # 19Feb09 Switched to a custom parser, LineText2 is recursive and can cause
123
149
  # stack overflows when there is too much data.
124
150
  # include EM::P::LineText2
@@ -136,6 +162,7 @@ module EventMachine
136
162
  end
137
163
  end
138
164
 
165
+ #--
139
166
  # def receive_line line
140
167
  def process_cmd line
141
168
  case line.strip
@@ -177,6 +204,7 @@ module EventMachine
177
204
  end
178
205
  end
179
206
 
207
+ #--
180
208
  # def receive_binary_data data
181
209
  # @values[@cur_key] = data[0..-3]
182
210
  # end
@@ -191,6 +219,8 @@ module EventMachine
191
219
  raise 'Unable to connect to memcached server'
192
220
  end
193
221
  end
222
+
223
+ # :startdoc:
194
224
  end
195
225
  end
196
226
  end
@@ -199,7 +229,7 @@ if __FILE__ == $0
199
229
  # ruby -I ext:lib -r eventmachine -rubygems lib/protocols/memcache.rb
200
230
  require 'em/spec'
201
231
 
202
- class TestConnection
232
+ class TestConnection # :nodoc:
203
233
  include EM::P::Memcache
204
234
  def send_data data
205
235
  sent_data << data
@@ -0,0 +1,39 @@
1
+ module EventMachine
2
+ module Protocols
3
+ # ObjectProtocol allows for easy communication using marshaled ruby objects
4
+ #
5
+ # module RubyServer
6
+ # include EM::P::ObjectProtocol
7
+ #
8
+ # def receive_object obj
9
+ # send_object({'you said' => obj})
10
+ # end
11
+ # end
12
+ #
13
+ module ObjectProtocol
14
+ def receive_data data # :nodoc:
15
+ (@buf ||= '') << data
16
+
17
+ while @buf.size >= 4
18
+ if @buf.size >= 4+(size=@buf.unpack('N').first)
19
+ @buf.slice!(0,4)
20
+ receive_object Marshal.load(@buf.slice!(0,size))
21
+ else
22
+ break
23
+ end
24
+ end
25
+ end
26
+
27
+ # Invoked with ruby objects received over the network
28
+ def receive_object obj
29
+ # stub
30
+ end
31
+
32
+ # Sends a ruby object over the network
33
+ def send_object obj
34
+ data = Marshal.dump(obj)
35
+ send_data [data.respond_to?(:bytesize) ? data.bytesize : data.size, data].pack('Na*')
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,247 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 15 November 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-08 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+
27
+ require 'readbytes'
28
+ require 'postgres-pr/message'
29
+ require 'postgres-pr/connection'
30
+ require 'stringio'
31
+
32
+ class StringIO # :nodoc:
33
+ # Reads exactly +n+ bytes.
34
+ #
35
+ # If the data read is nil an EOFError is raised.
36
+ #
37
+ # If the data read is too short a TruncatedDataError is raised and the read
38
+ # data is obtainable via its #data method.
39
+ def readbytes(n)
40
+ str = read(n)
41
+ if str == nil
42
+ raise EOFError, "End of file reached"
43
+ end
44
+ if str.size < n
45
+ raise TruncatedDataError.new("data truncated", str)
46
+ end
47
+ str
48
+ end
49
+ alias read_exactly_n_bytes readbytes
50
+ end
51
+
52
+
53
+ module EventMachine
54
+ module Protocols
55
+ # PROVISIONAL IMPLEMENTATION of an evented Postgres client.
56
+ # This implements version 3 of the Postgres wire protocol, which will work
57
+ # with any Postgres version from roughly 7.4 onward.
58
+ #
59
+ # Objective: we want to access Postgres databases without requiring threads.
60
+ # Until now this has been a problem because the Postgres client implementations
61
+ # have all made use of blocking I/O calls, which is incompatible with a
62
+ # thread-free evented model.
63
+ #
64
+ # But rather than re-implement the Postgres Wire3 protocol, we're taking advantage
65
+ # of the existing postgres-pr library, which was originally written by Michael
66
+ # Neumann but (at this writing) appears to be no longer maintained. Still, it's
67
+ # in basically a production-ready state, and the wire protocol isn't that complicated
68
+ # anyway.
69
+ #
70
+ # We need to monkeypatch StringIO because it lacks the #readbytes method needed
71
+ # by postgres-pr.
72
+ #
73
+ # We're tucking in a bunch of require statements that may not be present in garden-variety
74
+ # EM installations. Until we find a good way to only require these if a program
75
+ # requires postgres, this file will need to be required explicitly.
76
+ #
77
+ # The StringIO monkeypatch is lifted verbatim from the standard library readbytes.rb,
78
+ # which adds method #readbytes directly to class IO. But StringIO is not a subclass of IO.
79
+ #
80
+ # We cloned the handling of postgres messages from lib/postgres-pr/connection.rb
81
+ # in the postgres-pr library, and modified it for event-handling.
82
+ #
83
+ # TODO: The password handling in dispatch_conn_message is totally incomplete.
84
+ #
85
+ #
86
+ # We return Deferrables from the user-level operations surfaced by this interface.
87
+ # Experimentally, we're using the pattern of always returning a boolean value as the
88
+ # first argument of a deferrable callback to indicate success or failure. This is
89
+ # instead of the traditional pattern of calling Deferrable#succeed or #fail, and
90
+ # requiring the user to define both a callback and an errback function.
91
+ #
92
+ # === Usage
93
+ # EM.run {
94
+ # db = EM.connect_unix_domain( "/tmp/.s.PGSQL.5432", EM::P::Postgres3 )
95
+ # db.connect( dbname, username, psw ).callback do |status|
96
+ # if status
97
+ # db.query( "select * from some_table" ).callback do |status, result, errors|
98
+ # if status
99
+ # result.rows.each do |row|
100
+ # p row
101
+ # end
102
+ # end
103
+ # end
104
+ # end
105
+ # end
106
+ # }
107
+ class Postgres3 < EventMachine::Connection
108
+ include PostgresPR
109
+
110
+ def initialize
111
+ @data = ""
112
+ @params = {}
113
+ end
114
+
115
+ def connect db, user, psw=nil
116
+ d = EM::DefaultDeferrable.new
117
+ d.timeout 15
118
+
119
+ if @pending_query || @pending_conn
120
+ d.succeed false, "Operation already in progress"
121
+ else
122
+ @pending_conn = d
123
+ prms = {"user"=>user, "database"=>db}
124
+ @user = user
125
+ if psw
126
+ @password = psw
127
+ #prms["password"] = psw
128
+ end
129
+ send_data PostgresPR::StartupMessage.new( 3 << 16, prms ).dump
130
+ end
131
+
132
+ d
133
+ end
134
+
135
+ def query sql
136
+ d = EM::DefaultDeferrable.new
137
+ d.timeout 15
138
+
139
+ if @pending_query || @pending_conn
140
+ d.succeed false, "Operation already in progress"
141
+ else
142
+ @r = PostgresPR::Connection::Result.new
143
+ @e = []
144
+ @pending_query = d
145
+ send_data PostgresPR::Query.dump(sql)
146
+ end
147
+
148
+ d
149
+ end
150
+
151
+
152
+ def receive_data data
153
+ @data << data
154
+ while @data.length >= 5
155
+ pktlen = @data[1...5].unpack("N").first
156
+ if @data.length >= (1 + pktlen)
157
+ pkt = @data.slice!(0...(1+pktlen))
158
+ m = StringIO.open( pkt, "r" ) {|io| PostgresPR::Message.read( io ) }
159
+ if @pending_conn
160
+ dispatch_conn_message m
161
+ elsif @pending_query
162
+ dispatch_query_message m
163
+ else
164
+ raise "Unexpected message from database"
165
+ end
166
+ else
167
+ break # very important, break out of the while
168
+ end
169
+ end
170
+ end
171
+
172
+
173
+ def unbind
174
+ if o = (@pending_query || @pending_conn)
175
+ o.succeed false, "lost connection"
176
+ end
177
+ end
178
+
179
+ # Cloned and modified from the postgres-pr.
180
+ def dispatch_conn_message msg
181
+ case msg
182
+ when AuthentificationClearTextPassword
183
+ raise ArgumentError, "no password specified" if @password.nil?
184
+ send_data PasswordMessage.new(@password).dump
185
+
186
+ when AuthentificationCryptPassword
187
+ raise ArgumentError, "no password specified" if @password.nil?
188
+ send_data PasswordMessage.new(@password.crypt(msg.salt)).dump
189
+
190
+ when AuthentificationMD5Password
191
+ raise ArgumentError, "no password specified" if @password.nil?
192
+ require 'digest/md5'
193
+
194
+ m = Digest::MD5.hexdigest(@password + @user)
195
+ m = Digest::MD5.hexdigest(m + msg.salt)
196
+ m = 'md5' + m
197
+ send_data PasswordMessage.new(m).dump
198
+
199
+ when AuthentificationKerberosV4, AuthentificationKerberosV5, AuthentificationSCMCredential
200
+ raise "unsupported authentification"
201
+
202
+ when AuthentificationOk
203
+ when ErrorResponse
204
+ raise msg.field_values.join("\t")
205
+ when NoticeResponse
206
+ @notice_processor.call(msg) if @notice_processor
207
+ when ParameterStatus
208
+ @params[msg.key] = msg.value
209
+ when BackendKeyData
210
+ # TODO
211
+ #p msg
212
+ when ReadyForQuery
213
+ # TODO: use transaction status
214
+ pc,@pending_conn = @pending_conn,nil
215
+ pc.succeed true
216
+ else
217
+ raise "unhandled message type"
218
+ end
219
+ end
220
+
221
+ # Cloned and modified from the postgres-pr.
222
+ def dispatch_query_message msg
223
+ case msg
224
+ when DataRow
225
+ @r.rows << msg.columns
226
+ when CommandComplete
227
+ @r.cmd_tag = msg.cmd_tag
228
+ when ReadyForQuery
229
+ pq,@pending_query = @pending_query,nil
230
+ pq.succeed true, @r, @e
231
+ when RowDescription
232
+ @r.fields = msg.fields
233
+ when CopyInResponse
234
+ when CopyOutResponse
235
+ when EmptyQueryResponse
236
+ when ErrorResponse
237
+ # TODO
238
+ @e << msg
239
+ when NoticeResponse
240
+ @notice_processor.call(msg) if @notice_processor
241
+ else
242
+ # TODO
243
+ end
244
+ end
245
+ end
246
+ end
247
+ end