batsir 0.1.0
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.
- data/.document +5 -0
- data/.rspec +3 -0
- data/.travis.yml +10 -0
- data/Gemfile +22 -0
- data/LICENSE.txt +20 -0
- data/README.md +79 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/batsir.gemspec +104 -0
- data/batsir.png +0 -0
- data/lib/batsir.rb +73 -0
- data/lib/batsir/acceptors/acceptor.rb +45 -0
- data/lib/batsir/acceptors/amqp_acceptor.rb +19 -0
- data/lib/batsir/amqp.rb +45 -0
- data/lib/batsir/chain.rb +33 -0
- data/lib/batsir/config.rb +34 -0
- data/lib/batsir/dsl/dsl_mappings.rb +96 -0
- data/lib/batsir/filter.rb +12 -0
- data/lib/batsir/filter_queue.rb +30 -0
- data/lib/batsir/logo.rb +36 -0
- data/lib/batsir/notifiers/amqp_notifier.rb +16 -0
- data/lib/batsir/notifiers/notifier.rb +39 -0
- data/lib/batsir/registry.rb +15 -0
- data/lib/batsir/stage.rb +94 -0
- data/lib/batsir/stage_worker.rb +86 -0
- data/lib/batsir/transformers/field_transformer.rb +40 -0
- data/lib/batsir/transformers/json_input_transformer.rb +9 -0
- data/lib/batsir/transformers/json_output_transformer.rb +9 -0
- data/lib/batsir/transformers/transformer.rb +15 -0
- data/spec/batsir/acceptors/acceptor_spec.rb +136 -0
- data/spec/batsir/acceptors/amqp_acceptor_spec.rb +169 -0
- data/spec/batsir/chain_spec.rb +31 -0
- data/spec/batsir/dsl/chain_mapping_spec.rb +117 -0
- data/spec/batsir/dsl/stage_mapping_spec.rb +435 -0
- data/spec/batsir/filter_queue_spec.rb +74 -0
- data/spec/batsir/filter_spec.rb +12 -0
- data/spec/batsir/notifiers/amqp_notifier_spec.rb +117 -0
- data/spec/batsir/notifiers/notifier_spec.rb +73 -0
- data/spec/batsir/stage_spec.rb +678 -0
- data/spec/batsir/stage_worker_spec.rb +128 -0
- data/spec/batsir/support/bunny_mocks.rb +62 -0
- data/spec/batsir/support/mock_filters.rb +43 -0
- data/spec/batsir/transformers/field_transformer_spec.rb +73 -0
- data/spec/batsir/transformers/json_input_transformer_spec.rb +22 -0
- data/spec/batsir/transformers/json_output_transformer_spec.rb +18 -0
- data/spec/batsir/transformers/transformer_spec.rb +22 -0
- data/spec/spec_helper.rb +22 -0
- metadata +220 -0
data/lib/batsir/amqp.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Batsir
|
2
|
+
module AMQP
|
3
|
+
attr_accessor :queue
|
4
|
+
attr_accessor :host
|
5
|
+
attr_accessor :port
|
6
|
+
attr_accessor :username
|
7
|
+
attr_accessor :password
|
8
|
+
attr_accessor :vhost
|
9
|
+
attr_accessor :exchange
|
10
|
+
|
11
|
+
def bunny_options
|
12
|
+
{
|
13
|
+
:host => host,
|
14
|
+
:port => port,
|
15
|
+
:user => username,
|
16
|
+
:pass => password,
|
17
|
+
:vhost => vhost
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def host
|
22
|
+
@host || 'localhost'
|
23
|
+
end
|
24
|
+
|
25
|
+
def port
|
26
|
+
@port || 5672
|
27
|
+
end
|
28
|
+
|
29
|
+
def username
|
30
|
+
@username || 'guest'
|
31
|
+
end
|
32
|
+
|
33
|
+
def password
|
34
|
+
@password || 'guest'
|
35
|
+
end
|
36
|
+
|
37
|
+
def vhost
|
38
|
+
@vhost || '/'
|
39
|
+
end
|
40
|
+
|
41
|
+
def exchange
|
42
|
+
@exchange || 'amq.direct'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/batsir/chain.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Batsir
|
2
|
+
class Chain
|
3
|
+
|
4
|
+
def initialize(options = {})
|
5
|
+
options.each do |attr, value|
|
6
|
+
self.send("#{attr.to_s}=", value)
|
7
|
+
end
|
8
|
+
@stages = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def stages
|
12
|
+
@stages
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_stage(stage)
|
16
|
+
@stages << stage
|
17
|
+
end
|
18
|
+
|
19
|
+
def compile
|
20
|
+
generated = ""
|
21
|
+
stages.each do |stage|
|
22
|
+
generated << stage.compile
|
23
|
+
end
|
24
|
+
generated
|
25
|
+
end
|
26
|
+
|
27
|
+
def start
|
28
|
+
stages.each do | stage |
|
29
|
+
stage.start
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Batsir
|
2
|
+
class Config
|
3
|
+
def initialize(data={})
|
4
|
+
@data = {}
|
5
|
+
update!(data)
|
6
|
+
end
|
7
|
+
|
8
|
+
def update!(data)
|
9
|
+
data.each do |key, value|
|
10
|
+
self[key] = value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](key)
|
15
|
+
@data[key.to_sym]
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(key, value)
|
19
|
+
if value.class == Hash
|
20
|
+
@data[key.to_sym] = Config.new(value)
|
21
|
+
else
|
22
|
+
@data[key.to_sym] = value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(sym, *args)
|
27
|
+
if sym.to_s =~ /(.+)=$/
|
28
|
+
self[$1] = args.first
|
29
|
+
else
|
30
|
+
self[sym]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Batsir
|
2
|
+
module DSL
|
3
|
+
class ChainMapping < ::Blockenspiel::Base
|
4
|
+
def initialize
|
5
|
+
@chain = nil
|
6
|
+
end
|
7
|
+
|
8
|
+
def aggregator_chain(&block)
|
9
|
+
@chain = Batsir::Chain.new
|
10
|
+
::Blockenspiel.invoke(block, self)
|
11
|
+
@chain
|
12
|
+
end
|
13
|
+
|
14
|
+
def stage(name, &block)
|
15
|
+
new_block = ::Proc.new do
|
16
|
+
stage name, &block
|
17
|
+
end
|
18
|
+
stage = ::Blockenspiel.invoke(new_block, Batsir::DSL::StageMapping.new)
|
19
|
+
stage.chain = @chain
|
20
|
+
@chain.add_stage(stage)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class StageMapping < ::Blockenspiel::Base
|
25
|
+
def initialize
|
26
|
+
@stage = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def stage(name, &block)
|
30
|
+
@stage = Batsir::Stage.new(:name => name)
|
31
|
+
::Blockenspiel.invoke(block, self)
|
32
|
+
@stage
|
33
|
+
end
|
34
|
+
|
35
|
+
def filter(operation)
|
36
|
+
@stage.add_filter(operation)
|
37
|
+
end
|
38
|
+
|
39
|
+
def inbound(&block)
|
40
|
+
::Blockenspiel.invoke(block, Batsir::DSL::InboundMapping.new(@stage))
|
41
|
+
end
|
42
|
+
|
43
|
+
def outbound(&block)
|
44
|
+
::Blockenspiel.invoke(block, Batsir::DSL::OutboundMapping.new(@stage))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class InboundMapping < ::Blockenspiel::Base
|
49
|
+
def initialize(stage)
|
50
|
+
@stage = stage
|
51
|
+
end
|
52
|
+
|
53
|
+
def transformers(&block)
|
54
|
+
::Blockenspiel.invoke(block, Batsir::DSL::InboundTransformerMapping.new(@stage))
|
55
|
+
end
|
56
|
+
|
57
|
+
def acceptor(acceptor_class, options = {})
|
58
|
+
@stage.add_acceptor(acceptor_class, options)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class InboundTransformerMapping < ::Blockenspiel::Base
|
63
|
+
def initialize(stage)
|
64
|
+
@stage = stage
|
65
|
+
end
|
66
|
+
|
67
|
+
def transformer(transformer, options = {})
|
68
|
+
@stage.add_acceptor_transformer(transformer, options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class OutboundMapping < ::Blockenspiel::Base
|
73
|
+
def initialize(stage)
|
74
|
+
@stage = stage
|
75
|
+
end
|
76
|
+
|
77
|
+
def transformers(&block)
|
78
|
+
::Blockenspiel.invoke(block, Batsir::DSL::OutboundTransformerMapping.new(@stage))
|
79
|
+
end
|
80
|
+
|
81
|
+
def notifier(notifier_class, options = {})
|
82
|
+
@stage.add_notifier(notifier_class, options)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class OutboundTransformerMapping < ::Blockenspiel::Base
|
87
|
+
def initialize(stage)
|
88
|
+
@stage = stage
|
89
|
+
end
|
90
|
+
|
91
|
+
def transformer(transformer, options = {})
|
92
|
+
@stage.add_notifier_transformer(transformer, options)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Batsir
|
2
|
+
class FilterQueue
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_accessor :filters
|
6
|
+
attr_accessor :notifiers
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@filters = []
|
10
|
+
@notifiers = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(operation)
|
14
|
+
@filters << operation
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_notifier(notifier)
|
18
|
+
@notifiers << notifier
|
19
|
+
end
|
20
|
+
|
21
|
+
def each
|
22
|
+
@filters.each {|op| yield op}
|
23
|
+
@notifiers.each {|n| yield n}
|
24
|
+
end
|
25
|
+
|
26
|
+
def empty?
|
27
|
+
!(@notifiers.any? || @filters.any?)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/batsir/logo.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Batsir
|
2
|
+
def self.logo
|
3
|
+
<<EOF
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
E ,.
|
10
|
+
,,,agB8@f ,8v ,8L J88&gg,,,
|
11
|
+
.,a88888888@^ |8&,,,,,,88k ,88888888&g,,
|
12
|
+
,+88888888888$t 8888888f''9@. ,888888888888g,
|
13
|
+
,,88888888888888$; ,888888&` 8c ,888888888888888w,
|
14
|
+
,a88888888888888888&,......|8888888&gg&|8k......,d88888888888888888&,
|
15
|
+
,888888888888888888888888888888888qp8888|@8888888888888888888888888888y
|
16
|
+
,888888888888888888888888888888`8` '' `8`|888888888888888888888888888888E
|
17
|
+
,88888888888888888888888888888888 && 8|8888888888888888888888888888888c
|
18
|
+
|88888888888888888888888888888888888888888|8888888888888888888888888888888k
|
19
|
+
|88888888888888888888888888888888888888888|8888888888888888888888888888888k
|
20
|
+
,888888888888888888888888888888888888888888888888888888888888888888888888!
|
21
|
+
j8888888888888888888888888888888888888888888888888888888888888888888888f
|
22
|
+
j8888888888888888@@88888888888888888888888888888888@@888888888888888@f
|
23
|
+
,9888888888888@: `988M^ `?88888888888@f: |988M' .8888888888888M'
|
24
|
+
,98888888888F jf J8888888@f jf ,888888888@f'
|
25
|
+
|98888888&. ,98888@' d888888@9"
|
26
|
+
`?9@888&, j88f ,d88$@9l'
|
27
|
+
`|?9t |f `9T"`
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
EOF
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'batsir/amqp'
|
2
|
+
|
3
|
+
module Batsir
|
4
|
+
module Notifiers
|
5
|
+
class AMQPNotifier < Notifier
|
6
|
+
include Batsir::AMQP
|
7
|
+
|
8
|
+
def execute(message)
|
9
|
+
Bunny.run( bunny_options )do |bunny|
|
10
|
+
exc = bunny.exchange( exchange )
|
11
|
+
exc.publish( message, :key => queue )
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Batsir
|
2
|
+
module Notifiers
|
3
|
+
class Notifier
|
4
|
+
attr_accessor :field_mapping
|
5
|
+
attr_accessor :transformer_queue
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
fields = options.delete(:fields)
|
9
|
+
|
10
|
+
options.each do |option, value|
|
11
|
+
self.send("#{option}=", value)
|
12
|
+
end
|
13
|
+
@transformer_queue = []
|
14
|
+
if fields
|
15
|
+
add_transformer(Batsir::Transformers::FieldTransformer.new(:fields => fields))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_transformer(transformer)
|
20
|
+
@transformer_queue << transformer
|
21
|
+
end
|
22
|
+
|
23
|
+
def notify(message)
|
24
|
+
execute(transform(message))
|
25
|
+
end
|
26
|
+
|
27
|
+
def execute(message)
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def transform(message)
|
32
|
+
transformer_queue.each do |transformer|
|
33
|
+
message = transformer.transform(message)
|
34
|
+
end
|
35
|
+
message
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/batsir/stage.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
module Batsir
|
2
|
+
class Stage
|
3
|
+
include Celluloid
|
4
|
+
|
5
|
+
FilterDeclaration = Struct.new(:filter, :options)
|
6
|
+
TransformerDeclaration = Struct.new(:transformer, :options)
|
7
|
+
|
8
|
+
attr_accessor :name
|
9
|
+
attr_accessor :chain
|
10
|
+
attr_accessor :cancellators
|
11
|
+
attr_reader :filter_declarations
|
12
|
+
attr_reader :notifiers
|
13
|
+
attr_reader :acceptors
|
14
|
+
attr_reader :running_acceptors
|
15
|
+
attr_reader :notifier_transformers
|
16
|
+
attr_reader :acceptor_transformers
|
17
|
+
|
18
|
+
def initialize(options = {})
|
19
|
+
options.each do |attr, value|
|
20
|
+
self.send("#{attr.to_s}=", value)
|
21
|
+
end
|
22
|
+
@cancellators = []
|
23
|
+
@acceptor_transformers = []
|
24
|
+
@running_acceptors = []
|
25
|
+
@acceptors = {}
|
26
|
+
@filter_declarations = []
|
27
|
+
@notifiers = {}
|
28
|
+
@notifier_transformers = []
|
29
|
+
@built = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def built?
|
33
|
+
@built
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_acceptor_transformer(transformer, options = {})
|
37
|
+
@acceptor_transformers << TransformerDeclaration.new(transformer, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_acceptor(acceptor, options = {})
|
41
|
+
@acceptors[acceptor] ||= Set.new
|
42
|
+
@acceptors[acceptor] << options
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_filter(filter, options = {})
|
46
|
+
@filter_declarations << FilterDeclaration.new(filter, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def filters
|
50
|
+
@filter_declarations.map{ |filter_declaration| filter_declaration.filter }
|
51
|
+
end
|
52
|
+
|
53
|
+
def add_notifier(notifier, options = {})
|
54
|
+
@notifiers[notifier] ||= Set.new
|
55
|
+
@notifiers[notifier] << options
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_notifier_transformer(transformer, options = {})
|
59
|
+
@notifier_transformers << TransformerDeclaration.new(transformer, options)
|
60
|
+
end
|
61
|
+
|
62
|
+
def compile
|
63
|
+
Batsir::StageWorker.compile_from(self)
|
64
|
+
end
|
65
|
+
|
66
|
+
def finalize
|
67
|
+
@cancellators.each do |cancellator|
|
68
|
+
cancellator.write "STOP"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def start
|
73
|
+
acceptors.each do |acceptor_class, options|
|
74
|
+
options.each do |acceptor_options|
|
75
|
+
cancellator_reader, cancellator_writer = ::IO.pipe
|
76
|
+
acceptor_options.merge!(:stage_name => self.name, :cancellator => cancellator_reader)
|
77
|
+
@cancellators << cancellator_writer
|
78
|
+
acceptor = acceptor_class.new(acceptor_options)
|
79
|
+
if acceptor_transformers.any?
|
80
|
+
acceptor_transformers.each do |transformer_declaration|
|
81
|
+
transformer = transformer_declaration.transformer.new(transformer_declaration.options)
|
82
|
+
acceptor.add_transformer(transformer)
|
83
|
+
end
|
84
|
+
else
|
85
|
+
acceptor.add_transformer(Batsir::Transformers::JSONInputTransformer.new)
|
86
|
+
end
|
87
|
+
@running_acceptors << acceptor
|
88
|
+
acceptor.start!
|
89
|
+
end
|
90
|
+
end
|
91
|
+
true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|