cool.io 1.0.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yaml +54 -0
  3. data/.gitignore +30 -0
  4. data/.rspec +3 -0
  5. data/{CHANGES → CHANGES.md} +175 -79
  6. data/{README.markdown → README.md} +43 -49
  7. data/Rakefile +44 -69
  8. data/appveyor.yml +18 -0
  9. data/cool.io.gemspec +18 -131
  10. data/examples/callbacked_echo_server.rb +24 -0
  11. data/ext/cool.io/buffer.c +781 -0
  12. data/ext/cool.io/cool.io.h +13 -0
  13. data/ext/cool.io/cool.io_ext.c +1 -0
  14. data/ext/cool.io/ev_wrap.h +4 -2
  15. data/ext/cool.io/extconf.rb +27 -16
  16. data/ext/cool.io/iowatcher.c +17 -8
  17. data/ext/cool.io/loop.c +36 -84
  18. data/ext/cool.io/stat_watcher.c +103 -25
  19. data/ext/cool.io/timer_watcher.c +3 -3
  20. data/ext/cool.io/utils.c +5 -0
  21. data/ext/cool.io/watcher.h +1 -1
  22. data/ext/libev/Changes +152 -3
  23. data/ext/libev/LICENSE +2 -1
  24. data/ext/libev/README +8 -8
  25. data/ext/libev/ev.c +1719 -348
  26. data/ext/libev/ev.h +146 -118
  27. data/ext/libev/ev_epoll.c +71 -20
  28. data/ext/libev/ev_kqueue.c +36 -16
  29. data/ext/libev/ev_poll.c +14 -11
  30. data/ext/libev/ev_port.c +43 -18
  31. data/ext/libev/ev_select.c +82 -25
  32. data/ext/libev/ev_vars.h +28 -21
  33. data/ext/libev/ev_win32.c +19 -10
  34. data/ext/libev/ev_wrap.h +166 -152
  35. data/ext/libev/test_libev_win32.c +1 -1
  36. data/gems.rb +9 -0
  37. data/lib/cool.io/async_watcher.rb +1 -1
  38. data/lib/cool.io/custom_require.rb +9 -0
  39. data/lib/cool.io/dns_resolver.rb +30 -22
  40. data/lib/cool.io/dsl.rb +32 -28
  41. data/lib/cool.io/io.rb +55 -35
  42. data/lib/cool.io/iowatcher.rb +1 -1
  43. data/lib/cool.io/listener.rb +35 -17
  44. data/lib/cool.io/loop.rb +17 -25
  45. data/lib/cool.io/meta.rb +6 -5
  46. data/lib/cool.io/server.rb +5 -4
  47. data/lib/cool.io/socket.rb +41 -30
  48. data/lib/cool.io/timer_watcher.rb +1 -1
  49. data/lib/cool.io/version.rb +7 -0
  50. data/lib/cool.io.rb +11 -10
  51. data/lib/coolio.rb +1 -1
  52. data/libev_ruby_gil.diff +175 -0
  53. data/libev_win_select.diff +130 -0
  54. data/spec/async_watcher_spec.rb +5 -5
  55. data/spec/dns_spec.rb +27 -8
  56. data/spec/iobuffer_spec.rb +147 -0
  57. data/spec/spec_helper.rb +15 -1
  58. data/spec/stat_watcher_spec.rb +81 -0
  59. data/spec/tcp_server_spec.rb +225 -0
  60. data/spec/tcp_socket_spec.rb +185 -0
  61. data/spec/timer_watcher_spec.rb +23 -19
  62. data/spec/udp_socket_spec.rb +58 -0
  63. data/spec/unix_listener_spec.rb +8 -8
  64. data/spec/unix_server_spec.rb +10 -8
  65. metadata +109 -112
  66. data/VERSION +0 -1
  67. data/examples/httpclient.rb +0 -38
  68. data/ext/http11_client/.gitignore +0 -5
  69. data/ext/http11_client/LICENSE +0 -31
  70. data/ext/http11_client/ext_help.h +0 -14
  71. data/ext/http11_client/extconf.rb +0 -6
  72. data/ext/http11_client/http11_client.c +0 -300
  73. data/ext/http11_client/http11_parser.c +0 -403
  74. data/ext/http11_client/http11_parser.h +0 -48
  75. data/ext/http11_client/http11_parser.rl +0 -173
  76. data/lib/cool.io/eventmachine.rb +0 -234
  77. data/lib/cool.io/http_client.rb +0 -419
  78. data/lib/rev.rb +0 -4
  79. data/spec/possible_tests/schedules_other_threads.rb +0 -48
  80. data/spec/possible_tests/test_on_resolve_failed.rb +0 -9
  81. data/spec/possible_tests/test_resolves.rb +0 -27
  82. data/spec/possible_tests/test_write_during_resolve.rb +0 -27
  83. data/spec/possible_tests/works_straight.rb +0 -71
