hatetepe 0.6.0.pre → 0.6.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
- # Hatetepe
1
+ # Hatetepe, the HTTP toolkit [![Build Status](https://travis-ci.org/lgierth/hatetepe.png?branch=master)](https://travis-ci.org/lgierth/hatetepe) [![Code Climate](https://codeclimate.com/github/lgierth/hatetepe.png)](https://codeclimate.com/github/lgierth/hatetepe)
2
2
 
3
- The HTTP toolkit
3
+ General purpose toolkit for HTTP clients and servers.
4
+
5
+ Note: The `master` branch contains the latest development effort. Look at the
6
+ `0.5.x` branch for stable releases.
4
7
 
5
8
  ## Installation
6
9
 
@@ -27,9 +30,8 @@ TODO: Write usage instructions here
27
30
  - Unit tests
28
31
  - Method/Status semantics (GET/HEAD/204/etc.)
29
32
  - Host header
33
+ - Date header
30
34
  - Documentation
31
- - Replace into hatetepe-dev
32
- - Deprecate hatetepe-0.5
33
35
  - Future
34
36
  - SSL support
35
37
  - Webmachine adapter
data/bin/hatetepe CHANGED
@@ -1,20 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
3
 
4
- require 'ap'
5
4
  require 'hatetepe'
6
5
 
7
6
  class RequestHandler
8
7
  def initialize(config, server, connection)
9
8
  end
10
9
 
11
- def serve(request)
12
- request.finished.then do
13
- puts "#{request.http_method.upcase} #{request.uri}"
14
- response = build_response
15
- request.served.fulfill(response)
16
- response.finished.fulfill
17
- end
10
+ def serve(request, served)
11
+ puts "#{request.http_method.upcase} #{request.uri}"
12
+ response = build_response
13
+ served.fulfill(response)
18
14
  end
19
15
 
20
16
  def build_response
data/config/flay.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  ---
2
- threshold: 10
3
- total_score: 160
2
+ threshold: 8
3
+ total_score: 147
data/config/reek.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  Attribute:
3
- enabled: true
3
+ enabled: false
4
4
  exclude: []
5
5
  BooleanParameter:
6
6
  enabled: true
@@ -19,13 +19,13 @@ DataClump:
19
19
  DuplicateMethodCall:
20
20
  enabled: true
21
21
  exclude: []
22
- max_calls: 1
22
+ max_calls: 2
23
23
  allow_calls: []
24
24
  FeatureEnvy:
25
- enabled: true
25
+ enabled: false
26
26
  exclude: []
27
27
  IrresponsibleModule:
28
- enabled: true
28
+ enabled: false
29
29
  exclude: []
30
30
  LongParameterList:
31
31
  enabled: true
@@ -33,7 +33,7 @@ LongParameterList:
33
33
  max_params: 2
34
34
  overrides:
35
35
  initialize:
36
- max_params: 3
36
+ max_params: 4
37
37
  LongYieldList:
38
38
  enabled: true
39
39
  exclude: []
@@ -41,7 +41,7 @@ LongYieldList:
41
41
  NestedIterators:
42
42
  enabled: true
43
43
  exclude: []
44
- max_allowed_nesting: 1
44
+ max_allowed_nesting: 2
45
45
  ignore_iterators: []
46
46
  NilCheck:
47
47
  enabled: true
@@ -53,7 +53,7 @@ RepeatedConditional:
53
53
  TooManyInstanceVariables:
54
54
  enabled: true
55
55
  exclude: []
56
- max_instance_variables: 3
56
+ max_instance_variables: 4
57
57
  TooManyMethods:
58
58
  enabled: true
59
59
  exclude: []
@@ -62,7 +62,7 @@ TooManyStatements:
62
62
  enabled: true
63
63
  exclude:
64
64
  - each
65
- max_statements: 2
65
+ max_statements: 5
66
66
  UncommunicativeMethodName:
67
67
  enabled: true
68
68
  exclude: []
@@ -85,7 +85,8 @@ UncommunicativeParameterName:
85
85
  - !ruby/regexp /^.$/
86
86
  - !ruby/regexp /[0-9]$/
87
87
  - !ruby/regexp /[A-Z]/
88
- accept: []
88
+ accept:
89
+ - _
89
90
  UncommunicativeVariableName:
90
91
  enabled: true
91
92
  exclude: []
@@ -93,11 +94,14 @@ UncommunicativeVariableName:
93
94
  - !ruby/regexp /^.$/
94
95
  - !ruby/regexp /[0-9]$/
95
96
  - !ruby/regexp /[A-Z]/
