hoth 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,45 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ hoth (0.3.0)
5
+ activesupport
6
+ bertrpc
7
+ json
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activesupport (3.0.3)
13
+ bert (1.1.2)
14
+ bertrpc (1.3.0)
15
+ bert (>= 1.1.0, < 2.0.0)
16
+ diff-lcs (1.1.2)
17
+ eventmachine (0.12.10)
18
+ json (1.4.6)
19
+ memcache-client (1.8.5)
20
+ rspec (2.4.0)
21
+ rspec-core (~> 2.4.0)
22
+ rspec-expectations (~> 2.4.0)
23
+ rspec-mocks (~> 2.4.0)
24
+ rspec-core (2.4.0)
25
+ rspec-expectations (2.4.0)
26
+ diff-lcs (~> 1.1.2)
27
+ rspec-mocks (2.4.0)
28
+ simple_publisher (0.1.1)
29
+ starling
30
+ system_timer
31
+ starling (0.10.1)
32
+ eventmachine (>= 0.12.0)
33
+ memcache-client (>= 1.7.0)
34
+ system_timer (1.0)
35
+
36
+ PLATFORMS
37
+ ruby
38
+
39
+ DEPENDENCIES
40
+ activesupport
41
+ bertrpc
42
+ hoth!
43
+ json
44
+ rspec
45
+ simple_publisher
@@ -18,6 +18,8 @@ require 'hoth/util/logger'
18
18
  require 'hoth/extension/core/exception'
19
19
  require 'hoth/exceptions'
20
20
 
21
+ require 'digest/sha1'
22
+
21
23
  module Hoth
22
24
 
23
25
  class <<self
@@ -25,6 +27,11 @@ module Hoth
25
27
  load_service_definition
26
28
  load_module_definition
27
29
  Logger.init_logging!
30
+ @client_uuid = Digest::SHA1.hexdigest("Time.now--#{rand()}")
31
+ end
32
+
33
+ def client_uuid
34
+ @client_uuid
28
35
  end
29
36
 
30
37
  def config_path
@@ -11,4 +11,11 @@ module Hoth
11
11
 
12
12
  class TransportError < HothException; end
13
13
  class TransportException < HothException; end
14
+
15
+ class EncodingError < HothException; end
16
+
17
+ class EmptyServiceNameError < HothException; end
18
+ class ServiceNotFoundException < HothException; end
19
+
20
+ class RecursiveServiceCallException < HothException; end
14
21
  end
@@ -4,8 +4,8 @@ module Hoth
4
4
  module Providers
5
5
  class RackProvider
6
6
 
7
- def initialize(app)
8
- @app = app
7
+ def initialize(app=nil)
8
+ @app = app || lambda {|env| [404, {'Content-Type' => "text/plain"}, ["Nothing here!"]]}
9
9
  end
10
10
 
11
11
  def call(env)
@@ -13,33 +13,42 @@ module Hoth
13
13
  if env["PATH_INFO"] =~ /^\/execute/
14
14
  begin
15
15
  req = Rack::Request.new(env)
16
+ Hoth::Logger.debug "req: #{req.inspect}"
16
17
 
17
18
  service_name = req.params["name"]
18
19
  service_params = req.params["params"]
19
-
20
+
21
+ raise EmptyServiceNameError.new("You must provide a service name!") if service_name.nil?
22
+
20
23
  responsible_service = ServiceRegistry.locate_service(service_name)
21
-
24
+
25
+ raise ServiceNotFoundException.new("The requested service '#{service_name}' was not found!") if responsible_service.nil?
26
+
27
+ # check if we have called ourself
28
+ raise RecursiveServiceCallException.new("Service caller and callee have the same Client-UUID!") if req.params["caller_uuid"] == Hoth.client_uuid
29
+
22
30
  decoded_params = responsible_service.transport.encoder.decode(service_params)
23
31
  result = Hoth::Services.send(service_name, *decoded_params)
24
-
32
+
25
33
  encoded_result = responsible_service.transport.encoder.encode({"result" => result})
