king_soa 0.0.1 → 0.0.2

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.
@@ -13,24 +13,28 @@ module KingSoa::Rack
13
13
  req = Rack::Request.new(env)
14
14
  # find service
15
15
  service = KingSoa.find(req.params["name"])
16
+ # TODO rescue service class not found
17
+ raise "The service: #{req.params["name"]} could not be found" unless service
16
18
  # authenticate
17
- authenticated?(service, req.params["auth_key"])
18
- # perform method with decoded params
19
- result = service.perform(*service.decode( req.params["params"] ))
19
+ authenticated?(service, req.params["auth"])
20
+ # perform method with decoded params
21
+ result = service.perform(*service.decode( req.params["args"] ))
20
22
  # encode result
21
23
  encoded_result = service.encode({"result" => result})
22
24
  # and return
23
- [ 200,
24
- {'Content-Type' => 'application/json',
25
- 'Content-Length' => "#{encoded_result.length}"},
26
- [encoded_result] ]
25
+ [
26
+ 200,
27
+ {'Content-Type' => 'application/json', 'Content-Length' => "#{encoded_result.length}"},
28
+ [encoded_result]
29
+ ]
30
+
27
31
  rescue Exception => e
28
32
  #Hoth::Logger.debug "e: #{e.message}"
29
33
  if service
30
34
  encoded_error = service.encode({"error" => e})
31
35
  [500, {'Content-Type' => 'application/json', 'Content-Length' => "#{encoded_error.length}"}, [encoded_error]]
32
36
  else
33
- encoded_error = {"error" => "An error occurred! (#{e.message})"}.to_json
37
+ encoded_error = {"error" => "An error occurred => #{e.message}"}.to_json
34
38
  [500, {'Content-Type' => "application/json", 'Content-Length' => "#{encoded_error.length}"}, [encoded_error]]
35
39
  end
36
40
  end
@@ -39,8 +43,9 @@ module KingSoa::Rack
39
43
  end
40
44
  end
41
45
 
46
+ # TODO raise and rescue specific error
42
47
  def authenticated?(service, key)
43
- raise "Please provide a valid authentication key" unless service.auth_key == key
48
+ raise "Please provide a valid authentication key" unless service.auth == key
44
49
  end
45
50
 
46
51
  end
@@ -1,16 +1,18 @@
1
1
  module KingSoa
2
2
  class Service
3
3
  # endpoint url
4
- attr_accessor :debug, :name, :auth_key, :queue
4
+ attr_accessor :debug, :name, :auth, :queue
5
5
  attr_reader :request
6
6
 
7
7
  def initialize(opts)
8
8
  self.name = opts[:name].to_sym
9
9
  self.url = opts[:url] if opts[:url]
10
10
  self.queue = opts[:queue] if opts[:queue]
11
- self.auth_key = opts[:auth_key] if opts[:auth_key]
11
+ self.auth = opts[:auth] if opts[:auth]
12
12
  end
13
13
 
14
+ # Call a service living somewhere in the soa universe. This is done by
15
+ # making a POST request to the url
14
16
  def call_remote(*args)
15
17
  set_request_opts(args)
16
18
  resp_code = @request.perform
@@ -22,20 +24,40 @@ module KingSoa
22
24
  end
23
25
  end
24
26
 
25
- def perform(*args)
26
- result = local_class ? local_class.send(:perform, *args) : call_remote(*args)
27
- return result
27
+ # A queued method MUST have an associated resque worker running and the soa
28
+ # class MUST have the @queue attribute for redis set
29
+ def add_to_queue(*args)
30
+ # use low level resque method since class might not be local available for Resque.enqueue
31
+ Resque::Job.create(queue, local_class_name, *args)
28
32
  end
29
-
33
+
34
+ # Call a method: remote over http, local or put a job onto a queue
35
+ # === Parameter
36
+ # args:: whatever arguments the service methods recieves. Those are later json
37
+ # encoded for remote or queued methods
38
+ def perform(*args)
39
+ if queue
40
+ add_to_queue(*args)
41
+ return nil
42
+ else
43
+ result = local_class ? local_class.send(:perform, *args) : call_remote(*args)
44
+ return result
45
+ end
46
+ end
30
47
 
