internethakai 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/CHANGES +53 -0
  2. data/README +177 -0
  3. data/bin/hakaigen +10 -0
  4. data/bin/internethakai +9 -0
  5. data/internethakai.gemspec +27 -0
  6. data/lib/internethakai.rb +26 -0
  7. data/lib/internethakai.rb.~1~ +25 -0
  8. data/lib/internethakai/action.rb +403 -0
  9. data/lib/internethakai/client_handler.rb +175 -0
  10. data/lib/internethakai/client_queue.rb +27 -0
  11. data/lib/internethakai/concurrency_manager.rb +333 -0
  12. data/lib/internethakai/concurrency_manager.rb.~1~ +331 -0
  13. data/lib/internethakai/core.rb +146 -0
  14. data/lib/internethakai/executor.rb +129 -0
  15. data/lib/internethakai/generator.rb +32 -0
  16. data/lib/internethakai/hakairev.rb +119 -0
  17. data/lib/internethakai/hakairev/executor.rb +43 -0
  18. data/lib/internethakai/hakairev/http_client.rb +362 -0
  19. data/lib/internethakai/hakairev/http_client.rb.~1~ +371 -0
  20. data/lib/internethakai/hakairev/monkey.rb +70 -0
  21. data/lib/internethakai/hakairev/revpipe.rb +39 -0
  22. data/lib/internethakai/hakairev/task.rb +39 -0
  23. data/lib/internethakai/hakairev/time_register.rb +116 -0
  24. data/lib/internethakai/hakairev/timer_factory.rb +38 -0
  25. data/lib/internethakai/http_client.rb +120 -0
  26. data/lib/internethakai/logger.rb +52 -0
  27. data/lib/internethakai/main.rb +90 -0
  28. data/lib/internethakai/reporter.rb +143 -0
  29. data/lib/internethakai/response.rb +65 -0
  30. data/lib/internethakai/scenario.rb +98 -0
  31. data/lib/internethakai/scenario.tmpl +58 -0
  32. data/lib/internethakai/scenario_builder.rb +183 -0
  33. data/lib/internethakai/scenario_handler.rb +91 -0
  34. data/lib/internethakai/time_register.rb +53 -0
  35. data/lib/internethakai/util.rb +130 -0
  36. metadata +134 -0