26
-
34
+
27
35
  [200, {'Content-Type' => responsible_service.transport.encoder.content_type, 'Content-Length' => "#{encoded_result.length}"}, [encoded_result]]
28
36
  rescue Exception => e
29
- Hoth::Logger.debug "e: #{e.message}"
37
+ Hoth::Logger.error "e: #{e.message}"
38
+
30
39
  if responsible_service
31
40
  encoded_error = responsible_service.transport.encoder.encode({"error" => e})
32
- [500, {'Content-Type' => service.transport.encoder.content_type, 'Content-Length' => "#{encoded_error.length}"}, [encoded_error]]
41
+ [500, {'Content-Type' => responsible_service.transport.encoder.content_type, 'Content-Length' => "#{encoded_error.length}"}, [encoded_error]]
33
42
  else
34
- plain_error = "An error occuered! (#{e.message})"
35
- [500, {'Content-Type' => "text/plain", 'Content-Length' => "#{plain_error.length}"}, [plain_error]]
43
+ plain_error = "An error occurred! (#{e.message})"
44
+ [e.class == ServiceNotFoundException ? 404 : 500, {'Content-Type' => "text/plain", 'Content-Length' => "#{plain_error.length}"}, [plain_error]]
36
45
  end
37
46
  end
38
47
  else
39
48
  @app.call(env)
40
49
  end
41
50
  end
42
-
51
+
43
52
  end
44
53
  end
45
54
  end
@@ -1,5 +1,6 @@
1
1
  require 'hoth/transport/base'
2
2
  require 'hoth/transport/http'
3
+ require 'hoth/transport/https'
3
4
  require 'hoth/transport/bert'
4
5
  require 'hoth/transport/workling'
5
6
 
@@ -15,6 +16,13 @@ module Hoth
15
16
  :encoder => Encoding::Json
16
17
  },
17
18
  :http => :json_via_http,
19
+
20
+ :json_via_https => {
21
+ :transport_class => Transport::Https,
22
+ :encoder => Encoding::Json
23
+ },
24
+ :https => :json_via_https,
25
+
18
26
  :workling => {
19
27
  :transport_class => Transport::Workling
20
28
  }
@@ -4,14 +4,10 @@ module Hoth
4
4
  module Transport
5
5
  class Http < Base
6
6
  def call_remote_with(*params)
7
- unless return_nothing?
8
- begin
9
- handle_response post_payload(params)
10
- rescue Exception => e
11
- raise TransportError.wrap(e)
12
- end
13
- else
14
- return nil
7
+ begin
8
+ handle_response post_payload(params)
9
+ rescue Exception => e
10
+ raise TransportError.wrap(e)
15
11
  end
16
12
  end
17
13
 
@@ -35,8 +31,9 @@ module Hoth
35
31
  def post_payload(payload)
36
32
  uri = URI.parse(self.endpoint.to_url)
37
33
  return Net::HTTP.post_form(uri,
38
- 'name' => self.name.to_s,
39
- 'params' => encoder.encode(payload)
34
+ 'name' => self.name.to_s,
35
+ 'caller_uuid' => Hoth.client_uuid,
36
+ 'params' => encoder.encode(payload)
40
37
  )
41
38
  end
42
39
 
@@ -0,0 +1,31 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+
4
+ module Hoth
5
+ module Transport
6
+ class Https < Http
7
+ def post_payload(payload)
8
+ uri = URI.parse(self.endpoint.to_url)
9
+
10
+ post = Net::HTTP::Post.new(uri.path)
11
+
12
+ post.set_form_data({
13
+ 'name' => self.name.to_s,
14
+ 'caller_uuid' => Hoth.client_uuid,
15
+ 'params' => encoder.encode(payload)
16
+ }, ';')
17
+
18
+ request = Net::HTTP.new(uri.host, uri.port)
19
+ request.use_ssl = true
20
+ response = request.start {|http| http.request(post) }
21
+
22
+ case response
23
+ when Net::HTTPSuccess, Net::HTTPRedirection
24
+ response
25
+ else
26
+ response.error!
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,46 +1,43 @@
1
1
  module Hoth
