harmoniser 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/console +15 -0
- data/bin/harmoniser +11 -0
- data/bin/setup +8 -0
- data/lib/harmoniser/channelable.rb +25 -0
- data/lib/harmoniser/cli.rb +70 -0
- data/lib/harmoniser/configurable.rb +25 -0
- data/lib/harmoniser/configuration.rb +77 -0
- data/lib/harmoniser/connection.rb +35 -0
- data/lib/harmoniser/definition.rb +35 -0
- data/lib/harmoniser/includable.rb +25 -0
- data/lib/harmoniser/launcher.rb +56 -0
- data/lib/harmoniser/options.rb +11 -0
- data/lib/harmoniser/parser.rb +36 -0
- data/lib/harmoniser/publisher.rb +55 -0
- data/lib/harmoniser/subscriber.rb +85 -0
- data/lib/harmoniser/topology.rb +72 -0
- data/lib/harmoniser/version.rb +3 -0
- data/lib/harmoniser.rb +8 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6daf41d7ec196c5f279bca1e4d9ee1339f17a81508fb4432359b32595c364a07
|
4
|
+
data.tar.gz: 1cab012d3c64c10590f032b768e5acd267980980e988d02b3f7297a138d8477a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3ec7c8e929076ca5725f91d1755ba5548b99e87e8d7c3b6f9d63d029cf6fd76c8419fef99c25b46a525dc49f0d1af011f71a210bf3602d75787fbba7941c5cb1
|
7
|
+
data.tar.gz: 554b5e2c30444280133ec848124e3b1bb88fbb994b3a2056efdbcfaa5817783530b6d25642217db43eaeb25a5cc80652395e7b1203ebe2c37767e07b8a024578
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "harmoniser"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/harmoniser
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Harmoniser
|
2
|
+
module Channelable
|
3
|
+
MUTEX = Mutex.new
|
4
|
+
private_constant :MUTEX
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def harmoniser_channel
|
8
|
+
MUTEX.synchronize do
|
9
|
+
@harmoniser_channel ||= create_channel
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_channel
|
14
|
+
connection = Harmoniser.connection
|
15
|
+
connection.create_channel
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def included(base)
|
21
|
+
base.extend(ClassMethods)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "singleton"
|
2
|
+
require "harmoniser"
|
3
|
+
require "harmoniser/parser"
|
4
|
+
require "harmoniser/launcher"
|
5
|
+
|
6
|
+
module Harmoniser
|
7
|
+
class CLI
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
SIGNAL_HANDLERS = {
|
11
|
+
"INT" => lambda { |cli, signal| raise Interrupt },
|
12
|
+
"TERM" => lambda { |cli, signal| raise Interrupt }
|
13
|
+
}
|
14
|
+
SIGNAL_HANDLERS.default = lambda { |cli, signal| cli.logger.info("Default signal handler executed since there is no handler defined: signal = `#{signal}`") }
|
15
|
+
|
16
|
+
attr_reader :logger
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@configuration = Harmoniser.default_configuration
|
20
|
+
@logger = Harmoniser.logger
|
21
|
+
end
|
22
|
+
|
23
|
+
def call
|
24
|
+
parse_options
|
25
|
+
define_signals
|
26
|
+
run
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :configuration
|
32
|
+
|
33
|
+
def parse_options
|
34
|
+
options = Parser.new(logger: @logger).call(ARGV)
|
35
|
+
configuration.options_with(**options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def define_signals
|
39
|
+
@read_io, @write_io = IO.pipe
|
40
|
+
|
41
|
+
["INT", "TERM"].each do |sig|
|
42
|
+
Signal.trap(sig) do
|
43
|
+
@write_io.puts(sig)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def run
|
49
|
+
launcher = Launcher.new
|
50
|
+
launcher.start
|
51
|
+
|
52
|
+
while @read_io.wait_readable
|
53
|
+
signal = @read_io.gets.strip
|
54
|
+
handle_signal(signal)
|
55
|
+
end
|
56
|
+
rescue Interrupt
|
57
|
+
logger.info("Shutting down!")
|
58
|
+
launcher.stop
|
59
|
+
@write_io.close
|
60
|
+
@read_io.close
|
61
|
+
logger.info("Bye!")
|
62
|
+
exit(0)
|
63
|
+
end
|
64
|
+
|
65
|
+
def handle_signal(signal)
|
66
|
+
logger.info("Signal received: signal = `#{signal}`")
|
67
|
+
SIGNAL_HANDLERS[signal].call(self, signal)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "harmoniser/configuration"
|
3
|
+
|
4
|
+
module Harmoniser
|
5
|
+
module Configurable
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def configure
|
9
|
+
@configuration ||= Configuration.new
|
10
|
+
yield(@configuration)
|
11
|
+
end
|
12
|
+
|
13
|
+
def configuration
|
14
|
+
raise NoMethodError.new("Please, configure first") unless @configuration
|
15
|
+
|
16
|
+
@configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_configuration
|
20
|
+
@configuration ||= Configuration.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def_delegators :configuration, :logger, :connection
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "logger"
|
3
|
+
require "harmoniser/connection"
|
4
|
+
require "harmoniser/topology"
|
5
|
+
require "harmoniser/options"
|
6
|
+
|
7
|
+
module Harmoniser
|
8
|
+
class Configuration
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
DEFAULT_CONNECTION_OPTS = {
|
12
|
+
connection_name: "harmoniser@#{VERSION}",
|
13
|
+
host: "127.0.0.1",
|
14
|
+
password: "guest",
|
15
|
+
port: 5672,
|
16
|
+
tls_silence_warnings: true,
|
17
|
+
username: "guest",
|
18
|
+
verify_peer: false,
|
19
|
+
vhost: "/"
|
20
|
+
}
|
21
|
+
MUTEX = Mutex.new
|
22
|
+
|
23
|
+
attr_reader :connection, :connection_opts, :logger, :options
|
24
|
+
def_delegators :options, :environment, :require, :verbose
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@logger = Logger.new($stdout, progname: "harmoniser@#{VERSION}")
|
28
|
+
@options = Options.new(**default_options)
|
29
|
+
set_logger_severity
|
30
|
+
@connection_opts = DEFAULT_CONNECTION_OPTS.merge({ logger: @logger })
|
31
|
+
@topology = Topology.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def define_topology
|
35
|
+
raise LocalJumpError, "A block is required for this method" unless block_given?
|
36
|
+
|
37
|
+
yield(@topology)
|
38
|
+
end
|
39
|
+
|
40
|
+
def connection
|
41
|
+
MUTEX.synchronize do
|
42
|
+
@connection = Connection.new(connection_opts) unless @connection
|
43
|
+
@connection.start unless @connection.open?
|
44
|
+
@connection
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def connection_opts=(opts)
|
49
|
+
raise TypeError, "opts must be a Hash object" unless opts.is_a?(Hash)
|
50
|
+
|
51
|
+
@connection_opts = connection_opts.merge(opts)
|
52
|
+
end
|
53
|
+
|
54
|
+
def options_with(**kwargs)
|
55
|
+
@options = options.with(**kwargs)
|
56
|
+
set_logger_severity
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def default_options
|
62
|
+
{
|
63
|
+
environment: ENV.fetch("RAILS_ENV", ENV.fetch("RACK_ENV", "production")),
|
64
|
+
require: ".",
|
65
|
+
verbose: false
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def set_logger_severity
|
70
|
+
if @options.production?
|
71
|
+
@logger.level = @options.verbose? ? Logger::DEBUG : Logger::INFO
|
72
|
+
else
|
73
|
+
@logger.level = Logger::DEBUG
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "bunny"
|
3
|
+
|
4
|
+
module Harmoniser
|
5
|
+
class Connection
|
6
|
+
extend Forwardable
|
7
|
+
def_delegators :@bunny, :close, :create_channel, :open?, :start
|
8
|
+
|
9
|
+
def initialize(opts)
|
10
|
+
@bunny = Bunny.new(opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"<#{self.class.name}>: #{user}@#{host}:#{port}, vhost = #{vhost}"
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def host
|
20
|
+
@bunny.transport.host
|
21
|
+
end
|
22
|
+
|
23
|
+
def port
|
24
|
+
@bunny.transport.port
|
25
|
+
end
|
26
|
+
|
27
|
+
def user
|
28
|
+
@bunny.user
|
29
|
+
end
|
30
|
+
|
31
|
+
def vhost
|
32
|
+
@bunny.vhost
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Harmoniser
|
2
|
+
module Definition
|
3
|
+
Binding = Data.define(:exchange_name, :destination_name, :destination_type, :opts) do
|
4
|
+
def queue?
|
5
|
+
[:queue, "queue"].include?(destination_type)
|
6
|
+
end
|
7
|
+
|
8
|
+
def exchange?
|
9
|
+
[:exchange, "exchange"].include?(destination_type)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Consumer = Data.define(:queue_name, :consumer_tag, :no_ack, :exclusive, :arguments)
|
14
|
+
|
15
|
+
Exchange = Data.define(:name, :type, :opts) do
|
16
|
+
def hash
|
17
|
+
[self.class, name].hash
|
18
|
+
end
|
19
|
+
|
20
|
+
def eql?(other)
|
21
|
+
self.class == other.class && name == other.name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Queue = Data.define(:name, :opts) do
|
26
|
+
def hash
|
27
|
+
[self.class, name].hash
|
28
|
+
end
|
29
|
+
|
30
|
+
def eql?(other)
|
31
|
+
self.class == other.class && name == other.name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Harmoniser
|
2
|
+
module Includable
|
3
|
+
MUTEX = Mutex.new
|
4
|
+
private_constant :MUTEX
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def harmoniser_register_included(klass)
|
8
|
+
MUTEX.synchronize do
|
9
|
+
@harmoniser_included ||= Set.new
|
10
|
+
@harmoniser_included << klass
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def harmoniser_included
|
15
|
+
@harmoniser_included.to_a
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def included(base)
|
21
|
+
base.extend(ClassMethods)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Harmoniser
|
2
|
+
class Launcher
|
3
|
+
def initialize(configuration: Harmoniser.configuration, logger: Harmoniser.logger)
|
4
|
+
@configuration = configuration
|
5
|
+
@logger = logger
|
6
|
+
end
|
7
|
+
|
8
|
+
def start
|
9
|
+
boot_app
|
10
|
+
start_subscribers
|
11
|
+
end
|
12
|
+
|
13
|
+
def stop
|
14
|
+
stop_subscribers
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def boot_app
|
20
|
+
if File.directory?(@configuration.require)
|
21
|
+
load_rails
|
22
|
+
else
|
23
|
+
load_file
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# TODO - Frameworks like Rails which have autoload for development/test will not start any subscriber unless the files where subscribers are located are required explicitly. Since we premier production and the eager load ensures that every file is loaded, this approach works
|
28
|
+
def start_subscribers
|
29
|
+
klasses = Subscriber.harmoniser_included
|
30
|
+
klasses.each do |klass|
|
31
|
+
klass.harmoniser_subscriber_start
|
32
|
+
end
|
33
|
+
@logger.info("Subscribers registered to consume messages from queues: klasses = `#{klasses}`")
|
34
|
+
end
|
35
|
+
|
36
|
+
def stop_subscribers
|
37
|
+
@logger.info("Connection will be closed: connection = `#{@configuration.connection.to_s}`")
|
38
|
+
@configuration.connection.close
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def load_rails
|
44
|
+
filepath = File.expand_path("#{@configuration.require}/config/environment.rb")
|
45
|
+
require filepath
|
46
|
+
rescue LoadError
|
47
|
+
@logger.warn("Error while requiring file within directory. No subscribers will run for this process: require = `#{@configuration.require}`, filepath = `#{filepath}`")
|
48
|
+
end
|
49
|
+
|
50
|
+
def load_file
|
51
|
+
require @configuration.require
|
52
|
+
rescue LoadError
|
53
|
+
@logger.warn("Error while requiring file. No subscribers will run for this process: require = `#{@configuration.require}`")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require_relative "version"
|
3
|
+
|
4
|
+
module Harmoniser
|
5
|
+
class Parser
|
6
|
+
def initialize(logger:)
|
7
|
+
@logger = logger
|
8
|
+
@options = {}
|
9
|
+
@option_parser = OptionParser.new do |opts|
|
10
|
+
opts.banner = "harmoniser [options]"
|
11
|
+
opts.on "-e", "--environment ENV", "Application environment" do |arg|
|
12
|
+
@options[:environment] = arg
|
13
|
+
end
|
14
|
+
opts.on "-r", "--require [PATH|DIR]", "File to require or location of Rails application" do |arg|
|
15
|
+
@options[:require] = arg
|
16
|
+
end
|
17
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |arg|
|
18
|
+
@options[:verbose] = arg
|
19
|
+
end
|
20
|
+
opts.on "-V", "--version", "Print version and exit" do
|
21
|
+
puts "Harmoniser #{Harmoniser::VERSION}"
|
22
|
+
exit(0)
|
23
|
+
end
|
24
|
+
opts.on_tail "-h", "--help", "Show help" do
|
25
|
+
puts @option_parser
|
26
|
+
exit(0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def call(argv = [])
|
32
|
+
@option_parser.parse!(argv)
|
33
|
+
@options
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "harmoniser/channelable"
|
2
|
+
require "harmoniser/definition"
|
3
|
+
|
4
|
+
module Harmoniser
|
5
|
+
module Publisher
|
6
|
+
class MissingExchangeDefinition < StandardError ; end
|
7
|
+
include Channelable
|
8
|
+
MUTEX = Mutex.new
|
9
|
+
private_constant :MUTEX
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def harmoniser_publisher(exchange_name:)
|
13
|
+
@harmoniser_exchange_definition = Definition::Exchange.new(
|
14
|
+
name: exchange_name,
|
15
|
+
type: nil,
|
16
|
+
opts: { passive: true }
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def publish(payload, opts = {})
|
21
|
+
raise_missing_exchange_definition unless @harmoniser_exchange_definition
|
22
|
+
|
23
|
+
MUTEX.synchronize do
|
24
|
+
harmoniser_exchange.publish(payload, opts)
|
25
|
+
end
|
26
|
+
Harmoniser.logger.debug { "Message published: payload = `#{payload}`, opts = `#{opts}`" }
|
27
|
+
|
28
|
+
harmoniser_exchange
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def harmoniser_exchange
|
34
|
+
return @harmoniser_exchange if @harmoniser_exchange
|
35
|
+
|
36
|
+
@harmoniser_exchange ||= Bunny::Exchange.new(
|
37
|
+
Publisher.harmoniser_channel,
|
38
|
+
@harmoniser_exchange_definition.type,
|
39
|
+
@harmoniser_exchange_definition.name,
|
40
|
+
@harmoniser_exchange_definition.opts
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def raise_missing_exchange_definition
|
45
|
+
raise MissingExchangeDefinition, "Please, call harmoniser_publisher class method first with the exchange_name that will be used for publications"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class << self
|
50
|
+
def included(base)
|
51
|
+
base.extend(ClassMethods)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "harmoniser/channelable"
|
2
|
+
require "harmoniser/definition"
|
3
|
+
require "harmoniser/includable"
|
4
|
+
|
5
|
+
module Harmoniser
|
6
|
+
module Subscriber
|
7
|
+
class MissingConsumerDefinition < StandardError ; end
|
8
|
+
include Channelable
|
9
|
+
include Includable
|
10
|
+
MUTEX = Mutex.new
|
11
|
+
private_constant :MUTEX
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def harmoniser_subscriber(queue_name:, consumer_tag: nil, no_ack: true, exclusive: false, arguments: {})
|
15
|
+
@harmoniser_consumer_definition = Definition::Consumer.new(
|
16
|
+
queue_name: queue_name,
|
17
|
+
consumer_tag: consumer_tag,
|
18
|
+
no_ack: no_ack,
|
19
|
+
exclusive: exclusive,
|
20
|
+
arguments: arguments
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def harmoniser_subscriber_start
|
25
|
+
MUTEX.synchronize do
|
26
|
+
@harmoniser_consumer ||= create_consumer
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def create_consumer
|
33
|
+
raise_missing_consumer_definition unless @harmoniser_consumer_definition
|
34
|
+
|
35
|
+
consumer = Bunny::Consumer.new(
|
36
|
+
Subscriber.harmoniser_channel,
|
37
|
+
@harmoniser_consumer_definition.queue_name,
|
38
|
+
@harmoniser_consumer_definition.consumer_tag || Subscriber.harmoniser_channel.generate_consumer_tag,
|
39
|
+
@harmoniser_consumer_definition.no_ack,
|
40
|
+
@harmoniser_consumer_definition.exclusive,
|
41
|
+
@harmoniser_consumer_definition.arguments
|
42
|
+
)
|
43
|
+
handle_cancellation(consumer)
|
44
|
+
handle_delivery(consumer)
|
45
|
+
register_consumer(consumer)
|
46
|
+
consumer
|
47
|
+
end
|
48
|
+
|
49
|
+
def handle_cancellation(consumer)
|
50
|
+
consumer.on_cancellation do |basic_cancel|
|
51
|
+
if respond_to?(:on_cancellation)
|
52
|
+
on_cancellation(basic_cancel)
|
53
|
+
else
|
54
|
+
Harmoniser.logger.info("Default on_cancellation handler executed for consumer: consumer_tag = `#{consumer.consumer_tag}`, queue = `#{consumer.queue}`")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def handle_delivery(consumer)
|
60
|
+
consumer.on_delivery do |delivery_info, properties, payload|
|
61
|
+
if respond_to?(:on_delivery)
|
62
|
+
on_delivery(delivery_info, properties, payload)
|
63
|
+
else
|
64
|
+
Harmoniser.logger.info("Default on_delivery handler executed for consumer: consumer_tag = `#{consumer.consumer_tag}`, queue = `#{consumer.queue}`")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def register_consumer(consumer)
|
70
|
+
consumer.channel.basic_consume_with(consumer)
|
71
|
+
end
|
72
|
+
|
73
|
+
def raise_missing_consumer_definition
|
74
|
+
raise MissingConsumerDefinition, "Please, call harmoniser_subscriber class method first with the queue_name that will be used for subscribing"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class << self
|
79
|
+
def included(base)
|
80
|
+
base.extend(ClassMethods)
|
81
|
+
harmoniser_register_included(base)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "harmoniser/channelable"
|
2
|
+
require "harmoniser/definition"
|
3
|
+
|
4
|
+
module Harmoniser
|
5
|
+
class Topology
|
6
|
+
include Channelable
|
7
|
+
|
8
|
+
attr_reader :bindings, :exchanges, :queues
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@bindings = Set.new
|
12
|
+
@exchanges = Set.new
|
13
|
+
@queues = Set.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_exchange(type, name, **opts)
|
17
|
+
@exchanges << Definition::Exchange.new(
|
18
|
+
type: type,
|
19
|
+
name: name,
|
20
|
+
opts: opts
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_queue(name, **opts)
|
25
|
+
@queues << Definition::Queue.new(
|
26
|
+
name: name,
|
27
|
+
opts: opts
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def add_binding(exchange_name, destination_name, destination_type = :queue, **opts)
|
32
|
+
@bindings << Definition::Binding.new(
|
33
|
+
exchange_name: exchange_name,
|
34
|
+
destination_name: destination_name,
|
35
|
+
destination_type: destination_type,
|
36
|
+
opts: opts
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def declare
|
41
|
+
channel = self.class.create_channel
|
42
|
+
declare_exchanges(channel)
|
43
|
+
declare_queues(channel)
|
44
|
+
declare_bindings(channel)
|
45
|
+
Harmoniser.connection.close
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def declare_exchanges(channel)
|
51
|
+
exchanges.each do |exchange|
|
52
|
+
Bunny::Exchange.new(channel, exchange.type, exchange.name, exchange.opts)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def declare_queues(channel)
|
57
|
+
queues.each do |queue|
|
58
|
+
Bunny::Queue.new(channel, queue.name, queue.opts)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def declare_bindings(channel)
|
63
|
+
bindings.each do |binding|
|
64
|
+
if binding.queue?
|
65
|
+
channel.queue_bind(binding.destination_name, binding.exchange_name, binding.opts)
|
66
|
+
elsif binding.exchange?
|
67
|
+
;
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/harmoniser.rb
ADDED
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: harmoniser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jose Lloret
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-11-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bunny
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.22'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.22'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '13.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '13.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: standardrb
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
description: A declarative tool to communicate with RabbitMQ
|
70
|
+
email:
|
71
|
+
- jollopre@gmail.com
|
72
|
+
executables:
|
73
|
+
- harmoniser
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- bin/console
|
78
|
+
- bin/harmoniser
|
79
|
+
- bin/setup
|
80
|
+
- lib/harmoniser.rb
|
81
|
+
- lib/harmoniser/channelable.rb
|
82
|
+
- lib/harmoniser/cli.rb
|
83
|
+
- lib/harmoniser/configurable.rb
|
84
|
+
- lib/harmoniser/configuration.rb
|
85
|
+
- lib/harmoniser/connection.rb
|
86
|
+
- lib/harmoniser/definition.rb
|
87
|
+
- lib/harmoniser/includable.rb
|
88
|
+
- lib/harmoniser/launcher.rb
|
89
|
+
- lib/harmoniser/options.rb
|
90
|
+
- lib/harmoniser/parser.rb
|
91
|
+
- lib/harmoniser/publisher.rb
|
92
|
+
- lib/harmoniser/subscriber.rb
|
93
|
+
- lib/harmoniser/topology.rb
|
94
|
+
- lib/harmoniser/version.rb
|
95
|
+
homepage: https://github.com/jollopre/harmoniser
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata:
|
99
|
+
homepage_uri: https://github.com/jollopre/harmoniser
|
100
|
+
source_code_uri: https://github.com/jollopre/harmoniser
|
101
|
+
changelog_uri: https://github.com/jollopre/harmoniser/blob/master/CHANGELOG.md
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 2.7.0
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubygems_version: 3.4.10
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: A declarative tool to communicate with RabbitMQ
|
121
|
+
test_files: []
|