96
- accept: []
97
+ accept:
98
+ - a
99
+ - e
100
+ - _
97
101
  UnusedParameters:
98
102
  enabled: true
99
103
  exclude: []
100
104
  UtilityFunction:
101
- enabled: true
105
+ enabled: false
102
106
  exclude: []
103
107
  max_helper_calls: 0
data/lib/hatetepe.rb CHANGED
@@ -9,10 +9,10 @@ require 'hatetepe/version'
9
9
 
10
10
  require 'hatetepe/errors'
11
11
  require 'hatetepe/support/handlers'
12
- require 'hatetepe/support/keep_alive'
13
12
  require 'hatetepe/support/message'
14
13
 
15
14
  require 'hatetepe/promise'
15
+ require 'hatetepe/body'
16
16
  require 'hatetepe/request'
17
17
  require 'hatetepe/response'
18
18
 
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+
3
+ module Hatetepe
4
+ class Body
5
+ include Promise::Attribute
6
+ promise :closed
7
+
8
+ def self.build(arg)
9
+ if arg.is_a?(Body)
10
+ arg
11
+ else
12
+ body = new(arg.to_str)
13
+ body.closed.fulfill
14
+ body
15
+ end
16
+ end
17
+
18
+ def initialize(string = '')
19
+ @io = StringIO.new(string)
20
+
21
+ closed.on_progress { |str| @io.write(str) }
22
+ end
23
+
24
+ # don't optimize the sync call, we don't wanna search in @io.string
25
+ # because search time increases with its size.
26
+ def gets(*args)
27
+ closed.sync
28
+ @io.gets(*args)
29
+ end
30
+
31
+ def read(length = nil, buffer = nil)
32
+ closed.sync unless optimized_read?(length)
33
+ @io.read(length, buffer)
34
+ end
35
+
36
+ def rewind
37
+ closed.sync
38
+ @io.rewind
39
+ end
40
+
41
+ def each(&block)
42
+ yield_string(&block)
43
+ closed.on_progress(&block)
44
+ closed.sync
45
+ end
46
+
47
+ def to_s
48
+ closed.sync
49
+ @io.string
50
+ end
51
+
52
+ private
53
+
54
+ def optimized_read?(length)
55
+ length && length < (@io.length - pos)
56
+ end
57
+
58
+ def yield_string(&block)
59
+ block.call(@io.string) unless @io.string.empty?
60
+ end
61
+ end
62
+ end
@@ -13,67 +13,67 @@ module Hatetepe
13
13
 
14
14
  setup_connection
15
15
  setup_handlers
16
- notify_handlers(:post_init)
16
+ notify_handlers(:setup)
17
17
  end
18
18
 
19
19
  def request(http_method, uri)
20
20
  request = Request.new(http_method, uri)
21
- request.finished.fulfill
22
- perform(request)
23
- request.served.sync
21
+ perform(request).sync
24
22
  end
25
23
 
26
24
  def perform(request)
27
- @requests << request
25
+ served = Promise.new
26
+ @requests << [request, served]
28
27
 
29
- fiber = Fiber.new do
30
- notify_handlers(:perform, request)
31
- @connection.serialize(request)
32
- end
33
- fiber.resume
34
- end
35
-
36
- def close
37
- @connection.close
28
+ Fiber.new { perform!(request) }.resume
29
+ served
38
30
  end
39
31
 
40
32
  def receive(response)
41
- unless (request = correlate(response))
42
- raise ClientError, 'Unable to correlate with request'
43
- end
33
+ request, served = correlate
34
+
35
+ served.fulfill(response)
36
+ response.closed { finish(request) }
44
37
 
45
- setup_cleanup(request, response)
46
38
  notify_handlers(:receive, request, response)
47
39
  end
48
40
 
41
+ def finish(request)
42
+ @requests.delete_if { |(req, _)| req == request }
43
+ notify_handlers(:finish, request)
44
+ end
45
+
46
+ def close
47
+ @connection.close
48
+ end
49
+
49
50
  def teardown(reason)
50
- while (request = @requests.shift)
51
- if (response = request.served.value)
52
- response.finished.reject(reason)
53
- else
54
- request.served.reject(reason)
51
+ @requests.each do |(_, served)|
52
+ served.reject(reason)
53
+ if (response = served.value)
54
+ response.reject_closed(reason)
55
55
  end
56
56
  end
57
57
  end
58
58
 
59
59
  private
60
60
 