2
2
  class Logger
3
3
  class <<self
4
-
4
+
5
5
  def log_provider=(log_provider)
6
6
  @log_provider = log_provider
7
7
  end
8
-
9
- def init_logging!
8
+
9
+ def init_logging!(logfile="log/hoth.log")
10
10
  Hoth::Logger.log_provider = if Object.const_defined?("Rails")
11
11
  Rails.logger
12
12
  else
13
13
  require 'logger'
14
- ::Logger.new("/tmp/hoth.log")
14
+ ::Logger.new(logfile)
15
15
  end
16
16
  end
17
-
17
+
18
18
  def debug(msg)
19
19
  log_provider.debug msg
20
20
  end
21
-
21
+
22
22
  def info(msg)
23
23
  log_provider.info msg
24
24
  end
25
-
25
+
26
26
  def warn(msg)
27
27
  log_provider.warn msg
28
28
  end
29
-
29
+
30
30
  def error(msg)
31
31
  log_provider.error msg
32
32
  end
33
-
33
+
34
34
  def fatal(msg)
35
35
  log_provider.fatal msg
36
36
  end
37
-
38
- private
39
-
40
- def log_provider
41
- @log_provider || init_logging!
42
- end
37
+
38
+ def log_provider
39
+ @log_provider || init_logging!
40
+ end
43
41
  end
44
-
45
42
  end
46
43
  end
@@ -10,6 +10,7 @@ module Hoth
10
10
  describe RackProvider do
11
11
 
12
12
  it "should get transport and encoder based on called service" do
13
+ Hoth.should_receive(:client_uuid).and_return("CALLER_UUID")
13
14
  app = stub("ApplicationStub").as_null_object
14
15
  middleware = Hoth::Providers::RackProvider.new(app)
15
16
 
@@ -40,10 +41,10 @@ module Hoth
40
41
  rack_response = middleware.call env
41
42
  rack_response.first.should == 500 #status code
42
43
  rack_response.last.should be_a_kind_of(Array)
43
- rack_response.last.first.should == "An error occuered! (RuntimeError)"
44
+ rack_response.last.first.should == "An error occurred! (RuntimeError)"
44
45
  end
45
46
 
46
47
  end
47
48
 
48
49
  end
49
- end
50
+ end
@@ -42,7 +42,16 @@ module Hoth
42
42
  service.should_receive(:is_local?).and_return(true)
43
43
  service.impl_class.should_receive(:execute).with(:arg1, :arg2)
44
44
 
45
- service.execute(:arg1, :arg2)
45
+ service.execute(:arg1, :arg2).should be(nil)
46
+ end
47
+
48
+ it "should execute the service stub locally if its impl-class was found and return a value" do
49
+ service = Service.new("test_service") { |p1, p2| returns :value }
50
+
51
+ service.should_receive(:is_local?).and_return(true)
52
+ service.impl_class.should_receive(:execute).with(:arg1, :arg2).and_return(result = mock("ResultMock"))
53
+
54
+ service.execute(:arg1, :arg2).should be(result)
46
55
  end
47
56
 
48
57
  it "should call the remote service if impl-class does not exist" do
