Skip to content

Commit

Permalink
first raw version
Browse files Browse the repository at this point in the history
  • Loading branch information
schorsch committed May 7, 2010
0 parents commit 5bea5c4
Show file tree
Hide file tree
Showing 10 changed files with 459 additions and 0 deletions.
59 changes: 59 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
require 'rubygems'
require 'rake'

begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "sk-hoth"
gem.summary = %Q{Registry and deployment description abstraction for SOA-Services. Tweaked by SalesKing}
gem.description = <<-DESCRIPTION
Creating a SOA requires a centralized location to define all services within the
SOA. Furthermore you want to know where to deploy those services.
DESCRIPTION
gem.email = "gl@salesking.eu"
gem.homepage = "http://github.com/salesking/king_soa"
gem.authors = ['Georg Leciejewski']
gem.files = FileList["[A-Z]*.*", "{lib,spec}/**/*"]

gem.add_dependency "curb"
gem.add_dependency "json"
gem.add_dependency "king_hmac"

gem.add_development_dependency "rspec"
# gem.add_development_dependency "rack/test"
gem.add_development_dependency "webmock"
end
Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
end

require 'spec/rake/spectask'
Spec::Rake::SpecTask.new(:spec) do |spec|
spec.libs << 'lib' << 'spec'
spec.spec_files = FileList['spec/**/*_spec.rb']
end

Spec::Rake::SpecTask.new(:rcov) do |spec|
spec.libs << 'lib' << 'spec'
spec.pattern = 'spec/**/*_spec.rb'
spec.rcov = true
end

task :spec => :check_dependencies

task :default => :spec

require 'rake/rdoctask'
Rake::RDocTask.new do |rdoc|
if File.exist?('VERSION')
version = File.read('VERSION')
else
version = ""
end

rdoc.rdoc_dir = 'rdoc'
rdoc.title = "KingSoa #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end
60 changes: 60 additions & 0 deletions lib/king_soa.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require 'singleton'
require 'json'
require 'typhoeus'
#require 'king_hmac'
require 'active_support/inflector'

require 'king_soa/registry'
require 'king_soa/service'
require 'king_soa/rack/middleware'

# Define available services.
#
# service:
# name: sign_document
# url: "https://msg.salesking.eu"
# hmac: 'key:secret'#
# queue: a-queue-name
#
#
#
# method:
# name: sign_document
# # if given the named resque queue will be used
# queue: signings
#
# method: save_signed_document
# url: "https://www.salesking.eu/soa"
#
#
# after defining your services you can call each of them with
# <tt>Hoth::Services.service_name(params)</tt>
#
# KingSoa.sign_document(counter)
# current_number = Hoth::Services.value_of_counter(counter)
# created_account = Hoth::Services.create_account(account)
#
module KingSoa

class << self

def init_from_yaml(loc)

end
# Locate service by a given name
# ==== Params
# service<String|Symbol>:: the name to lookup
def find(service)
Registry[service]
end
# this is where the services get called
def method_missing(meth, *args, &blk) # :nodoc:
if service = Registry[meth]
service.execute(*args)
else
super
end
end
end

end
47 changes: 47 additions & 0 deletions lib/king_soa/rack/middleware.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module KingSoa::Rack
class Middleware

def initialize(app)
@app = app
end

# Takes incoming soa requests and calls the passed in method with given params
def call(env)
# Hoth::Logger.debug "env: #{env.inspect}"
if env["PATH_INFO"] =~ /^\/soa/
begin
req = Rack::Request.new(env)
# find service
service = KingSoa.find(req.params["name"])
# authenticate
authenticated?(service, req.params["auth_key"])
# execute method with decoded params
result = service.execute(*service.decode( req.params["params"] ))
# encode result
encoded_result = service.encode({"result" => result})
# and return
[ 200,
{'Content-Type' => 'application/json',
'Content-Length' => "#{encoded_result.length}"},
[encoded_result] ]
rescue Exception => e
#Hoth::Logger.debug "e: #{e.message}"
if service
encoded_error = service.encode({"error" => e})
[500, {'Content-Type' => 'application/json', 'Content-Length' => "#{encoded_error.length}"}, [encoded_error]]
else
encoded_error = {"error" => "An error occurred! (#{e.message})"}.to_json
[500, {'Content-Type' => "application/json", 'Content-Length' => "#{encoded_error.length}"}, [encoded_error]]
end
end
else
@app.call(env)
end
end