31
48
  def local_class
32
49
  @local_class ||= begin
33
- "#{self.name.to_s.camelize}".constantize
50
+ local_class_name.constantize
34
51
  rescue NameError => e # no local implementation
35
52
  false
36
53
  end
37
54
  end
38
55
 
56
+ # Return the classname infered from service name
57
+ def local_class_name
58
+ self.name.to_s.camelize
59
+ end
60
+
39
61
  def request
40
62
  @request ||= Typhoeus::Easy.new
41
63
  end
@@ -59,17 +81,20 @@ module KingSoa
59
81
  @url = "#{url}/soa"
60
82
  end
61
83
 
62
- # The params for each soa request consisnt of two values:
63
- # name => the name of the method to call
64
- # params => the parameters for the method
84
+ # The params for each soa request consist of following values:
85
+ # name => the name of the method to call
86
+ # args => the arguments for the soa class method
87
+ # auth => an authentication key. something like a api key or pass. To make
88
+ # it really secure you MUST use https or do not expose your soa endpoints
89
+ #
65
90
  # ==== Parameter
66
- # params<Hash|Array|String>:: will be json encoded
91
+ # payload<Hash|Array|String>:: will be json encoded
67
92
  # === Returns
68
93
  # <Hash{String=>String}>:: params added to the POST body
69
94
  def params(payload)
70
- { 'name' => name.to_s,
71
- 'params' => encode(payload),
72
- 'auth_key'=> auth_key }
95
+ { 'name' => name.to_s,
96
+ 'args' => encode(payload),
97
+ 'auth' => auth }
73
98
  end
74
99
 
75
100
  def encode(string)
data/lib/king_soa.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'singleton'
2
+ require 'resque'
2
3
  require 'json'
3
4
  require 'typhoeus'
4
5
  require 'active_support/inflector'
@@ -21,7 +22,8 @@ require 'king_soa/rack/middleware'
21
22
  #
22
23
  #
23
24
  # after defining your services you can call each of them with
24
- # <tt>Hoth::Services.service_name(params)</tt>
25
+ #
26
+ # <tt>KingSoa.service_name(args)</tt>
25
27
  #
26
28
  # KingSoa.sign_document(counter)
27
29
  # current_number = Hoth::Services.value_of_counter(counter)
@@ -32,12 +34,11 @@ module KingSoa
32
34
  class << self
33
35
 
34
36
  def init_from_hash(services)
35
- # create service
36
-
37
+ # create service
37
38
  end
38
39
 
39
40
  # Locate service by a given name
40
- # ==== Params
41
+ # ==== Parameter
41
42
  # service<String|Symbol>:: the name to lookup
42
43
  def find(service)
43
44
  Registry[service]
@@ -46,7 +47,7 @@ module KingSoa
46
47
  # this is where the services get called
47
48
  def method_missing(meth, *args, &blk) # :nodoc:
48
49
  if service = Registry[meth]
49
- service.execute(*args)
50
+ service.perform(*args)
50
51
  else
51
52
  super
52
53
  end
@@ -8,7 +8,7 @@ describe KingSoa::Rack::Middleware do
8
8
  KingSoa::Registry << @service
9
9
  end
10
10
 
11
- it "should be able to handle exceptions" do
11
+ it "should handle exceptions" do
12
12
  app = stub("ApplicationStub").as_null_object
13
13
  middleware = KingSoa::Rack::Middleware.new(app)
14
14
  env = {"PATH_INFO" => "/soa", "name" => 'a_method'}
@@ -19,18 +19,10 @@ describe KingSoa::Rack::Middleware do
19
19
  rack_response.last.first.should == "{\"error\":\"An error occurred! (Missing rack.input)\"}"
20
20
  end
21
21
 
22
- xit "says hello" do
22
+ xit "should handle result" do
23
23
  app = stub("ApplicationStub").as_null_object
24
- middleware = Hoth::Providers::RackProvider.new(app)
25
-
26
- get '/soa', :name=>'a_method', :params=> "#{{:number=>1}.to_json}"
27
- last_response.should == 'ads'#be_ok
28
- last_response.body.should == 'Hello World'
24
+ middleware = KingSoa::Rack::Middleware.new(app)
25
+ env = {"PATH_INFO" => "/soa"}
26
+ # KingSoa.should_receive(:find).and_return(@service)
29
27
  end