@@ -3,47 +3,44 @@ require File.expand_path(File.join(File.dirname(__FILE__), '../../', 'spec_help
3
3
  module Hoth
4
4
  module Transport
5
5
  describe Http do
6
-
6
+
7
7
  before(:each) do
8
8
  @service_mock = mock("ServiceMock")
9
9
  end
10
-
10
+
11
11
  it "should call a remote via http" do
12
- @service_mock.should_receive(:return_nothing?).and_return(false)
13
-
14
12
  params = {:first_name => "Seras", :last_name => "Victoria"}
15
13
 
16
14
  transport = Http.new(@service_mock)
17
15
  transport.should_receive(:post_payload).with([params])
18
16
  transport.call_remote_with(params)
19
17
  end
20
-
18
+
21
19
  it "should post payload encoded with JSON" do
20
+ Hoth.should_receive(:client_uuid).and_return("CLIENT_UUID")
22
21
  @service_mock.should_receive(:endpoint).and_return(endpoint = mock("EndpointMock"))
23
22
  @service_mock.should_receive(:name).and_return("service_name")
24
23
  endpoint.should_receive(:to_url).and_return("http://localhost:3000/execute")
25
24
 
26
25
  encoder = mock("JsonEncoderMock")
27
26
  encoder.should_receive(:encode).with("params").and_return("encoded_params")
28
-
27
+
29
28
  URI.should_receive(:parse).with("http://localhost:3000/execute").and_return(uri = mock("URIMock"))
30
- Net::HTTP.should_receive(:post_form).with(uri, {"name" => "service_name", "params" => "encoded_params"})
31
-
29
+ Net::HTTP.should_receive(:post_form).with(uri, {"name" => "service_name", "params" => "encoded_params", "caller_uuid" => "CLIENT_UUID"})
30
+
32
31
  transport = Http.new(@service_mock, {:encoder => encoder})
33
32
  transport.post_payload("params")
34
33
  end
35
-
34
+
36
35
  describe "Error Handling" do
37
-
36
+
38
37
  before(:each) do
39
38
  service_mock = mock("ServiceMock")
40
- service_mock.should_receive(:return_nothing?).any_number_of_times.and_return(false)
41
-
42
39
  @params = {:first_name => "Seras", :last_name => "Victoria"}
43
40
  encoder = mock("JsonEncoderMock")
44
41
  @transport = Http.new(service_mock, {:encoder => encoder})
45
42
  end
46
-
43
+
47
44
  it "should handle http connection error" do
48
45
  @transport.should_receive(:post_payload).and_raise(Exception)
49
46
  lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
@@ -70,8 +67,53 @@ module Hoth
70
67
  lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
71
68
  end
72
69
  end
73
- end
74
70
 
71
+ it "should handle Timeout::Error and wrap them in a TransportError" do
72
+ @transport.should_receive(:post_payload).and_raise(Timeout::Error)
73
+ lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
74
+ end
75
+
76
+ it "should handle Errno::EINVAL and wrap them in a TransportError" do
77
+ @transport.should_receive(:post_payload).and_raise(Errno::EINVAL)
78
+ lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
79
+ end
80
+
81
+ it "should handle Errno::ECONNRESET and wrap them in a TransportError" do
82
+ @transport.should_receive(:post_payload).and_raise(Errno::ECONNRESET)
83
+ lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
84
+ end
85
+
86
+ it "should handle EOFError and wrap them in a TransportError" do
87
+ @transport.should_receive(:post_payload).and_raise(EOFError)
88
+ lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
89
+ end
90
+
91
+ it "should handle Net::HTTPBadResponse and wrap them in a TransportError" do
92
+ @transport.should_receive(:post_payload).and_raise(Net::HTTPBadResponse)
93
+ lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
94
+ end
95
+
96
+ it "should handle Net::HTTPHeaderSyntaxError and wrap them in a TransportError" do
97
+ @transport.should_receive(:post_payload).and_raise(Net::HTTPHeaderSyntaxError)
98
+ lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
99
+ end
100
+
101
+ it "should handle Net::ProtocolError and wrap them in a TransportError" do
102
+ @transport.should_receive(:post_payload).and_raise(Net::ProtocolError)
103
+ lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
104
+ end
105
+
106
+ it "should handle Errno::ECONNREFUSED and wrap them in a TransportError" do
107
+ @transport.should_receive(:post_payload).and_raise(Errno::ECONNREFUSED)
108
+ lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
109
+ end
110
+
111
+ it "should handle SocketError and wrap them in a TransportError" do
112
+ @transport.should_receive(:post_payload).and_raise(SocketError)
113
+ lambda { @transport.call_remote_with(@params) }.should raise_error(TransportError)
114
+ end
115
+ end
75
116
  end
117
+
76
118
  end
77
119
  end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hoth
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 17
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 3
8
- - 0
9
- version: 0.3.0
9
+ - 1
10
+ version: 0.3.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - Dirk Breuer
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-03-31 00:00:00 +02:00
18
+ date: 2011-01-03 00:00:00 +01:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: activesupport
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 3
27
30
  segments:
28
31
  - 0
29
32
  version: "0"
@@ -33,9 +36,11 @@ dependencies:
33
36
  name: bertrpc
34
37
  prerelease: false
35
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
36
40
  requirements:
37
41
  - - ">="
38
42
  - !ruby/object:Gem::Version
43
+ hash: 3
39
44
  segments:
40
45
  - 0
41
46
  version: "0"
@@ -45,9 +50,11 @@ dependencies:
45
50
  name: json
46
51
  prerelease: false
47
52
  requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
48
54
  requirements:
49
55
  - - ">="
50
56
  - !ruby/object:Gem::Version
57
+ hash: 3
51
58
  segments:
52
59
  - 0
53
60
  version: "0"
@@ -57,9 +64,11 @@ dependencies:
57
64
  name: rspec
58
65
  prerelease: false
59
66
  requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
60
68
  requirements:
61
69
  - - ">="
62
70
  - !ruby/object:Gem::Version
71
+ hash: 3
63
72
  segments:
64
73
  - 0
65
74
  version: "0"
@@ -69,9 +78,11 @@ dependencies:
69
78
  name: simple_publisher
70
79
  prerelease: false
71
80
  requirement: &id005 !ruby/object:Gem::Requirement
81
+ none: false
72
82
  requirements:
73
83
  - - ">="
74
84
  - !ruby/object:Gem::Version
85
+ hash: 3
75
86
  segments:
76
87
  - 0
77
88
  version: "0"
@@ -91,6 +102,7 @@ extra_rdoc_files:
91
102
  - README.rdoc
92
103
  - TODO
93
104
  files:
105
+ - Gemfile.lock
94
106
  - README.rdoc
95
107
  - THANKS.md
96
108
  - lib/hoth.rb
@@ -111,6 +123,7 @@ files:
111
123
  - lib/hoth/transport/base.rb
112
124
  - lib/hoth/transport/bert.rb
113
125
  - lib/hoth/transport/http.rb
126
+ - lib/hoth/transport/https.rb
114
127
  - lib/hoth/transport/workling.rb
115
128
  - lib/hoth/util/logger.rb
116
129
  - spec/spec_helper.rb
@@ -129,7 +142,7 @@ files:
129
142
  - LICENSE
130
143
  - TODO
131
144
  has_rdoc: true
132
- homepage: http://github.com/railsbros/hoth
145
+ homepage: http://github.com/galaxycats/hoth
133
146
  licenses: []
134
147
 
135
148
  post_install_message:
@@ -138,23 +151,27 @@ rdoc_options:
138
151
  require_paths:
139
152
  - lib
140
153
  required_ruby_version: !ruby/object:Gem::Requirement
154
+ none: false
141
155
  requirements:
142
156
  - - ">="
143
157
  - !ruby/object:Gem::Version
158
+ hash: 3
144
159
  segments:
145
160
  - 0
146
161
  version: "0"
147
162
  required_rubygems_version: !ruby/object:Gem::Requirement
163
+ none: false
148
164
  requirements:
149
165
  - - ">="
150
166
  - !ruby/object:Gem::Version
167
+ hash: 3
151
168
  segments:
152
169
  - 0
153
170
  version: "0"
154
171
  requirements: []
155
172
 
156
173
  rubyforge_project:
157
- rubygems_version: 1.3.6
174
+ rubygems_version: 1.3.7
158
175
  signing_key:
159
176
  specification_version: 3
160
177
  summary: Registry and deployment description abstraction for SOA-Services