@@ -0,0 +1,371 @@
1
+ module InternetHakai
2
+ class RevHttpConnection < Rev::HttpClient
3
+ def initialize args
4
+ @remote_addr, @remote_port = args
5
+ soc = TCPConnectSocket::new(::Socket::AF_INET, @remote_addr, @remote_port)
6
+ super(soc)
7
+ end
8
+ def init
9
+ @content = ''
10
+ @writable_flag = false
11
+ @send_flag = false
12
+ @busy = false
13
+ @on_request_complete = nil
14
+ @requested = false
15
+ @response_object = InternetHakai::ResponseObject::new
16
+ self
17
+ end
18
+ attr_reader :connected, :busy
19
+ def on_read s
20
+ super
21
+ end
22
+ def on_readable
23
+ begin
24
+ on_read @_io.read_nonblock(INPUT_SIZE)
25
+ rescue Errno::EAGAIN
26
+ rescue Errno::ECONNRESET, EOFError
27
+ rescue IOError => e
28
+ @exception = e
29
+ on_error('io error')
30
+ rescue Exception => e
31
+ @exception = e
32
+ on_error('io error')
33
+ end
34
+ end
35
+ def reconnect
36
+ @requested = false
37
+ @busy = false
38
+ free
39
+ socket = TCPConnectSocket::new(::Socket::AF_INET, @remote_addr, @remote_port)
40
+
41
+ @_io = socket
42
+ #@_write_buffer ||= ::IO::Buffer.new
43
+ @_read_watcher = Watcher.new(socket, self, :r)
44
+ @_write_watcher = Watcher.new(socket, self, :w)
45
+ @address_family, @remote_port, @remote_host, @remote_addr = socket.peeraddr
46
+
47
+
48
+ @state = :response_header
49
+ #@data = ::IO::Buffer.new
50
+
51
+ @response_header = Rev::HttpResponseHeader.new
52
+ @chunk_header = Rev::HttpChunkHeader.new
53
+ #initialize(socket)
54
+
55
+ @_connector = Connector::new(self, socket)
56
+ @_connector.attach(@loop)
57
+ end
58
+ def close
59
+ super
60
+ end
61
+ def on_writable
62
+ @writable_flag = true unless @writable_flag
63
+ # writable + send 両方そろったら開始時間
64
+ if @send_flag && !@starttime
65
+ @starttime = Time::now
66
+ end
67
+ begin
68
+ @_write_buffer.write_to(@_io)
69
+
70
+ rescue Errno::EPIPE, Errno::ECONNRESET => e
71
+ rescue IOError => e
72
+ rescue Exception => e
73
+ @exception = e
74
+ on_error('io error')
75
+ end
76
+ if @_write_buffer.empty?
77
+ disable_write_watcher
78
+ on_write_complete
79
+ end
80
+ end
81
+ def send_request
82
+ @send_flag = true
83
+ @starttime = Time::now
84
+ super
85
+ end
86
+ def attached?
87
+ if @_connector
88
+ @_connector.attached?
89
+ elsif @_read_watcher
90
+ @_read_watcher.attached?
91
+ elsif @_resolver
92
+ @_resolver.attached
93
+ else
94
+ super
95
+ end
96
+ end
97
+ def on_body_data(data)
98
+ @content += data
99
+ end
100
+ def on_request_complete
101
+ @response_time = Time::now - @starttime
102
+ self.close
103
+ end
104
+ def on_connect_failed
105
+ @exception = SocketError::new('connection error')
106
+ on_error('')
107
+ end
108
+ def on_resolve_failed
109
+ @exception = SocketError::new('dns error')
110
+ on_error('')
111
+ end
112
+ def on_failure
113
+ @exception = SocketError::new
114
+ on_error('')
115
+ end
116
+ def on_error(reason='error')
117
+ unless @starttime.nil?
118
+ @response_time = Time::now - @starttime
119
+ else
120
+ @response_time = 0
121
+ end
122
+ close if @_io and !@_io.closed?
123
+ @requested = false
124
+ @exception = reason if @exception.nil?
125
+ @busy = false
126
+ end
127
+ def to_response_object
128
+ r = @response_object
129
+ r.body = @content.to_s
130
+ r.status = @response_header.http_status.to_i
131
+ r.content_type = @response_header["CONTENT_TYPE"].to_s
132
+ r.location = @response_header["LOCATION"]
133
+ r.time = @response_time
134
+ r
135
+ end
136
+ def attach lp
137
+ @loop = lp unless @loop
138
+ if @_connector
139
+ @_connector.attach lp
140
+ elsif @_read_watcher
141
+ @_read_watcher.attach(lp)
142
+ elsif @_resolver
143
+ @_resolver.attache lp
144
+ else
145
+ return
146
+ end
147
+ end
148
+ =begin
149
+ def parse_response_header
150
+ return false unless parse_header(@response_header)
151
+
152
+ unless @response_header.http_status and @response_header.http_reason
153
+ on_error "no HTTP response"
154
+ @state = :invalid
155
+ return false
156
+ end
157
+
158
+ on_response_header(@response_header)
159
+
160
+ @state = :body
161
+ @bytes_remaining = @response_header.content_length
162
+
163
+ true
164
+ end
165
+ =end
166
+ =begin
167
+ def parse_header(header)
168
+ return false if @data.empty?
169
+
170
+ key = nil
171
+ if idx = @data.to_str.index("\r\n\r\n")
172
+ ctx = idx + 4
173
+ key = @data.to_str[0, ctx]
174
+ #key = Digest::MD5::digest(@data.to_str[0, ctx])
175
+ if obj = searchcache(key)
176
+ @parser_nbytes = 0
177
+ @data.read(ctx)
178
+ @parser.reset
179
+ @response_header = obj
180
+ return true
181
+ end
182
+ end
183
+ begin
184
+ @parser_nbytes = @parser.execute(header, @data.to_str, @parser_nbytes)
185
+ rescue Rev::HttpClientParserError
186
+ on_error "invalid HTTP format, parsing fails"
187
+ @state = :invalid
188
+ end
189
+
190
+ return false unless @parser.finished?
191
+
192
+ if key
193
+ insertcache(key, header)
194
+ end
195
+
196
+ # Clear parsed data from the buffer
197
+ @data.read(@parser_nbytes)
198
+ @parser.reset
199
+ @parser_nbytes = 0
200
+
201
+ true
202
+ end
203
+ =end
204
+ @@_cache = {}
205
+ @@_cache_keys = []
206
+ @@_cache_max = 200
207
+ def insertcache key, data
208
+ @@_cache[key] = data.dup
209
+ if @@_cache_keys.size > @@_cache_max
210
+ @@_cache.delete(@@_cache_keys.shift)
211
+ end
212
+ end
213
+ def searchcache key
214
+ if @@_cache.has_key?(key)
215
+ @@_cache_keys << key
216
+ @@_cache[key]
217
+ else
218
+ nil
219
+ end
220
+ end
221
+ def free
222
+ @content = ''
223
+ #@response_header = nil
224
+ #@chunk_header = nil
225
+ @response_time = nil
226
+ @_write_buffer.clear
227
+ #@_write_buffer = nil
228
+ @_read_watcher.detach if @_read_watcher.attached?
229
+ #@_read_watcher = nil
230
+ @_write_watcher.detach if @_write_watcher.attached?
231
+ #@_write_watcher = nil
232
+ @data.clear
233
+ #@data = nil
234
+ #@path = nil
235
+ #@method = nil
236
+ #@options = nil
237
+ #@starttime = nil
238
+ #@_io = nil
239
+ @writable_flag = nil
240
+ @send_flag = nil
241
+ @connected = false
242
+ end
243
+ end
244
+ class RevHttpClient < RevHttpConnection
245
+ def self::create host, port
246
+ #o = self::create_from_port(host, port)
247
+ o = self::new([host, port])
248
+ o.attach(Rev::Loop::default)
249
+ o.prepare(host, port)
250
+ o
251
+ end
252
+ attr_reader :result, :complete
253
+ attr_accessor :timeout, :useragent, :tfactory, :client_queue
254
+ def prepare host, port
255
+ init
256
+ @host = host
257
+ @port = port
258
+ @on_failure = nil
259
+ @on_success = nil
260
+ @on_finish = []
261
+ @client_queue = nil
262
+ _this = self
263
+ @queue = BaseHandler::get_handler('TaskQueue')
264
+ @method_handle_response = method(:handle_response)
265
+ #以下のバグへの対応
266
+ #http://redmine.ruby-lang.org/issues/show/3786
267
+ @method_timeout = lambda{
268
+ _this.handle_timeout
269
+ }
270
+ #@method_timeout = method(:timeout)
271
+ #@method_call_on_success = method(:call_on_success)
272
+ #@method_call_on_failure = method(:call_on_failure)
273
+ end
274
+ def timeout= timeout
275
+ @timeout = timeout
276
+ end
277
+ def set_headers header
278
+ @headers = header
279
+ end
280
+ def set_header key, value
281
+ @headers[key] = value
282
+ end
283
+ def request_send methods, path, body = nil
284
+ @busy = true
285
+ #puts "req: #{object_id}"
286
+ if body
287
+ options = {
288
+ :head => @headers,
289
+ :body => body
290
+ }
291
+ @headers['content-type'] = 'application/x-www-form-urlencoded'
292
+ else
293
+ options = {
294
+ :head => @headers,
295
+ }
296
+ end
297
+ @timer = @tfactory.get
298
+ @timer.on_timer(&@method_timeout)
299
+ @exception = nil
300
+ begin
301
+ request(methods, path, options)
302
+ rescue
303
+ on_error("x")
304
+ end
305
+ end
306
+ def handle_timeout
307
+ @exception = TimeoutError::new('timeout')
308
+ self.on_error
309
+ end
310
+ def set_callback on_success, on_failure
311
+ @on_success = on_success
312
+ @on_failure = on_failure
313
+ end
314
+ def has_callback
315
+ !@on_success.nil? and !@on_failure.nil?
316
+ end
317
+ def set_on_finish on_finish
318
+ @on_finish << on_finish
319
+ end
320
+ def on_finish
321
+ unless @on_finish.empty?
322
+ @on_finish.shift.call
323
+ end
324
+ end
325
+ def on_error(reason='error')
326
+ $REQUEST_COUNT += 1
327
+ super
328
+ @tfactory.collect(@timer) if @timer
329
+ @timer = nil
330
+ @busy = false
331
+ @response = @response_object
332
+ @response.time = @response_time
333
+ @on_failure.call(@exception, @response) if @on_failure
334
+ @exception = nil
335
+ end
336
+ def send_request_header
337
+ #無駄な処理を省くため上書き
338
+ head = @options[:head]
339
+ body = @options[:body]
340
+
341
+ # Set the Content-Length if it hasn't been specified already and a body was given
342
+ # Default to Connection: close
343
+
344
+ # Build the request
345
+ request_header = HTTP_REQUEST_HEADER % [@method, @path]
346
+ request_header << encode_field('Content-Length', (body ? body.length : 0)) << encode_field('Connection', 'close')
347
+ for k, v in head
348
+ request_header << encode_field(k, v)
349
+ end
350
+ request_header << CRLF
351
+ write request_header
352
+ end
353
+ def handle_response
354
+ @tfactory.collect(@timer)
355
+ @client_queue.collect(self)
356
+ #@timer = nil
357
+ @queue.add([@on_success, [self.to_response_object]])
358
+ #@busy = false
359
+ end
360
+ def on_request_complete
361
+ super
362
+ return if @exception
363
+ $REQUEST_COUNT += 1
364
+ @tfactory.collect(@timer)
365
+ @client_queue.collect(self)
366
+ @queue.add([@on_success, [self.to_response_object]])
367
+ #handle_response
368
+ #@queue.add([@method_handle_response, ])
369
+ end
370
+ end
371
+ end
@@ -0,0 +1,70 @@
1
+ #rev向きモンキーパッチ
2
+ module Rev
3
+ class TCPSocket
4
+ def self.connect(addr, port, *args)
5
+ #DNS解決済み。ip v4しかこないことを前提する
6
+ family = ::Socket::AF_INET
7
+ return super(TCPConnectSocket.new(family, addr, port), *args) # this creates a 'real' write buffer so we're ok there with regards to already having a write buffer from the get go
8
+ end
9
+ class TCPConnectSocket
10
+ @@_cache = {}
11
+ def initialize(family, addr, port, host = addr)
12
+ #バグがあったので上書き
13
+ @host, @addr, @port = host, addr, port
14
+ @address_family = nil
15
+
16
+ @socket = super(family, ::Socket::SOCK_STREAM, 0)
17
+ begin
18
+ key = port.to_s + addr
19
+ if @@_cache[key]
20
+ addrin = @@_cache[key]
21
+ else
22
+ addrin = @@_cache[key] = ::Socket.sockaddr_in(port, addr)
23
+ end
24
+ @socket.connect_nonblock(addrin)
25
+ rescue Errno::EINPROGRESS
26
+ end
27
+ end
28
+ end
29
+ end
30
+ class HttpClient
31
+ def on_connect
32
+ @connected = true
33
+ send_request if @method and @path
34
+ end
35
+ def failedtrue
36
+ end
37
+ end
38
+ class Socket
39
+ def connectornil
40
+ @_connector = nil
41
+ end
42
+ end
43
+ class Socket::Connector
44
+ def on_writable
45
+ evl = evloop
46
+ detach
47
+
48
+ if connect_successful?
49
+ #@rev_socket.instance_eval { @_connector = nil }
50
+ @rev_socket.connectornil
51
+ @rev_socket.attach(evl)
52
+ @ruby_socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, [1].pack("l"))
53
+ @ruby_socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true)
54
+
55
+ @rev_socket.on_connect
56
+ else
57
+ #@rev_socket.instance_eval { @_failed = true }
58
+ @rev_socket.failedtrue
59
+ @rev_socket.on_connect_failed
60
+ end
61
+ end
62
+ end
63
+ class IO
64
+ end
65
+ class IO::Watcher
66
+ #__send__は重い
67
+ def on_readable; @rev_io.on_readable; end
68
+ def on_writable; @rev_io.on_writable; end
69
+ end
70
+ end
@@ -0,0 +1,39 @@
1
+ module InternetHakai
2
+ class RevPipe
3
+ extend Rev::Meta
4
+ def initialize
5
+ r, w = ::IO::pipe
6
+ @reader = RWatcher::new(r)
7
+ @writer = Rev::IO::new(w)
8
+ end
9
+ attr_reader :reader
10
+ def attach(loop)
11
+ @loop = loop
12
+ @reader.attach(@loop) unless @reader.attached?
13
+ @writer.attach(@loop) unless @writer.attached?
14
+ end
15
+ def write(data)
16
+ @writer.write(data)
17
+ end
18
+ def on_read &block
19
+ @reader.on_read(&block)
20
+ end
21
+ end
22
+ class RWatcher < Rev::IOWatcher
23
+ extend Rev::Meta
24
+ def initialize r
25
+ @reader = r
26
+ super(r)
27
+ end
28
+ def on_read(data); end
29
+ event_callback :on_read
30
+ def on_readable
31
+ begin
32
+ on_read(@reader.read_nonblock(Rev::IO::INPUT_SIZE))
33
+ rescue Errno::EAGAIN
34
+ # in case there are spurious wakeups from forked processs
35
+ return
36
+ end
37
+ end
38
+ end
39
+ end