conduit 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +22 -0
- data/app/controllers/conduit/responses_controller.rb +14 -0
- data/app/models/conduit/concerns/storage.rb +41 -0
- data/app/models/conduit/request.rb +109 -0
- data/app/models/conduit/response.rb +50 -0
- data/app/models/conduit/subscription.rb +6 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20131209223122_create_conduit_requests.rb +13 -0
- data/db/migrate/20131209223734_create_conduit_responses.rb +10 -0
- data/db/migrate/20140305202729_create_conduit_subscriptions.rb +12 -0
- data/lib/conduit.rb +60 -0
- data/lib/conduit/acts_as_conduit_subscriber.rb +41 -0
- data/lib/conduit/configuration.rb +43 -0
- data/lib/conduit/core/action.rb +136 -0
- data/lib/conduit/core/connection.rb +85 -0
- data/lib/conduit/core/driver.rb +83 -0
- data/lib/conduit/core/parser.rb +55 -0
- data/lib/conduit/core/render.rb +69 -0
- data/lib/conduit/drivers/keep +0 -0
- data/lib/conduit/engine.rb +20 -0
- data/lib/conduit/storage.rb +37 -0
- data/lib/conduit/storage/aws.rb +94 -0
- data/lib/conduit/storage/file.rb +74 -0
- data/lib/conduit/util.rb +17 -0
- data/lib/conduit/version.rb +3 -0
- data/lib/tasks/conduit_tasks.rake +4 -0
- data/spec/classes/acts_as_conduit_subscriber_spec.rb +61 -0
- data/spec/classes/core/action_spec.rb +53 -0
- data/spec/classes/core/driver_spec.rb +24 -0
- data/spec/controllers/responses_controller_spec.rb +29 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +29 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +20 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/conduit.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/schema.rb +46 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/actions/foo.rb +10 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/driver.rb +7 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/parsers/foo.rb +13 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/views/foo.erb +5 -0
- data/spec/dummy/lib/conduit/drivers/my_driver/views/layout.erb +3 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +9707 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/tmp/conduit/1/my_driver/foo/1-response.xml +3 -0
- data/spec/dummy/tmp/conduit/1/my_driver/foo/request.xml +7 -0
- data/spec/models/conduit/request_spec.rb +50 -0
- data/spec/models/conduit/response_spec.rb +52 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/support/helper.rb +15 -0
- data/spec/support/xml/xml_request.xml +7 -0
- data/spec/support/xml/xml_response.xml +3 -0
- metadata +311 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 38426d4ed06704aedc33d972b93160383581e319
|
4
|
+
data.tar.gz: b89d9ef6cc7c13c1ee9fcf492b4c1e2520ddaeab
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2c8516d726d6e17db237a920e31353e592d6542553d9277eae4f74cf79618dbaac09dd79c98fef70400f924d3b1e51c5ab110f8a23e1441a79a953d30343f4f0
|
7
|
+
data.tar.gz: 5d24fe0a44c971cce8571e5ce217e0f6438c118645a8d7408a4aa43298805703eca0607984531f2fcf6515f9fa4ac090ee7114d9296582687eb9550f26f20fb7
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Foo'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Conduit
|
2
|
+
class ResponsesController < ActionController::Base
|
3
|
+
|
4
|
+
# TODO: Determine the actual param the posted content
|
5
|
+
# will be stored in, and modify the code below
|
6
|
+
#
|
7
|
+
def create
|
8
|
+
request = Conduit::Request.find(params[:request_id])
|
9
|
+
request.responses.create(content: params[:content])
|
10
|
+
render nothing: true
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Conduit
|
2
|
+
module Concerns
|
3
|
+
module Storage
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_writer :content
|
8
|
+
|
9
|
+
after_create :add_to_storage, if: :generate_storage_path
|
10
|
+
after_destroy :remove_from_storage, if: :file
|
11
|
+
end
|
12
|
+
|
13
|
+
# Read the content from the storage location
|
14
|
+
#
|
15
|
+
def content
|
16
|
+
@content ||= Conduit::Storage.read(file)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Generate a unique storage key
|
22
|
+
#
|
23
|
+
def generate_storage_path
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
# Remove the file from remote storage
|
28
|
+
#
|
29
|
+
def remove_from_storage
|
30
|
+
Conduit::Storage.delete(file)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Write the content to the storage location
|
34
|
+
#
|
35
|
+
def add_to_storage
|
36
|
+
Conduit::Storage.write(file, content)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Conduit
|
2
|
+
class Request < ActiveRecord::Base
|
3
|
+
include Conduit::Concerns::Storage
|
4
|
+
|
5
|
+
serialize :options, Hash
|
6
|
+
|
7
|
+
# Associations
|
8
|
+
|
9
|
+
has_many :responses, dependent: :destroy
|
10
|
+
has_many :subscriptions, autosave: true
|
11
|
+
|
12
|
+
# Validations
|
13
|
+
|
14
|
+
validates :driver, presence: true
|
15
|
+
validates :action, presence: true
|
16
|
+
|
17
|
+
# Hooks
|
18
|
+
|
19
|
+
after_initialize :set_defaults
|
20
|
+
after_update :notify_subscribers
|
21
|
+
|
22
|
+
# Scopes
|
23
|
+
|
24
|
+
scope :by_action, -> (actions) { where(action: actions) }
|
25
|
+
scope :by_driver, -> (drivers) { where(driver: drivers) }
|
26
|
+
scope :by_status, -> (status) { where(status: status) }
|
27
|
+
|
28
|
+
# Methods
|
29
|
+
|
30
|
+
# Overriding this method fixes an issue
|
31
|
+
# where content isn't set until after
|
32
|
+
# the raw action is instantiated
|
33
|
+
#
|
34
|
+
def content
|
35
|
+
raw.view || super
|
36
|
+
end
|
37
|
+
|
38
|
+
# Perform the requested action
|
39
|
+
# for the specified driver
|
40
|
+
#
|
41
|
+
def perform_request
|
42
|
+
if response = raw.perform
|
43
|
+
responses.create(content: response.body)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Allow creation of subscriptions through the
|
48
|
+
# subscribers virtual attribute.
|
49
|
+
#
|
50
|
+
# NOTE: This is usually possible by default with a
|
51
|
+
# has_many :through, but with polymorphic
|
52
|
+
# association it gets more complicated.
|
53
|
+
#
|
54
|
+
def subscribers=(args)
|
55
|
+
args.map do |arg|
|
56
|
+
next unless arg.class < ActiveRecord::Base
|
57
|
+
subscriptions.build(subscriber: arg)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Fetch a list of subscribers through
|
62
|
+
# the subscriptions association
|
63
|
+
#
|
64
|
+
# NOTE: This is usually possible by default with a
|
65
|
+
# has_many :through, but with polymorphic
|
66
|
+
# association it gets more complicated.
|
67
|
+
#
|
68
|
+
def subscribers
|
69
|
+
subscriptions.map(&:subscriber)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Set some default values
|
75
|
+
#
|
76
|
+
def set_defaults
|
77
|
+
self.status ||= "open"
|
78
|
+
end
|
79
|
+
|
80
|
+
# Generate a unique storage key
|
81
|
+
# TODO: Dynamic File Format
|
82
|
+
#
|
83
|
+
def generate_storage_path
|
84
|
+
update_column(:file, File.join("#{id}".reverse!,
|
85
|
+
driver.to_s, action.to_s, "request.xml"))
|
86
|
+
end
|
87
|
+
|
88
|
+
# Notify the requestable that our status
|
89
|
+
# has changed. This is done by calling
|
90
|
+
# a predefined method name on the
|
91
|
+
# requestable instance
|
92
|
+
#
|
93
|
+
def notify_subscribers
|
94
|
+
last_response = responses.last
|
95
|
+
subscribers.each do |subscriber|
|
96
|
+
subscriber.after_conduit_update(action,
|
97
|
+
last_response.parsed_content)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Raw access to the action instance
|
102
|
+
#
|
103
|
+
def raw
|
104
|
+
@raw ||= Conduit::Util.find_driver(driver,
|
105
|
+
action).new(options.symbolize_keys!)
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Conduit
|
2
|
+
class Response < ActiveRecord::Base
|
3
|
+
include Conduit::Concerns::Storage
|
4
|
+
|
5
|
+
# Associations
|
6
|
+
|
7
|
+
belongs_to :request
|
8
|
+
|
9
|
+
# Validations
|
10
|
+
|
11
|
+
validates :request, presence: true
|
12
|
+
|
13
|
+
# Hooks
|
14
|
+
|
15
|
+
after_create :report_response_status
|
16
|
+
|
17
|
+
# Methods
|
18
|
+
|
19
|
+
delegate :driver, :action, to: :request
|
20
|
+
|
21
|
+
# Raw access to the parser instance
|
22
|
+
#
|
23
|
+
def parsed_content
|
24
|
+
@parsed_content ||= Conduit::Util.find_driver(driver, action, 'parser').new(content)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Generate a storage key based on parent request
|
30
|
+
# TODO: Dynamic File Format
|
31
|
+
#
|
32
|
+
def generate_storage_path
|
33
|
+
update_column(:file, File.join(File.dirname(
|
34
|
+
request.file), "#{id}-response.xml"))
|
35
|
+
end
|
36
|
+
|
37
|
+
# Check for the 'response_status' attribute
|
38
|
+
# from the parsed data, and return that to
|
39
|
+
# the request.
|
40
|
+
#
|
41
|
+
# NOTE: These should be one of the following:
|
42
|
+
# pending/success/failure
|
43
|
+
#
|
44
|
+
def report_response_status
|
45
|
+
status = parsed_content.response_status
|
46
|
+
request.update_attributes(status: status)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateConduitSubscriptions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :conduit_subscriptions do |t|
|
4
|
+
t.references :request, index: true
|
5
|
+
t.integer :subscriber_id
|
6
|
+
t.string :subscriber_type
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
add_index :conduit_subscriptions, [:subscriber_type, :subscriber_id]
|
11
|
+
end
|
12
|
+
end
|
data/lib/conduit.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'conduit/engine'
|
2
|
+
require 'conduit/acts_as_conduit_subscriber'
|
3
|
+
|
4
|
+
module Conduit
|
5
|
+
|
6
|
+
mattr_accessor :app_root
|
7
|
+
|
8
|
+
# Autoload the Conduit base classes
|
9
|
+
# NOTE: Autoloading should be
|
10
|
+
# concurrency-safe
|
11
|
+
#
|
12
|
+
autoload :Configuration, 'conduit/configuration'
|
13
|
+
autoload :Storage, 'conduit/storage'
|
14
|
+
autoload :Util, 'conduit/util'
|
15
|
+
|
16
|
+
module Core
|
17
|
+
|
18
|
+
# Autoload the Conduit::Core base classes
|
19
|
+
# NOTE: Autoloading should be
|
20
|
+
# concurrency-safe
|
21
|
+
#
|
22
|
+
autoload :Connection, 'conduit/core/connection'
|
23
|
+
autoload :Render, 'conduit/core/render'
|
24
|
+
autoload :Action, 'conduit/core/action'
|
25
|
+
autoload :Parser, 'conduit/core/parser'
|
26
|
+
autoload :Driver, 'conduit/core/driver'
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
module Driver
|
31
|
+
|
32
|
+
class << self
|
33
|
+
# Store a list of available drivers
|
34
|
+
#
|
35
|
+
# e.g.
|
36
|
+
# Conduit::Driver.index
|
37
|
+
# => [:foo, :bar, :baz]
|
38
|
+
#
|
39
|
+
def index
|
40
|
+
@index ||= []
|
41
|
+
end
|
42
|
+
|
43
|
+
# Load the drivers automatically, but only when they're needed
|
44
|
+
#
|
45
|
+
def load_drivers
|
46
|
+
Conduit::Configuration.driver_paths.each do |dir|
|
47
|
+
raise "Directory not found: #{dir}" unless File.exists?(dir)
|
48
|
+
Dir["#{dir}/**/driver.rb"].each do |file|
|
49
|
+
raise "File not found: #{file}" unless File.exists?(file)
|
50
|
+
name = File.dirname(file).split(File::SEPARATOR).last.classify.to_sym
|
51
|
+
index << name.downcase
|
52
|
+
autoload name, file
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Conduit
|
2
|
+
module ActsAsConduitSubscriber
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
# Define a method that can be used to inject
|
8
|
+
# methods into an ActiveRecord Model
|
9
|
+
#
|
10
|
+
def acts_as_conduit_subscriber
|
11
|
+
include Conduit::ActsAsConduitSubscriber::LocalInstanceMethods
|
12
|
+
|
13
|
+
has_many :conduit_subscriptions, as: :subscriber, class_name: 'Conduit::Subscription'
|
14
|
+
has_many :conduit_requests, through: :conduit_subscriptions, source: :request
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
# These methods are included when acts_as_conduit_request
|
20
|
+
# is called on an ActiveRecord Model
|
21
|
+
#
|
22
|
+
module LocalInstanceMethods
|
23
|
+
|
24
|
+
# Fire this method after the last conduit
|
25
|
+
# request has been updated
|
26
|
+
#
|
27
|
+
# NOTE: This could probably be better
|
28
|
+
# handled by observers, or a
|
29
|
+
# custom callback.
|
30
|
+
#
|
31
|
+
def after_conduit_update(action, parsed_response)
|
32
|
+
# This method should be overriden
|
33
|
+
# on the requestable object
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
ActiveRecord::Base.send :include, Conduit::ActsAsConduitSubscriber
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# The job of this class is to provide common
|
3
|
+
# configuration options to conduit
|
4
|
+
#
|
5
|
+
|
6
|
+
module Conduit
|
7
|
+
module Configuration
|
8
|
+
class << self
|
9
|
+
|
10
|
+
#
|
11
|
+
# Storage
|
12
|
+
#
|
13
|
+
# Define the storage configuration. This could
|
14
|
+
# include anything from file paths, to
|
15
|
+
# service credentials, and provider
|
16
|
+
#
|
17
|
+
mattr_accessor :storage_config
|
18
|
+
self.storage_config = {
|
19
|
+
provider: :file,
|
20
|
+
file_path: Conduit.app_root.join('tmp', 'conduit')
|
21
|
+
}
|
22
|
+
|
23
|
+
#
|
24
|
+
# Drivers
|
25
|
+
#
|
26
|
+
# Define the driver load path
|
27
|
+
# Define an array of drivers to load
|
28
|
+
#
|
29
|
+
mattr_accessor :driver_paths
|
30
|
+
self.driver_paths = ["#{File.dirname(__FILE__)}/drivers"]
|
31
|
+
|
32
|
+
#
|
33
|
+
# Methods
|
34
|
+
#
|
35
|
+
# Read in the configuration
|
36
|
+
#
|
37
|
+
def configure(&block)
|
38
|
+
yield self
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|