30
-
31
- # def app
32
- # dummy_app = lambda { |env| puts "in dummy"; [200, {}, ""] }
33
- # KingSoa::Rack::Middleware.new(dummy_app)
34
- # end
35
-
36
28
  end
@@ -2,26 +2,23 @@ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
2
 
3
3
  describe KingSoa::Registry do
4
4
  before(:each) do
5
-
5
+ @reg = KingSoa::Registry
6
6
  end
7
7
 
8
8
  it "should return empty services" do
9
- reg = KingSoa::Registry.new
10
- reg.services.should == []
9
+ @reg.services.should == []
11
10
  end
12
11
 
13
- it "should add service" do
14
- reg = KingSoa::Registry.new
15
- s = KingSoa::Service.new(:url=>'http://localhost')
16
- reg << s
17
- reg.services.should == [s]
12
+ it "should add service" do
13
+ s = KingSoa::Service.new(:name=>'process_documents')
14
+ @reg << s
15
+ @reg.services.should == [s]
18
16
  end
19
17
 
20
18
  it "should return a service by name" do
21
- reg = KingSoa::Registry.new
22
19
  s = KingSoa::Service.new(:name=>:save_document, :url=>'http://localhost')
23
- reg << s
24
- reg[:save_document].should == s
20
+ @reg << s
21
+ @reg[:save_document].should == s
25
22
  end
26
23
 
27
24
 
@@ -13,34 +13,40 @@ describe KingSoa::Service, 'local request' do
13
13
 
14
14
  it "should call service" do
15
15
  s = KingSoa::Service.new(:name=>:local_soa_class)
16
- res = s.perform(1,2,3)
17
- res.should == [1,2,3]
16
+ s.perform(1,2,3).should == [1,2,3]
17
+ end
18
+ end
19
+
20
+ describe KingSoa::Service, 'queued' do
21
+
22
+ it "should call queue" do
23
+ s = KingSoa::Service.new(:name=>:local_soa_class, :queue=>:test_queue)
24
+ s.perform(1,2,3).should be_nil
18
25
  end
19
26
  end
20
27
 
21
- # needs the local testserver !!!
22
- # ruby spec/server/app
23
28
  describe KingSoa::Service, 'remote request' do
24
29
 
30
+ before :all do
31
+ start_test_server
32
+ end
33
+
34
+ after :all do
35
+ stop_test_server
36
+ end
37
+
25
38
  it "should call a service remote" do
26
- s = KingSoa::Service.new(:name=>:soa_test_service, :url=>'http://localhost:4567', :auth_key=>'12345')
39
+ s = KingSoa::Service.new(:name=>:soa_test_service, :url=>test_url, :auth=>'12345')
27
40
  s.perform(1,2,3).should == [1,2,3]
28
41
  end
29
42
 
30
43
  it "should call a service remote and return auth error" do
31
- s = KingSoa::Service.new(:name=>:soa_test_service, :url=>'http://localhost:4567', :auth_key=>'wrong')
44
+ s = KingSoa::Service.new(:name=>:soa_test_service, :url=>test_url, :auth=>'wrong')
32
45
  s.perform(1,2,3).should == "Please provide a valid authentication key"
33
46
  end
34
47
 
35
48
  it "should call a service remote and return auth error" do
36
- s = KingSoa::Service.new(:name=>:wrong_service, :url=>'http://localhost:4567', :auth_key=>'12345')
37
- s.perform(1,2,3).should == "An error occurred! (undefined method `auth_key' for nil:NilClass)"
38
- end
39
- end
40
-
41
-
42
- class LocalSoaClass
43
- def self.perform(param1, param2, param3)
44
- return [param1, param2, param3]
49
+ s = KingSoa::Service.new(:name=>:wrong_service, :url=>test_url, :auth=>'12345')
50
+ s.perform(1,2,3).should include("The service: wrong_service could not be found")
45
51
  end
46
52
  end
data/spec/server/app.rb CHANGED
@@ -1,26 +1,29 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
3
  require 'sinatra'