@@ -1,234 +0,0 @@
1
- #--
2
- # Copyright (C)2007-10 Tony Arcieri, Roger Pack
3
- # You can redistribute this under the terms of the Ruby license
4
- # See file LICENSE for details
5
- #++
6
-
7
- require 'cool.io'
8
-
9
- # EventMachine emulation for Cool.io:
10
- #
11
- # require 'coolio/eventmachine'
12
- #
13
- # Drawbacks: slightly slower than EM.
14
- # Benefits: timers are more accurate using libev than using EM
15
- # TODO: some things like connection timeouts aren't implemented yet
16
- # DONE: timers and normal socket functions are implemented.
17
- module EventMachine
18
- class << self
19
- # Start the Reactor loop
20
- def run
21
- yield if block_given?
22
- Coolio::Loop.default.run
23
- end
24
-
25
- # Stop the Reactor loop
26
- def stop_event_loop
27
- Coolio::Loop.default.stop
28
- end
29
-
30
- class OneShotEMTimer < Coolio::TimerWatcher
31
- def setup(proc)
32
- @proc = proc
33
- end
34
-
35
- def on_timer
36
- @proc.call
37
- end
38
- end
39
-
40
- # ltodo: use Coolio's PeriodicTimer to wrap EM's two similar to it
41
- # todo: close all connections on 'stop', I believe
42
-
43
- def add_timer(interval, proc = nil, &block)
44
- block ||= proc
45
- t = OneShotEMTimer.new(interval, false) # non repeating
46
- t.setup(block)
47
-
48
- # fire 'er off ltodo: do we keep track of these timers in memory?
49
- t.attach(Coolio::Loop.default)
50
- t
51
- end
52
-
53
- def cancel_timer(t)
54
- # guess there's a case where EM you can say 'cancel' but it's already fired?
55
- # kind of odd but it happens
56
- t.detach if t.attached?
57
- end
58
-
59
- def set_comm_inactivity_timeout(*args); end # TODO
60
-
61
- # Make an outgoing connection
62
- def connect(addr, port, handler = Connection, *args, &block)
63
- block = args.pop if Proc === args[-1]
64
-
65
- # make sure we're a 'real' class here
66
- klass = if (handler and handler.is_a?(Class))
67
- handler
68
- else
69
- Class.new( Connection ) {handler and include handler}
70
- end
71
-
72
- wrapped_child = CallsBackToEM.connect(addr, port, *args) # ltodo: args? what? they're used? also TODOC TODO FIX
73
- conn = klass.new(wrapped_child) # ltodo [?] addr, port, *args)
74
- wrapped_child.attach(Coolio::Loop.default) # necessary
75
- conn.heres_your_socket(wrapped_child)
76
- wrapped_child.call_back_to_this(conn) # calls post_init for us
77
- yield conn if block_given?
78
- end
79
-
80
- # Start a TCP server on the given address and port
81
- def start_server(addr, port, handler = Connection, *args, &block)
82
- # make sure we're a 'real' class here
83
- klass = if (handler and handler.is_a?(Class))
84
- handler
85
- else
86
- Class.new( Connection ) {handler and include handler}
87
- end
88
-
89
- server = Coolio::TCPServer.new(addr, port, CallsBackToEM, *args) do |wrapped_child|
90
- conn = klass.new(wrapped_child)
91
- conn.heres_your_socket(wrapped_child) # ideally NOT have this :)
92
- wrapped_child.call_back_to_this(conn)
93
- block.call(conn) if block
94
- end
95
-
96
- server.attach(Coolio::Loop.default)
97
- end
98
-
99
- def stop_server(server)
100
- server.close
101
- end
102
-
103
- # Set the maximum number of descriptors available to this process
104
- def set_descriptor_table_size(nfds)
105
- Coolio::Utils.maxfds = nfds
106
- end
107
-
108
- # Compatibility noop. Handled automatically by libev
109
- def epoll; end
110
-
111
- # Compatibility noop. Handled automatically by libev
112
- def kqueue; end
113
- end
114
-
115
- class CallsBackToEM < Coolio::TCPSocket
116
- class ConnectTimer < Coolio::TimerWatcher
117
- attr_accessor :parent
118
- def on_timer
119
- @parent.connection_has_timed_out
120
- end
121
- end
122
-
123
- def call_back_to_this parent
124
- @call_back_to_this = parent
125
- parent.post_init
126
- end
127
-
128
- def on_connect
129
- # @connection_timer.detach if @connection_timer
130
- # won't need that anymore :) -- with server connecteds we don't have it, anyway
131
-
132
- # TODO should server accepted's call this? They don't currently
133
- # [and can't, since on_connect gets called basically in the initializer--needs some code love for that to happen :)
134
- @call_back_to_this.connection_completed if @call_back_to_this
135
- end
136
-
137
- def connection_has_timed_out
138
- return if closed?
139
-
140
- # wonder if this works when you're within a half-connected phase.
141
- # I think it does. What about TCP state?
142
- close unless closed?
143
- @call_back_to_this.unbind
144
- end
145
-
146
- def on_write_complete
147
- close if @should_close_after_writing
148
- end
149
-
150
- def should_close_after_writing
151
- @should_close_after_writing = true;
152
- end
153
-
154
- def on_close
155
- @call_back_to_this.unbind # about the same ltodo check if they ARE the same here
156
- end
157
-
158
- def on_resolve_failed
159
- fail
160
- end
161
-
162
- def on_connect_failed
163
- fail
164
- end
165
-
166
- def on_read(data)
167
- @call_back_to_this.receive_data data
168
- end
169
-
170
- def fail
171
- #@connection_timer.detch if @connection_timer
172
- @call_back_to_this.unbind
173
- end
174
-
175
- def self.connect(*args)
176
- a = super *args
177
- # the connect timer currently kills TCPServer classes. I'm not sure why.
178
- #@connection_timer = ConnectTimer.new(14) # needs to be at least higher than 12 :)
179
- #@connection_timer.parent = a
180
- #@connection_timer.attach(Coolio::Loop.default)
181
- a
182
- end
183
- end
184
-
185
- class Connection
186
- def self.new(*args)
187
- allocate#.instance_eval do
188
- # initialize *args
189
- #end
190
- end
191
-
192
- # we will need to call 'their functions' appropriately -- the commented out ones, here
193
- #
194
- # Callback fired when connection is created
195
- def post_init
196
- # I thought we were 'overriding' EM's existing methods, here.
197
- # Huh? Why do we have to define these then?
198
- end
199
-
200
- # Callback fired when connection is closed
201
- def unbind; end
202
-
203
- # Callback fired when data is received
204
- # def receive_data(data); end
205
- def heres_your_socket(instantiated_coolio_socket)
206
- instantiated_coolio_socket.call_back_to_this self
207
- @wrapped_coolio = instantiated_coolio_socket
208
- end
209
-
210
- # Send data to the current connection -- called by them
211
- def send_data(data)
212
- @wrapped_coolio.write data
213
- end
214
-
215
- # Close the connection, optionally after writing
216
- def close_connection(after_writing = false)
217
- return close_connection_after_writing if after_writing
218
- @wrapped_coolio.close
219
- end
220
-
221
- # Close the connection after all data has been written
222
- def close_connection_after_writing
223
- @wrapped_coolio.output_buffer_size.zero? ? @wrapped_coolio.close : @wrapped_coolio.should_close_after_writing
224
- end
225
-
226
- def get_peername
227
- family, port, host_name, host_ip = @wrapped_coolio.peeraddr
228
- Socket.pack_sockaddr_in(port, host_ip) # pack it up :)
229
- end
230
- end
231
- end
232
-
233
- # Shortcut constant
234
- EM = EventMachine
@@ -1,419 +0,0 @@
1
- #--
2
- # Copyright (C)2007-10 Tony Arcieri
3
- # Includes portions originally Copyright (C)2005 Zed Shaw
4
- # You can redistribute this under the terms of the Ruby license
5
- # See file LICENSE for details
6
- #++
7
-
8
- require 'http11_client'
9
-
10
- module Coolio
11
- # A simple hash is returned for each request made by HttpClient with
12
- # the headers that were given by the server for that request.
13
- class HttpResponseHeader < Hash
14
- # The reason returned in the http response ("OK","File not found",etc.)
15
- attr_accessor :http_reason
16
-
17
- # The HTTP version returned.
18
- attr_accessor :http_version
19
-
20
- # The status code (as a string!)
21
- attr_accessor :http_status
22
-
23
- # HTTP response status as an integer
24
- def status
25
- Integer(http_status) rescue nil
26
- end
27
-
28
- # Length of content as an integer, or nil if chunked/unspecified
29
- def content_length
30
- Integer(self[HttpClient::CONTENT_LENGTH]) rescue nil
31
- end
32
-
33
- # Is the transfer encoding chunked?
34
- def chunked_encoding?
35
- /chunked/i === self[HttpClient::TRANSFER_ENCODING]
36
- end
37
- end
38
-
39
- class HttpChunkHeader < Hash
40
- # When parsing chunked encodings this is set
41
- attr_accessor :http_chunk_size
42
-
43
- # Size of the chunk as an integer
44
- def chunk_size
45
- return @chunk_size unless @chunk_size.nil?
46
- @chunk_size = @http_chunk_size ? @http_chunk_size.to_i(base=16) : 0
47
- end
48
- end
49
-
50
- # Methods for building HTTP requests
51
- module HttpEncoding
52
- HTTP_REQUEST_HEADER="%s %s HTTP/1.1\r\n"
53
- FIELD_ENCODING = "%s: %s\r\n"
54
-
55
- # Escapes a URI.
56
- def escape(s)
57
- s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
58
- '%'+$1.unpack('H2'*$1.size).join('%').upcase
59
- }.tr(' ', '+')
60
- end
61
-
62
- # Unescapes a URI escaped string.
63
- def unescape(s)
64
- s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
65
- [$1.delete('%')].pack('H*')
66
- }
67
- end
68
-
69
- # Map all header keys to a downcased string version
70
- def munge_header_keys(head)
71
- head.inject({}) { |h, (k, v)| h[k.to_s.downcase] = v; h }
72
- end
73
-
74
- # HTTP is kind of retarded that you have to specify
75
- # a Host header, but if you include port 80 then further
76
- # redirects will tack on the :80 which is annoying.
77
- def encode_host
78
- remote_host + (remote_port.to_i != 80 ? ":#{remote_port}" : "")
79
- end
80
-
81
- def encode_request(method, path, query)
82
- HTTP_REQUEST_HEADER % [method.to_s.upcase, encode_query(path, query)]
83
- end
84
-
85
- def encode_query(path, query)
86
- return path unless query
87
- path + "?" + query.map { |k, v| encode_param(k, v) }.join('&')
88
- end
89
-
90
- # URL encodes a single k=v parameter.
91
- def encode_param(k, v)
92
- escape(k) + "=" + escape(v)
93
- end
94
-
95
- # Encode a field in an HTTP header
96
- def encode_field(k, v)
97
- FIELD_ENCODING % [k, v]
98
- end
99
-
100
- def encode_headers(head)
101
- head.inject('') do |result, (key, value)|
102
- # Munge keys from foo-bar-baz to Foo-Bar-Baz
103
- key = key.split('-').map { |k| k.capitalize }.join('-')
104
- result << encode_field(key, value)
105
- end
106
- end
107
-
108
- def encode_cookies(cookies)
109
- cookies.inject('') { |result, (k, v)| result << encode_field('Cookie', encode_param(k, v)) }
110
- end
111
- end
112
-
113
- # HTTP client class implemented as a subclass of Coolio::TCPSocket. Encodes
114
- # requests and allows streaming consumption of the response. Response is
115
- # parsed with a Ragel-generated whitelist parser which supports chunked
116
- # HTTP encoding.
117
- #
118
- # == Example
119
- #
120
- # loop = Coolio::Loop.default
121
- # client = Coolio::HttpClient.connect("www.google.com").attach
122
- # client.get('/search', query: {q: 'foobar'})
123
- # loop.run
124
- #
125
- class HttpClient < TCPSocket
126
- include HttpEncoding
127
-
128
- ALLOWED_METHODS=[:put, :get, :post, :delete, :head]
129
- TRANSFER_ENCODING="TRANSFER_ENCODING"
130
- CONTENT_LENGTH="CONTENT_LENGTH"
131
- SET_COOKIE="SET_COOKIE"
132
- LOCATION="LOCATION"
133
- HOST="HOST"
134
- CRLF="\r\n"
135
-
136
- # Connect to the given server, with port 80 as the default
137
- def self.connect(addr, port = 80, *args)
138
- super
139
- end
140
-
141
- def initialize(socket)
142
- super
143
-
144
- @parser = HttpClientParser.new
145
- @parser_nbytes = 0
146
-
147
- @state = :response_header
148
- @data = ::IO::Buffer.new
149
-
150
- @response_header = HttpResponseHeader.new
151
- @chunk_header = HttpChunkHeader.new
152
- end
153
-
154
- # Send an HTTP request and consume the response.
155
- # Supports the following options:
156
- #
157
- # head: {Key: Value}
158
- # Specify an HTTP header, e.g. {'Connection': 'close'}
159
- #
160
- # query: {Key: Value}
161
- # Specify query string parameters (auto-escaped)
162
- #
163
- # cookies: {Key: Value}
164
- # Specify hash of cookies (auto-escaped)
165
- #
166
- # body: String
167
- # Specify the request body (you must encode it for now)
168
- #
169
- def request(method, path, options = {})
170
- raise ArgumentError, "invalid request path" unless /^\// === path
171
- raise RuntimeError, "request already sent" if @requested
172
-
173
- @method, @path, @options = method, path, options
174
- @requested = true
175
-
176
- return unless @connected
177
- send_request
178
- end
179
-
180
- # Enable the HttpClient if it has been disabled
181
- def enable
182
- super
183
- dispatch unless @data.empty?
184
- end
185
-
186
- # Called when response header has been received
187
- def on_response_header(response_header)
188
- end
189
-
190
- # Called when part of the body has been read
191
- def on_body_data(data)
192
- STDOUT.write data
193
- STDOUT.flush
194
- end
195
-
196
- # Called when the request has completed
197
- def on_request_complete
198
- close
199
- end
200
-
201
- # Called when an error occurs dispatching the request
202
- def on_error(reason)
203
- close
204
- raise RuntimeError, reason
205
- end
206
-
207
- #########
208
- protected
209
- #########
210
-
211
- #
212
- # Coolio callbacks
213
- #
214
-
215
- def on_connect
216
- @connected = true
217
- send_request if @method and @path
218
- end
219
-
220
- def on_read(data)
221
- @data << data
222
- dispatch
223
- end
224
-
225
- #
226
- # Request sending
227
- #
228
-
229
- def send_request
230
- send_request_header
231
- send_request_body
232
- end
233
-
234
- def send_request_header
235
- query = @options[:query]
236
- head = @options[:head] ? munge_header_keys(@options[:head]) : {}
237
- cookies = @options[:cookies]
238
- body = @options[:body]
239
-
240
- # Set the Host header if it hasn't been specified already
241
- head['host'] ||= encode_host
242
-
243
- # Set the Content-Length if it hasn't been specified already and a body was given
244
- head['content-length'] ||= body ? body.length : 0
245
-
246
- # Set the User-Agent if it hasn't been specified
247
- head['user-agent'] ||= "Coolio #{Coolio::VERSION}"
248
-
249
- # Default to Connection: close
250
- head['connection'] ||= 'close'
251
-
252
- # Build the request
253
- request_header = encode_request(@method, @path, query)
254
- request_header << encode_headers(head)
255
- request_header << encode_cookies(cookies) if cookies
256
- request_header << CRLF
257
-
258
- write request_header
259
- end
260
-
261
- def send_request_body
262
- write @options[:body] if @options[:body]
263
- end
264
-
265
- #
266
- # Response processing
267
- #
268
-
269
- def dispatch
270
- while enabled? and case @state
271
- when :response_header
272
- parse_response_header
273
- when :chunk_header
274
- parse_chunk_header
275
- when :chunk_body
276
- process_chunk_body
277
- when :chunk_footer
278
- process_chunk_footer
279
- when :response_footer
280
- process_response_footer
281
- when :body
282
- process_body
283
- when :finished, :invalid
284
- break
285
- else raise RuntimeError, "invalid state: #{@state}"
286
- end
287
- end
288
- end
289
-
290
- def parse_header(header)
291
- return false if @data.empty?
292
-
293
- begin
294
- @parser_nbytes = @parser.execute(header, @data.to_str, @parser_nbytes)
295
- rescue Coolio::HttpClientParserError
296
- on_error "invalid HTTP format, parsing fails"
297
- @state = :invalid
298
- end
299
-
300
- return false unless @parser.finished?
301
-
302
- # Clear parsed data from the buffer
303
- @data.read(@parser_nbytes)
304
- @parser.reset
305
- @parser_nbytes = 0
306
-
307
- true
308
- end
309
-
310
- def parse_response_header
311
- return false unless parse_header(@response_header)
312
-
313
- unless @response_header.http_status and @response_header.http_reason
314
- on_error "no HTTP response"
315
- @state = :invalid
316
- return false
317
- end
318
-
319
- on_response_header(@response_header)
320
-
321
- if @response_header.chunked_encoding?
322
- @state = :chunk_header
323
- else
324
- @state = :body
325
- @bytes_remaining = @response_header.content_length
326
- end
327
-
328
- true
329
- end
330
-
331
- def parse_chunk_header
332
- return false unless parse_header(@chunk_header)
333
-
334
- @bytes_remaining = @chunk_header.chunk_size
335
- @chunk_header = HttpChunkHeader.new
336
-
337
- @state = @bytes_remaining > 0 ? :chunk_body : :response_footer
338
- true
339
- end
340
-
341
- def process_chunk_body
342
- if @data.size < @bytes_remaining
343
- @bytes_remaining -= @data.size
344
- on_body_data @data.read
345
- return false
346
- end
347
-
348
- on_body_data @data.read(@bytes_remaining)
349
- @bytes_remaining = 0
350
-
351
- @state = :chunk_footer
352
- true
353
- end
354
-
355
- def process_chunk_footer
356
- return false if @data.size < 2
357
-
358
- if @data.read(2) == CRLF
359
- @state = :chunk_header
360
- else
361
- on_error "non-CRLF chunk footer"
362
- @state = :invalid
363
- end
364
-
365
- true
366
- end
367
-
368
- def process_response_footer
369
- return false if @data.size < 2
370
-
371
- if @data.read(2) == CRLF
372
- if @data.empty?
373
- on_request_complete
374
- @state = :finished
375
- else
376
- on_error "garbage at end of chunked response"
377
- @state = :invalid
378
- end
379
- else
380
- on_error "non-CRLF response footer"
381
- @state = :invalid
382
- end
383
-
384
- false
385
- end
386
-
387
- def process_body
388
- if @bytes_remaining.nil?
389
- on_body_data @data.read
390
- return false
391
- end
392
-
393
- if @bytes_remaining.zero?
394
- on_request_complete
395
- @state = :finished
396
- return false
397
- end
398
-
399
- if @data.size < @bytes_remaining
400
- @bytes_remaining -= @data.size
401
- on_body_data @data.read
402
- return false
403
- end
404
-
405
- on_body_data @data.read(@bytes_remaining)
406
- @bytes_remaining = 0
407
-
408
- if @data.empty?
409
- on_request_complete
410
- @state = :finished
411
- else
412
- on_error "garbage at end of body"
413
- @state = :invalid
414
- end
415
-
416
- false
417
- end
418
- end
419
- end
data/lib/rev.rb DELETED
@@ -1,4 +0,0 @@
1
- STDERR.puts "*** DEPRECATION WARNING: require 'rev' and the Rev constant are deprecated. Please use require 'cool.io' and the Coolio constant instead"
2
-
3
- require 'cool.io'
4
- Rev = Coolio
@@ -1,48 +0,0 @@
1
- require File.dirname(__FILE__) + '/../lib/rev'
2
- def dbg
3
- require 'rubygems'
4
- require 'ruby-debug'
5
- debugger
6
- end
7
- Thread.abort_on_exception=true
8
-
9
- require 'socket'
10
-
11
- describe Rev::TCPSocket do
12
- HOST = '127.0.0.1'
13
- PORT = 4321
14
- before :each do
15
- @server = Rev::TCPServer.new(HOST, PORT) do |c|
16
- c.on_connect { puts "#{remote_addr}:#{remote_port} connected" }
17
- c.on_close { puts "#{remote_addr}:#{remote_port} disconnected" }
18
- #c.on_read { |data| write data }
19
- end
20
-
21
- end
22
-
23
- after :each do
24
- @server.close
25
- end
26
-
27
- def sleep_until(seconds = 1, interval = 0.1)
28
- raise unless block_given?
29
- start_time=Time.now
30
- sleep interval until ((Time.now - start_time) > seconds) or yield
31
- end
32
-
33
- it "should stop" do
34
- loop = Rev::Loop.default
35
- stopped = false;
36
- @server.attach(loop)
37
- Thread.new {
38
- loop.run
39
- stopped = true
40
- }
41
- sleep 0
42
- stopped.should == false
43
- loop.stop
44
- sleep_until(3) { stopped == true }
45
- stopped.should == true
46
- end
47
- end
48
-
@@ -1,9 +0,0 @@
1
- require '../rev'
2
- class Tester < Rev::TCPSocket
3
- def on_resolve_failed
4
- print "resolved failed! that's good!"
5
- end
6
- end
7
- a = Tester.connect('asdfgoogle.com', 80)
8
- a.attach Rev::Loop.default
9
- Rev::Loop.default.run