carnivore 0.2.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +7 -0
- data/carnivore.gemspec +2 -0
- data/lib/carnivore/callback.rb +31 -15
- data/lib/carnivore/config.rb +22 -12
- data/lib/carnivore/container.rb +8 -0
- data/lib/carnivore/errors.rb +2 -0
- data/lib/carnivore/message.rb +15 -8
- data/lib/carnivore/runner.rb +8 -4
- data/lib/carnivore/source/test.rb +11 -3
- data/lib/carnivore/source.rb +181 -79
- data/lib/carnivore/source_container.rb +14 -4
- data/lib/carnivore/spec_helper.rb +65 -3
- data/lib/carnivore/supervisor.rb +40 -22
- data/lib/carnivore/utils/logging.rb +4 -0
- data/lib/carnivore/utils/message_registry.rb +16 -7
- data/lib/carnivore/utils/params.rb +9 -5
- data/lib/carnivore/utils/smash.rb +90 -0
- data/lib/carnivore/utils.rb +2 -0
- data/lib/carnivore/version.rb +3 -3
- data/lib/carnivore.rb +16 -2
- metadata +21 -4
- data/lib/carnivore/autoloader.rb +0 -13
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# v0.2.2
|
2
|
+
* Local loopback is optional and disabled by default
|
3
|
+
* Include Smash utility for Hash management
|
4
|
+
* Provide originating source to callback instances on initialization
|
5
|
+
* Add spec helpers
|
6
|
+
* Clean up custom supervisor implementation
|
7
|
+
|
1
8
|
# v0.2.0
|
2
9
|
* Remove `fog` from dependency list
|
3
10
|
* Add common spec helper for testing
|
data/carnivore.gemspec
CHANGED
@@ -8,9 +8,11 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.email = 'chrisroberts.code@gmail.com'
|
9
9
|
s.homepage = 'https://github.com/carnivore-rb/carnivore'
|
10
10
|
s.description = 'Message processing helper'
|
11
|
+
s.license = 'Apache 2.0'
|
11
12
|
s.require_path = 'lib'
|
12
13
|
s.add_dependency 'celluloid'
|
13
14
|
s.add_dependency 'mixlib-config'
|
14
15
|
s.add_dependency 'multi_json'
|
16
|
+
s.add_dependency 'hashie'
|
15
17
|
s.files = Dir['lib/**/*'] + %w(carnivore.gemspec README.md CHANGELOG.md)
|
16
18
|
end
|
data/lib/carnivore/callback.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'carnivore'
|
2
2
|
|
3
3
|
module Carnivore
|
4
|
+
# Payload modifier
|
4
5
|
class Callback
|
5
6
|
|
6
7
|
class << self
|
@@ -10,15 +11,21 @@ module Carnivore
|
|
10
11
|
|
11
12
|
include Celluloid
|
12
13
|
include Carnivore::Utils::Logging
|
14
|
+
# @!parse include Carnivore::Utils::Logging
|
13
15
|
|
16
|
+
# @return [String, Symbol] name of callback
|
14
17
|
attr_reader :name
|
18
|
+
# @return [Carnivore::Source] source this callback is attached
|
19
|
+
attr_reader :source
|
15
20
|
|
16
|
-
# name:: Name of the callback
|
17
|
-
# block:: Optional `Proc` to define the callback behavior
|
18
21
|
# Creates a new callback. Optional block to define callback
|
19
22
|
# behavior must be passed as a `Proc` instance, not a block.
|
20
|
-
|
23
|
+
#
|
24
|
+
# @param name [String, Symbol] name of the callback
|
25
|
+
# @param block [Proc] optionally define the callback behavior
|
26
|
+
def initialize(name, source, block=nil)
|
21
27
|
@name = name
|
28
|
+
@source = source
|
22
29
|
if(block.nil? && self.class == Callback)
|
23
30
|
raise ArgumentError.new 'Block is required for dynamic callbacks!'
|
24
31
|
end
|
@@ -28,32 +35,41 @@ module Carnivore
|
|
28
35
|
|
29
36
|
# Used by custom callback classes for setup
|
30
37
|
def setup
|
38
|
+
debug 'No custom setup defined'
|
31
39
|
end
|
32
40
|
|
33
41
|
# Provide nice output when printed
|
42
|
+
#
|
43
|
+
# @return [String]
|
34
44
|
def inspect
|
35
45
|
"callback<#{self.name}:#{self.object_id}>"
|
36
46
|
end
|
37
47
|
alias_method :to_s, :inspect
|
38
48
|
|
39
|
-
#
|
40
|
-
#
|
49
|
+
# Message is valid for this callback
|
50
|
+
#
|
51
|
+
# @param message [Carnivore::Message]
|
52
|
+
# @return [TrueClass, FalseClass]
|
41
53
|
def valid?(message)
|
42
54
|
true
|
43
55
|
end
|
44
56
|
|
45
|
-
# message
|
46
|
-
#
|
57
|
+
# Execute callback against given message
|
58
|
+
#
|
59
|
+
# @param message [Carnivore::Message]
|
47
60
|
def call(message)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
61
|
+
begin
|
62
|
+
if(valid?(message))
|
63
|
+
debug ">> Received message is valid for this callback (#{message})"
|
64
|
+
execute(message)
|
65
|
+
else
|
66
|
+
debug "Invalid message for this callback #{message})"
|
67
|
+
end
|
68
|
+
rescue => e
|
69
|
+
error "[callback: #{self}, source: #{message[:source]}, message: #{message[:message].object_id}]: #{e.class} - #{e}"
|
70
|
+
debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
71
|
+
nil
|
53
72
|
end
|
54
|
-
rescue => e
|
55
|
-
error "[callback: #{self}, source: #{message[:source]}, message: #{message[:message].object_id}]: #{e.class} - #{e}"
|
56
|
-
debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
57
73
|
end
|
58
74
|
|
59
75
|
end
|
data/lib/carnivore/config.rb
CHANGED
@@ -3,14 +3,18 @@ require 'mixlib/config'
|
|
3
3
|
require 'carnivore'
|
4
4
|
|
5
5
|
module Carnivore
|
6
|
+
# Configuration helper
|
6
7
|
class Config
|
7
8
|
|
8
9
|
extend Mixlib::Config
|
9
10
|
|
10
11
|
class << self
|
11
12
|
|
12
|
-
# v:: Boolean value
|
13
13
|
# Set/get automatic symbolization of hash keys
|
14
|
+
#
|
15
|
+
# @param v [Object] truthy or falsey value
|
16
|
+
# @return [TrueClass, FalseClass]
|
17
|
+
# v:: Boolean value
|
14
18
|
def auto_symbolize(v=nil)
|
15
19
|
unless(v.nil?)
|
16
20
|
@hash_symbolizer = !!v
|
@@ -18,16 +22,20 @@ module Carnivore
|
|
18
22
|
@hash_symbolizer.nil? ? false : @hash_symbolizer
|
19
23
|
end
|
20
24
|
|
21
|
-
# args:: configuration hash
|
22
25
|
# Merge provided args into configuration
|
26
|
+
#
|
27
|
+
# @param args [Hash]
|
28
|
+
# @return [self]
|
23
29
|
def configure(args)
|
24
30
|
build(args[:config_path]) if args[:config_path]
|
25
31
|
self.merge!(args)
|
26
32
|
self
|
27
33
|
end
|
28
34
|
|
29
|
-
# path_or_hash:: Path to JSON file or configuration Hash
|
30
35
|
# Populates the configuration
|
36
|
+
#
|
37
|
+
# @param path_or_hash [String, Hash] Path to JSON file or configuration hash
|
38
|
+
# @return [self]
|
31
39
|
def build(path_or_hash)
|
32
40
|
if(path_or_hash.is_a?(Hash))
|
33
41
|
conf = path_or_hash
|
@@ -45,18 +53,20 @@ module Carnivore
|
|
45
53
|
self
|
46
54
|
end
|
47
55
|
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
+
# Fetch value from configuration
|
57
|
+
#
|
58
|
+
# @param ary [String, Symbol] list of strings or symbols as hash path
|
59
|
+
# @return [Object] return value or nil
|
60
|
+
# @example
|
61
|
+
# Config.build(:my_app => {:port => 30})
|
62
|
+
# Config.get(:my_app, :port) => 30
|
63
|
+
# Config.get(:my_app, :host) => nil
|
64
|
+
# Config.get(:other_app, :port) => nil
|
65
|
+
# Config.get(:my_app, :mail, :server) => nil
|
56
66
|
def get(*ary)
|
57
67
|
value = Carnivore::Utils.retrieve(self, *ary)
|
58
68
|
if(value.is_a?(Hash) && auto_symbolize)
|
59
|
-
|
69
|
+
Smash.new(value)
|
60
70
|
else
|
61
71
|
value
|
62
72
|
end
|
data/lib/carnivore/container.rb
CHANGED
@@ -2,17 +2,25 @@ require 'carnivore'
|
|
2
2
|
require 'celluloid/logger'
|
3
3
|
|
4
4
|
module Carnivore
|
5
|
+
# Module used for building isolation
|
5
6
|
class Container < Module
|
6
7
|
|
7
8
|
include Carnivore::Utils::Logging
|
9
|
+
# @!parse include Carnivore::Utils::Logging
|
8
10
|
|
9
11
|
class << self
|
12
|
+
|
13
|
+
# @return [Celluloid::Logger]
|
10
14
|
def log
|
11
15
|
Celluloid::Logger
|
12
16
|
end
|
17
|
+
|
13
18
|
end
|
19
|
+
|
20
|
+
# @return [Celluloid::Logger]
|
14
21
|
def log
|
15
22
|
Celluloid::Logger
|
16
23
|
end
|
24
|
+
|
17
25
|
end
|
18
26
|
end
|
data/lib/carnivore/errors.rb
CHANGED
data/lib/carnivore/message.rb
CHANGED
@@ -1,40 +1,47 @@
|
|
1
1
|
require 'carnivore'
|
2
2
|
|
3
3
|
module Carnivore
|
4
|
+
# Wraps a message (Hash) with Carnivore specific helpers
|
4
5
|
class Message
|
5
6
|
|
7
|
+
# @return [Hash] underlying message hash
|
6
8
|
attr_reader :args
|
7
9
|
|
10
|
+
# @param args [Hash]
|
11
|
+
# @option args [Carnivore::Source] :source origin source of message
|
8
12
|
def initialize(args={})
|
13
|
+
args = args.to_smash
|
9
14
|
unless(args[:source])
|
10
15
|
raise ArgumentError.new("A valid `Carnivore::Source` name must be provided via `:source`")
|
11
16
|
end
|
12
|
-
@args = args
|
17
|
+
@args = args
|
13
18
|
end
|
14
19
|
|
15
|
-
#
|
20
|
+
# @return [Array<String>] keys available in message hash
|
16
21
|
def keys
|
17
22
|
args.keys
|
18
23
|
end
|
19
24
|
|
20
|
-
#
|
21
|
-
#
|
25
|
+
# Message accessor
|
26
|
+
#
|
27
|
+
# @param k [String, Symbol]
|
22
28
|
def [](k)
|
23
|
-
args[k
|
29
|
+
args[k]
|
24
30
|
end
|
25
31
|
|
26
|
-
# args:: Arguments
|
27
32
|
# Confirm message was received on source
|
33
|
+
#
|
34
|
+
# @param args [Object] list passed to Carnivore::Source#confirm
|
28
35
|
def confirm!(*args)
|
29
36
|
self[:source].confirm(*([self] + args).flatten(1).compact)
|
30
37
|
end
|
31
38
|
|
32
|
-
#
|
39
|
+
# @return [String] formatted inspection string
|
33
40
|
def inspect
|
34
41
|
"<Carnivore::Message[#{self.object_id}] @args=#{args.inspect}>"
|
35
42
|
end
|
36
43
|
|
37
|
-
# String representation
|
44
|
+
# @return [String] string representation
|
38
45
|
def to_s
|
39
46
|
"<Carnivore::Message:#{self.object_id}>"
|
40
47
|
end
|
data/lib/carnivore/runner.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
|
-
require 'carnivore
|
1
|
+
require 'carnivore'
|
2
2
|
|
3
3
|
module Carnivore
|
4
4
|
class << self
|
5
5
|
|
6
|
-
# block:: Block of configuration
|
7
6
|
# Add configuration to Carnivore
|
7
|
+
#
|
8
|
+
# @yield block of configuration
|
9
|
+
# @return [self]
|
8
10
|
def configure(&block)
|
9
11
|
mod = Container.new
|
10
12
|
mod.instance_exec(mod, &block)
|
11
13
|
self
|
12
14
|
end
|
13
15
|
|
14
|
-
# Start
|
16
|
+
# Start the Carnivore subsystem
|
15
17
|
def start!
|
16
18
|
supervisor = nil
|
17
19
|
begin
|
@@ -44,7 +46,9 @@ module Carnivore
|
|
44
46
|
sleep 10
|
45
47
|
retry
|
46
48
|
rescue Exception => e
|
47
|
-
|
49
|
+
Celluloid::Logger.warn "Exception type encountered forcing shutdown - #{e.class}: #{e}"
|
50
|
+
Celluloid::Logger.debug "Shutdown exception info: #{e.class}: #{e}\n#{e.backtrace.join("\n")}"
|
51
|
+
supervisor.terminate if supervisor
|
48
52
|
# Gracefully shut down
|
49
53
|
end
|
50
54
|
end
|
@@ -1,18 +1,23 @@
|
|
1
1
|
module Carnivore
|
2
2
|
class Source
|
3
|
+
# Test source
|
3
4
|
class Test < Source
|
4
5
|
|
6
|
+
# Maximum rand value
|
5
7
|
RAND_MAX = 99999
|
8
|
+
# Default rand divisor
|
6
9
|
RAND_DIV = 3
|
10
|
+
# Sleep length when valid
|
7
11
|
RAND_SLEEP = 10
|
8
12
|
|
9
|
-
|
10
|
-
end
|
11
|
-
|
13
|
+
# Note that we are connected
|
12
14
|
def connect(*args)
|
13
15
|
info 'Test connect called'
|
14
16
|
end
|
15
17
|
|
18
|
+
# Receive randomly generated message
|
19
|
+
#
|
20
|
+
# @return [Array<String>]
|
16
21
|
def receive(*args)
|
17
22
|
if(rand(RAND_MAX) % RAND_DIV == 0)
|
18
23
|
sleep_for = rand(RAND_SLEEP)
|
@@ -22,6 +27,9 @@ module Carnivore
|
|
22
27
|
20.times.map{('a'..'z').to_a.shuffle.first}.join
|
23
28
|
end
|
24
29
|
|
30
|
+
# Dummy transmit message
|
31
|
+
#
|
32
|
+
# @param message [Carnivore::Message]
|
25
33
|
def transmit(message)
|
26
34
|
info "Transmit requested: #{message}"
|
27
35
|
end
|