4
- require "#{File.dirname(__FILE__)}/../../lib/king_soa"
4
+ # change since we want the files in here not from installed gem
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
7
+ require "king_soa"
5
8
 
9
+ # this grabs all /soa requests
6
10
  use KingSoa::Rack::Middleware
7
11
 
12
+ # method to kill this server instance
13
+ get '/die' do
14
+ exit!
15
+ end
8
16
 
9
- ###################################################
10
- # method to kill this server instance
11
- #'/die'
12
17
  #######################################
13
- # Somewhere in you app
18
+ # Somewhere in you app define services
14
19
  #
15
20
  # setup test registry
16
- service = KingSoa::Service.new(:name=>'soa_test_service', :auth_key=>'12345')
21
+ service = KingSoa::Service.new(:name=>'soa_test_service', :auth => '12345')
17
22
  KingSoa::Registry << service
18
23
 
19
- # the class beeing called localy
24
+ # the local soa class beeing called
20
25
  class SoaTestService
21
-
22
26
  def self.perform(param1, param2, param3)
23
27
  return [param1, param2, param3]
24
28
  end
25
-
26
29
  end
data/spec/spec_helper.rb CHANGED
@@ -5,33 +5,35 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
5
5
  require 'king_soa'
6
6
  require 'spec'
7
7
  require 'spec/autorun'
8
- # for mocking web requests
9
- require 'webmock/rspec'
10
8
  require 'rack/test'
11
- include WebMock
9
+ # for starting the test sinatra server
10
+ require 'open3'
12
11
 
12
+ def test_url
13
+ 'http://localhost:4567'
14
+ end
13
15
 
16
+ # Start a local test sinatra app receiving the real requests .. no mocking here
17
+ # the server could also be started manually with:
18
+ # ruby spec/server/app
19
+ def start_test_server(wait_time=1)
20
+ # start sinatra test server
21
+ Dir.chdir(File.dirname(__FILE__) + '/server/') do
22
+ @in, @rackup, @err = Open3.popen3("ruby app.rb")
23
+ end
24
+ sleep wait_time # ensure the server is up
25
+ end
14
26
 
15
- def local_service
16
- # Rack::Builder.app do
17
- # use KingSoa::Rack::Middleware
18
- # run super
19
- # end
27
+ def stop_test_server
28
+ Typhoeus::Request.get( "#{test_url}/die")
29
+ end
20
30
 
21
- # Rack::Builder.new do
22
- # use KingSoa::Rack::Middleware
23
- # app = proc do |env|
24
- # [ 200, {'Content-Type' => 'text/plain'}, "b" ]
25
- # end
26
- # run app
27
- # end.to_app
28
- # def app
29
- # Rack::Builder.new {
30
- # # URLs starting with /account (logged in users) go to Rails
31
- # map "/soa" do
32
- # run KingSoa::Rack::Middleware.new
33
- # end
34
- # }.to_app
35
- # end
36
- # app.run
31
+ ################################################################################
32
+ # Local soa classes called in specs
33
+ ################################################################################
34
+
35
+ class LocalSoaClass
36
+ def self.perform(param1, param2, param3)
37
+ return [param1, param2, param3]
38
+ end
37
39
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Georg Leciejewski
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-08 00:00:00 +02:00
17
+ date: 2010-05-09 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -55,7 +55,7 @@ dependencies:
55
55
  version_requirements: *id003
56
56
  description: |
57
57
  Creating a SOA requires a centralized location to define all services within the
58
- SOA. Furthermore you want to know where to deploy those services.
58
+ SOA. KingSoa takes care of keeping services in a service registry and knows how to call them.
59
59
 
60
60
  email: gl@salesking.eu
61
61
  executables: []
@@ -106,7 +106,7 @@ rubyforge_project:
106
106
  rubygems_version: 1.3.6
107
107
  signing_key:
108
108
  specification_version: 3
109
- summary: Registry and deployment description abstraction for SOA-Services by SalesKing
109
+ summary: Abstraction layer for SOA-Services
110
110
  test_files:
111
111
  - spec/spec_helper.rb
112
112
  - spec/king_soa/registry_spec.rb