61
+ def perform!(request)
62
+ notify_handlers(:perform, request)
63
+ @connection.serialize(request)
64
+ end
65
+
66
+ def correlate
67
+ tuple = @requests.detect { |(_, served)| served.pending? }
68
+ raise ClientError, 'Unable to correlate with request' unless tuple
69
+ tuple
70
+ end
71
+
61
72
  def setup_connection
62
73
  @connection =
63
74
  EM.connect(@config[:address], @config[:port], Connection::EventMachine)
64
75
  @connection.parse(method(:receive))
65
76
  @connection.closed.then(method(:teardown))
66
77
  end
67
-
68
- def correlate(response)
69
- @requests
70
- .detect { |request| request.served.pending? }
71
- .tap { |request| request.served.fulfill(response) if request }
72
- end
73
-
74
- def setup_cleanup(request, response)
75
- callback = proc { @requests.delete(request) }
76
- response.finished.then(callback, callback)
77
- end
78
78
  end
79
79
  end
@@ -2,58 +2,13 @@
2
2
 
3
3
  module Hatetepe
4
4
  class Client::KeepAlive
5
- CONNECTION = 'Connection'.freeze
6
-
7
- include Support::KeepAlive
8
-
9
- def initialize(config, client, connection)
10
- @config, @client = config, client
11
- @connection = connection
12
- @close = nil
13
- @requests = []
5
+ def initialize(*_)
6
+ @previous = nil
14
7
  end
15
8
 
16
9
  def perform(request)
17
- previous_request = current_request
18
- @requests << request
19
-
20
- if @close.nil?
21
- await_connection_header(request)
22
- elsif !@close
23
- await_previous_response(previous_request) if previous_request
24
- end
25
- end
26
-
27
- def receive(request, response)
28
- @requests.delete(request)
29
- end
30
-
31
- private
32
-
33
- def current_request
34
- @requests.first
35
- end
36
-
37
- def await_connection_header(request)
38
- if current_request == request
39
- # first response has the relevant Connection header
40
- assume_connection_header
41
- else
42
- # subsequent requests wait for first response
43
- current_request.served.sync
44
- end
45
- end
46
-
47
- def assume_connection_header
48
- current_request.served.then do |response|
49
- @close = close_connection?(response.http_version,
50
- response.headers[CONNECTION])
51
- end
52
- end
53
-
54
- def await_previous_response(request)
55
- response = request.served.sync
56
- response.finished.sync
10
+ @previous, previous = request, @previous
11
+ previous.closed! if previous
57
12
  end
58
13
  end
59
14
  end
@@ -3,15 +3,15 @@
3
3
  module Hatetepe
4
4
  # @see EM.heartbeat_interval
5
5
  class Client::Timeouts
6
- def initialize(config, client, connection)
7
- @config, @client = config, client
6
+ def initialize(config, _, connection)
7
+ @config = config
8
8
  @connection = connection
9
9
 
10
10
  @config[:timeout] ||= 2.0
11
11
  @config[:connect_timeout] ||= 2.0
12
12
  end
13
13
 
14
- def post_init
14
+ def setup
15
15
  @connection.comm_inactivity_timeout = @config[:timeout]
16
16
  @connection.pending_connect_timeout = @config[:connect_timeout]
17
17
  end
@@ -6,9 +6,9 @@ module Hatetepe
6
6
  include Promise::Attribute
7
7
  promise :closed
8
8
 
9
- def initialize(callback = nil)
9
+ def initialize(callback = proc {})
10
10
  @parser = HTTP::Parser.new(self)
11
- callback.call(self) if callback
11
+ callback.call(self)
12
12
  end
13
13
 
14
14
  def parse(block)
@@ -21,16 +21,16 @@ module Hatetepe
21
21
  end
22
22
 
23
23
  def receive_data(data)
24
- # ap data
24
+ # ap [__id__, :receive, data]
25
25
  @parser << data
26
26
  # rescue => error
27
27
  # $stderr.puts(error.to_s)
28
- # @message.finished.reject(error) if @message
28
+ # @message.reject_close(error) if @message
29
29
  # close_connection
30
30
  end
31
31
 
32
32
  # def send_data(data)
33
- # ap data
33
+ # ap [__id__, :send, data]
34
34
  # super
35
35
  # end
36
36
 
@@ -49,12 +49,11 @@ module Hatetepe
49
49
  end
50
50
 
51
51
  def on_body(chunk)
52
- @message.body << chunk
53
- @message.finished.progress(chunk)
52
+ @message.body.closed.progress(chunk)
54
53
  end
55
54
 
56
55
  def on_message_complete
57
- @message.finished.fulfill
56
+ @message.close
58
57
  end
59
58
  end
60
59
  end