rflow-components-amqp 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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+ require 'rdoc/task'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.verbose = true
8
+ t.rspec_opts = '--tty --color'
9
+ end
10
+
11
+ Rake::RDocTask.new do |rd|
12
+ rd.main = "README"
13
+ rd.rdoc_files.include("README", "lib/**/*.rb")
14
+ rd.rdoc_dir = File.join('doc', 'html')
15
+ end
@@ -0,0 +1,27 @@
1
+ class RFlow
2
+ module Components
3
+ module AMQP
4
+
5
+ # The set of extensions to add capability to AMQP data types
6
+ module Extensions
7
+
8
+ module AMQPMessageExtension
9
+ def self.extended(base_data)
10
+ base_data.data_object ||= {'header' => {}, 'payload' => ''}
11
+ end
12
+
13
+ # Default accessors
14
+ ['header', 'payload'].each do |name|
15
+ define_method name do |*args|
16
+ data_object[name]
17
+ end
18
+ define_method :"#{name}=" do |*args|
19
+ data_object[name] = args.first
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,113 @@
1
+ require 'eventmachine'
2
+ require 'amqp'
3
+ require 'rflow'
4
+
5
+ class RFlow
6
+ module Components
7
+ module AMQP
8
+
9
+ # By default will use and exclusive, non-durable, auto-deleting,
10
+ # randomly named queue for subscribing to topic messages with an
11
+ # empty-string pattern
12
+ class Subscriber < RFlow::Component
13
+ output_port :amqp_port
14
+ output_port :raw_port
15
+
16
+ attr_accessor :config, :queue_config
17
+
18
+ DEFAULT_CONFIG = {
19
+ 'server' => '127.0.0.1',
20
+ 'port' => 5672,
21
+ 'username' => 'guest',
22
+ 'password' => 'guest',
23
+ 'vhost' => '/',
24
+
25
+ 'queue_name' => 'asdf',
26
+ 'queue_passive' => false,
27
+ 'queue_durable' => false,
28
+ 'queue_exclusive' => true,
29
+ 'queue_auto_delete' => true,
30
+
31
+ 'binding_pattern' => '',
32
+ }
33
+
34
+ def configure!(config)
35
+ @config = DEFAULT_CONFIG.merge config
36
+ @config['port'] = @config['port'].to_i
37
+
38
+ ['durable', 'passive', 'exclusive', 'auto_delete'].each do |queue_bool_opt|
39
+ @config["queue_#{queue_bool_opt}"] = to_boolean(@config["queue_#{queue_bool_opt}"])
40
+ end
41
+
42
+ # Convert the queue parameters into AMQP-friendly sym-keyed
43
+ # Hash that can be passed directly to underlying AMQP gem
44
+ # methods
45
+ @queue_config = {}
46
+ @config.each do |key, value|
47
+ md = /queue_(.*)/.match(key.to_s)
48
+ unless md.nil?
49
+ @queue_config[md[1].to_sym] = value
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ def run!
56
+ ::AMQP.connect(:host => @config['server'], :port => @config['port'], :vhost => @config['vhost'], :username => @config['username'], :password => @config['password']) do |conn|
57
+ @amqp_connection = conn
58
+
59
+ ::AMQP::Channel.new(@amqp_connection) do |channel|
60
+ @amqp_channel = channel
61
+ @amqp_exchange = @amqp_channel.topic
62
+
63
+ ::AMQP::Queue.new(@amqp_channel, @config['queue_name'], @queue_config) do |queue|
64
+ @amqp_queue = queue
65
+ @amqp_queue.bind(@amqp_exchange, :routing_key => @config['binding_pattern']).subscribe(:ack => true) do |header, payload|
66
+ RFlow.logger.debug "AMQP message received"
67
+ processing_event = RFlow::Message::ProcessingEvent.new(instance_uuid, Time.now.utc)
68
+
69
+ amqp_message = RFlow::Message.new('RFlow::Message::Data::AMQP::Message')
70
+ header.to_hash.each {|k,v| amqp_message.data.header[k.to_s] = v}
71
+ amqp_message.data.payload = payload
72
+
73
+ # TODO: Optimize out if not connected
74
+ raw_message = RFlow::Message.new('RFlow::Message::Data::Raw')
75
+ raw_message.data.raw = payload
76
+
77
+ processing_event.completed_at = Time.now.utc
78
+ amqp_message.provenance << processing_event
79
+ raw_message.provenance << processing_event
80
+
81
+ amqp_port.send_message amqp_message
82
+ raw_port.send_message raw_message
83
+
84
+ header.ack
85
+ end
86
+ end
87
+
88
+ end
89
+ end
90
+
91
+ # EM.add_timer(2) do
92
+ # EM.add_periodic_timer(0) do
93
+ # @amqp_exchange.publish Array.new(rand(1000)) { rand(256) }.pack('c*'), :routing_key => ""
94
+ # end
95
+ # end
96
+ end
97
+
98
+ def to_boolean(string)
99
+ case string
100
+ when /^true$/i, '1', true
101
+ true
102
+ when /^false/i, '0', false
103
+ false
104
+ else
105
+ raise ArgumentError, "'#{string}' cannot be coerced to a boolean value"
106
+ end
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,7 @@
1
+ class RFlow
2
+ module Components
3
+ module AMQP
4
+ VERSION = "0.0.2"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,25 @@
1
+ require 'rflow/components/amqp/extensions'
2
+ require 'rflow/components/amqp/subscriber'
3
+
4
+ class RFlow
5
+ module Components
6
+ module AMQP
7
+ # Load the schemas
8
+ SCHEMA_DIRECTORY = ::File.expand_path(::File.join(::File.dirname(__FILE__), '..', '..', '..', 'schema'))
9
+
10
+ SCHEMA_FILES = {
11
+ 'amqp_message.avsc' => 'RFlow::Message::Data::AMQP::Message',
12
+ }
13
+
14
+ SCHEMA_FILES.each do |file_name, data_type_name|
15
+ schema_string = ::File.read(::File.join(SCHEMA_DIRECTORY, file_name))
16
+ RFlow::Configuration.add_available_data_type data_type_name, 'avro', schema_string
17
+ end
18
+
19
+ # Load the data extensions
20
+ RFlow::Configuration.add_available_data_extension('RFlow::Message::Data::AMQP::Message',
21
+ RFlow::Components::AMQP::Extensions::AMQPMessageExtension)
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,2 @@
1
+ require 'rflow'
2
+ require 'rflow/components/amqp'
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rflow/components/amqp/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rflow-components-amqp"
7
+ s.version = RFlow::Components::AMQP::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.required_ruby_version = '~> 1.9'
10
+ s.authors = ["Michael L. Artz"]
11
+ s.email = ["michael.artz@redjack.com"]
12
+ s.homepage = "https://github.com/redjack/rflow-components-amqp"
13
+ s.summary = %q{AMQP publisher and subscriber component for the RFlow FBP framework}
14
+ s.description = %q{AMQP publisher and subscriber component for the RFlow FBP framework. Also includes the necessary AMQP::Message message type}
15
+
16
+ s.rubyforge_project = "rflow-components-amqp"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+
23
+ s.add_dependency 'rflow', '~> 0.0.1'
24
+ s.add_dependency 'amqp', '>= 0.8.0.rc12'
25
+
26
+ s.add_development_dependency 'rspec', '~> 2.5.0'
27
+ s.add_development_dependency 'rake', '~> 0.8.7'
28
+ end
@@ -0,0 +1,15 @@
1
+ {
2
+ "type": "record",
3
+ "name": "Message",
4
+ "namespace": "org.rflow.message.data.amqp",
5
+ "aliases": [],
6
+ "fields": [
7
+ {"name": "client_ip", "type": ["string", "null"]},
8
+ {"name": "client_port", "type": ["int", "null"]},
9
+ {"name": "server_ip", "type": ["string", "null"]},
10
+ {"name": "server_port", "type": ["int", "null"]},
11
+
12
+ {"name": "header", "type": {"type": "map", "values": ["string", "int", "null"]}},
13
+ {"name": "payload", "type": "bytes"}
14
+ ]
15
+ }
@@ -0,0 +1,47 @@
1
+ require 'spec_helper.rb'
2
+
3
+ # describe RFlow::Components::File::Extensions::FileExtension do
4
+ # before(:each) do
5
+ # @schema_string = RFlow::Configuration.available_data_types['RFlow::Message::Data::File']['avro']
6
+ # end
7
+ #
8
+ # it "should add the extension to RFlow::Configuration" do
9
+ # RFlow::Configuration.available_data_extensions['RFlow::Message::Data::File'].should include(described_class)
10
+ # end
11
+ #
12
+ # it "should set the defaults" do
13
+ # file = RFlow::Message.new('RFlow::Message::Data::File')
14
+ #
15
+ # file.data.path.should == '/'
16
+ # file.data.size.should == 0
17
+ # file.data.content.should == ''
18
+ # file.data.creation_timestamp.should == nil
19
+ # file.data.modification_timestamp.should == nil
20
+ # file.data.accessed_timestamp.should == nil
21
+ # end
22
+ #
23
+ # it "should correctly use integers or strings for size field" do
24
+ # file = RFlow::Message.new('RFlow::Message::Data::File')
25
+ #
26
+ # file.data.size.should == 0
27
+ # file.data.size = 10
28
+ # file.data.size.should == 10
29
+ # file.data.size = '20'
30
+ # file.data.size == 20
31
+ # end
32
+ #
33
+ # it "should correctly use Time or xmlschema strings for timestamp fields" do
34
+ # file = RFlow::Message.new('RFlow::Message::Data::File')
35
+ #
36
+ # file.data.creation_timestamp.should == nil
37
+ # now = Time.now
38
+ #
39
+ # file.data.creation_timestamp = now
40
+ # file.data.creation_timestamp.should == Time.xmlschema(now.xmlschema(9))
41
+ #
42
+ # file.data.creation_timestamp = now.xmlschema
43
+ # file.data.creation_timestamp.should == Time.xmlschema(now.xmlschema)
44
+ # end
45
+ #
46
+ #
47
+ # end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper.rb'
2
+
3
+ describe 'RFlow::Message::Data::AMQP::Message Avro Schema' do
4
+ before(:each) do
5
+ @schema_string = RFlow::Configuration.available_data_types['RFlow::Message::Data::AMQP::Message']['avro']
6
+ end
7
+
8
+ it "should encode and decode an object" do
9
+ amqp_message = {
10
+ 'header' => {
11
+ 'content_type' => 'application/octet-stream',
12
+ 'delivery_mode' => 2,
13
+ 'priority' => 0,
14
+ },
15
+ 'payload' =>'PAYLOAD',
16
+ }
17
+
18
+ expect {encode_avro(@schema_string, amqp_message)}.to_not raise_error
19
+ avro_encoded_amqp_message = encode_avro(@schema_string, amqp_message)
20
+
21
+ expect {decode_avro(@schema_string, avro_encoded_amqp_message)}.to_not raise_error
22
+ decoded_amqp_message = decode_avro(@schema_string, avro_encoded_amqp_message)
23
+
24
+ decoded_amqp_message['payload'].should == amqp_message['payload']
25
+ decoded_amqp_message['header'].should == amqp_message['header']
26
+
27
+ end
28
+ end
29
+
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'rflow-components-amqp'))
2
+
3
+ require 'logger'
4
+
5
+ RFlow.logger = Logger.new STDOUT
6
+
7
+ def decode_avro(schema_string, serialized_object)
8
+ schema = Avro::Schema.parse(schema_string)
9
+ serialized_object.force_encoding 'BINARY'
10
+ sio = StringIO.new(serialized_object)
11
+ Avro::IO::DatumReader.new(schema, schema).read Avro::IO::BinaryDecoder.new(sio)
12
+ end
13
+
14
+ def encode_avro(schema_string, object)
15
+ encoded_string = ''
16
+ encoded_string.force_encoding 'BINARY'
17
+ schema = Avro::Schema.parse(schema_string)
18
+ sio = StringIO.new(encoded_string)
19
+ Avro::IO::DatumWriter.new(schema).write object, Avro::IO::BinaryEncoder.new(sio)
20
+ encoded_string
21
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rflow-components-amqp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael L. Artz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-03-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rflow
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.0.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.0.1
30
+ - !ruby/object:Gem::Dependency
31
+ name: amqp
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 0.8.0.rc12
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 0.8.0.rc12
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 2.5.0
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.5.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 0.8.7
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.8.7
78
+ description: AMQP publisher and subscriber component for the RFlow FBP framework. Also
79
+ includes the necessary AMQP::Message message type
80
+ email:
81
+ - michael.artz@redjack.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - Gemfile
88
+ - Rakefile
89
+ - lib/rflow-components-amqp.rb
90
+ - lib/rflow/components/amqp.rb
91
+ - lib/rflow/components/amqp/extensions.rb
92
+ - lib/rflow/components/amqp/subscriber.rb
93
+ - lib/rflow/components/amqp/version.rb
94
+ - rflow-components-amqp.gemspec
95
+ - schema/amqp_message.avsc
96
+ - spec/extensions_spec.rb
97
+ - spec/schema_spec.rb
98
+ - spec/spec_helper.rb
99
+ homepage: https://github.com/redjack/rflow-components-amqp
100
+ licenses: []
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '1.9'
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ! '>='
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project: rflow-components-amqp
119
+ rubygems_version: 1.8.24
120
+ signing_key:
121
+ specification_version: 3
122
+ summary: AMQP publisher and subscriber component for the RFlow FBP framework
123
+ test_files:
124
+ - spec/extensions_spec.rb
125
+ - spec/schema_spec.rb
126
+ - spec/spec_helper.rb