def authenticated?(service, key)
raise "Please provide a valid authentication key" unless service.auth_key == key
end

end
end
44 changes: 44 additions & 0 deletions lib/king_soa/registry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module KingSoa
class Registry
include Singleton

############################################################################
# Class methods
############################################################################

# Get a method by a given name
def self.[](service_name)
instance[service_name]
end
# add a service
def self.<<(service)
instance << service
end
# Return an array of defined services
def self.services
instance.services
end

############################################################################
# Instance methods - not accessible => Singleton
############################################################################

# returns all available methods
def services
@services ||= []
end

# Add a new method onto the stack
def <<(service)
(services || []) << service
end

# Get a method by a given name
def [](service_name)
name = service_name.to_sym
services.detect {|s| s.name == name }
end


end
end
92 changes: 92 additions & 0 deletions lib/king_soa/service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
module KingSoa
class Service
# endpoint url
attr_accessor :debug, :name, :auth_key, :queue, :response
attr_reader :request

def initialize(opts)
self.name = opts[:name].to_sym
self.url = opts[:url] if opts[:url]
self.queue = opts[:queue] if opts[:queue]
self.auth_key = opts[:auth_key] if opts[:auth_key]
end

def call_remote(*args)
set_request_opts(args)
resp_code = @request.perform
case resp_code
when 200
#Hoth::Loggerequest.debug "response.body: #{response.body}"
return self.decode(@request.response_body)["result"]
else
#Hoth::Loggerequest.debug "response.body: #{response.body}"
return self.decode(@request.response_body)["error"]
end
end

def execute(*args)
result = local_class ? local_class.send(:execute, *args) : call_remote(*args)
return result
end

def local_class
@local_class_name ||= "#{self.name.to_s.camelize}"
begin
@local_class_name.constantize
rescue NameError => e # no local implementation
false
end
end

def request
@request ||= Typhoeus::Easy.new
end

def set_request_opts(args)
r = request
request.url = url
request.method = :post
request.user_agent = 'KingSoa'
request.follow_location = true
request.timeout = 100 # milliseconds
request.params = params(args)
request.verbose = 1 if debug

end

# Url receiving the request
# TODO. if not present try to grab from endpoint
def url
@url
end
def url=(url)
@url = "#{url}/soa"
end

def encode(string)
string.to_json
end

def decode(string)
begin
JSON.parse(string)
rescue JSON::ParserError => e
raise e
end
end

# The params for each soa request consisnt of two values:
# name => the name of the method to call
# params => the parameters for the method
# ==== Parameter
# params<Hash|Array|String>:: will be json encoded
# === Returns
# <Hash{String=>String}>:: params added to the POST body
def params(payload)
{ 'name' => name.to_s,
'params' => encode(payload),
'auth_key'=> auth_key }
end

end
end
26 changes: 26 additions & 0 deletions spec/king_soa/rack/middleware_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require File.dirname(__FILE__) + '/../../spec_helper.rb'

#set :environment, :test

describe KingSoa::Rack::Middleware do
include Rack::Test::Methods

before(:each) do
@service = KingSoa::Service.new(:url=>'localhost', :name=>'a_method')
KingSoa::Registry << @service
end


def app
dummy_app = lambda { |env| puts "in dummy"; [200, {}, ""] }
KingSoa::Rack::Middleware.new(dummy_app)
end

it "says hello" do
get '/soa', :name=>'a_method', :params=> "#{{:number=>1}.to_json}"
last_response.should == 'ads'#be_ok
last_response.body.should == 'Hello World'
end


end
28 changes: 28 additions & 0 deletions spec/king_soa/registry_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require File.dirname(__FILE__) + '/../spec_helper.rb'

describe KingSoa::Registry do
before(:each) do

end

it "should return empty services" do
reg = KingSoa::Registry.new
reg.services.should == []
end

it "should add service" do
reg = KingSoa::Registry.new
s = KingSoa::Service.new(:url=>'http://localhost')
reg << s
reg.services.should == [s]
end

it "should return a service by name" do
reg = KingSoa::Registry.new
s = KingSoa::Service.new(:name=>:save_document, :url=>'http://localhost')
reg << s
reg[:save_document].should == s
end


end
Loading

0 comments on commit 5bea5c4

Please sign in to comment.