genesisreactor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4817f006c4e5a7f526e34621d7a2ade1dcf2d023
4
+ data.tar.gz: e5d4f096612c72f90d8e68045b2611f2f3e1b2b0
5
+ SHA512:
6
+ metadata.gz: 7e9893694f8f69a7f1c872604f7c39ff12e06be91288999408eb0349131254c40d62be9afdad0b12bceae9dcf4fdd3da0e154c95540b2066fec190b69d278d6e
7
+ data.tar.gz: b093bd04764782ed939d155fd98c01f06eaf5c4e00338f1fcd8c099a4b032a60bc3ad9eb7794e3ec6495a9b216f259da2ee9228829a85bf2c2caced7cc08f283
@@ -0,0 +1,25 @@
1
+ module Genesis
2
+ # Interface for a GenesisAgent
3
+ # Allows subclasess specifying agents in a DSL
4
+ class Agent
5
+ class << self
6
+ attr_accessor :agents
7
+ def register_agent(**kwargs, &block)
8
+ @agents << { interval: kwargs[:interval] || 60, opts: kwargs, block: block }
9
+ end
10
+
11
+ def reset!
12
+ @agents = []
13
+ end
14
+
15
+ def inherited(subclass)
16
+ subclass.reset!
17
+ super
18
+ end
19
+
20
+ alias_method :schedule, :register_agent
21
+ end
22
+
23
+ reset!
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ module Genesis
2
+ # Interface for a GenesisHandler
3
+ # Allows subclasess specifying routes and subscribers in a DSL
4
+ class Handler
5
+ class << self
6
+ attr_accessor :routes, :subscribers
7
+ def register_route(match, opts = {}, &block)
8
+ @routes[match] = { verb: __callee__.to_s, opts: opts, block: block }
9
+ end
10
+
11
+ def register_subscriber(*_args, &block)
12
+ @subscribers << { block: block }
13
+ end
14
+
15
+ def reset!
16
+ @subscribers = []
17
+ @routes = {}
18
+ end
19
+
20
+ def inherited(subclass)
21
+ subclass.reset!
22
+ super
23
+ end
24
+
25
+ alias_method :subscribe, :register_subscriber
26
+ end
27
+
28
+ reset!
29
+ end
30
+ end
@@ -0,0 +1,10 @@
1
+ require 'genesis/agent'
2
+
3
+ module Genesis
4
+ module Echo
5
+ # Define an agent for Echo protocol
6
+ class Agent < Genesis::Agent
7
+ include Protocol
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ require 'genesis/handler'
2
+
3
+ module Genesis
4
+ module Echo
5
+ # A test handler to demonstrate functionality and facilitate testing
6
+ class Handler < Genesis::Handler
7
+ include Protocol
8
+
9
+ class << self
10
+ alias_method :say, :register_route
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ require 'genesis/protocol'
2
+
3
+ module Genesis
4
+ module Echo
5
+ # Implement a simple protocol to demonstrate
6
+ # how to write a protocol, and facilitate testing.
7
+ # In keeping with event machine tradition, it's a simple 'echo' protocol.
8
+ module Protocol
9
+ include Genesis::Protocol
10
+
11
+ def self.protocol
12
+ :echo
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ require 'genesis/server'
2
+
3
+ module Genesis
4
+ module Echo
5
+ # Implement a test server to demonstrate functionality and facilitate testing
6
+ class Server < EM::Connection
7
+ include Genesis::Server
8
+ include Protocol
9
+ def receive_data(data)
10
+ @channel << data
11
+ @handle_routes.each do |verb, matchdata|
12
+ case verb
13
+ when 'say'
14
+ matchdata.each do |pattern, blockdata|
15
+ send_data blockdata[:block].call(data) if data =~ pattern
16
+ end
17
+ end
18
+ end
19
+ close_connection_after_writing
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ require 'genesis/protocol/echo/protocol'
2
+ require 'genesis/protocol/echo/server'
3
+ require 'genesis/protocol/echo/handler'
4
+ require 'genesis/protocol/echo/agent'
@@ -0,0 +1,19 @@
1
+ # Monkey-patch async sinatra to support all verb sinatra supports
2
+ # Can remove if this patch gets merged:
3
+ # https://github.com/raggi/async_sinatra/pull/39
4
+ module Sinatra
5
+ # Monkey patch async to add some more methods
6
+ module Async
7
+ def apatch(path, opts = {}, &bk)
8
+ aroute('PATCH', path, opts, &bk)
9
+ end
10
+
11
+ def alink(path, opts = {}, &bk)
12
+ aroute('LINK', path, opts, &bk)
13
+ end
14
+
15
+ def aunlink(path, opts = {}, &bk)
16
+ aroute('UNLINK', path, opts, &bk)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ require 'genesis/handler'
2
+
3
+ module Genesis
4
+ module Http
5
+ # Handle various HTTP verbs
6
+ class Handler < Genesis::Handler
7
+ include Protocol
8
+
9
+ class << self
10
+ alias_method :get, :register_route
11
+ alias_method :post, :register_route
12
+ alias_method :delete, :register_route
13
+ alias_method :head, :register_route
14
+ alias_method :options, :register_route
15
+ alias_method :patch, :register_route
16
+ alias_method :link, :register_route
17
+ alias_method :unlink, :register_route
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ require 'genesis/protocol'
2
+
3
+ module Genesis
4
+ module Http
5
+ # Implement support for HTTP protocol
6
+ # Levering sinatra_async, and the fact that thin uses eventmachine
7
+ module Protocol
8
+ include Genesis::Protocol
9
+
10
+ def self.start_block
11
+ proc { Server.start_server }
12
+ end
13
+
14
+ def self.protocol
15
+ :http
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,88 @@
1
+ require 'sinatra/async'
2
+ require 'thin'
3
+
4
+ require 'genesis/server'
5
+ require 'async_monkeypatch'
6
+
7
+ module Genesis
8
+ module Http
9
+ # Implement an HTTP server using async_sinatra and thin
10
+ class Server < Sinatra::Base
11
+ include Genesis::Server
12
+ include Protocol
13
+ register Sinatra::Async
14
+
15
+ # Block to actually start the server
16
+ def self.start_server
17
+ app = new(channel: @channel, routes: @handle_routes, views: @args[:views] || [])
18
+ dispatch = Rack::Builder.app do
19
+ map '/' do
20
+ run app
21
+ end
22
+ end
23
+
24
+ # Since Thin is backed by EventMachine's TCPserver anyways,
25
+ # This is just a TCPServer like any other - running inside the same EventMachine!
26
+ Thin::Server.new(@port, '0.0.0.0', dispatch).backend.start
27
+ end
28
+
29
+ # Inject the channel and extended routes
30
+ def initialize(app = nil, **kwargs)
31
+ super(app)
32
+ @channel = kwargs[:channel] || nil
33
+ @extended_routes = kwargs[:routes] || {}
34
+ @views = kwargs[:views] || []
35
+ initialize_routes
36
+ end
37
+
38
+ private
39
+
40
+ # Register all routes provided
41
+ def initialize_routes
42
+ @extended_routes.each do |verb, matches|
43
+ matches.each do |match, data|
44
+ register_route(verb, match, data[:args], data[:block])
45
+ end
46
+ end
47
+ end
48
+
49
+ # Injects a route into the sinatra class
50
+ def register_route(verb, match, opts, block)
51
+ async_verb = "a#{verb}" # force verb to async verb
52
+ self.class.send(async_verb, match, opts, &block)
53
+ end
54
+
55
+ helpers do
56
+ # Enable partial template rendering
57
+ def partial(template, locals = {})
58
+ erb(template, layout: false, locals: locals)
59
+ end
60
+
61
+ # Override template search directorys to add spells
62
+ def find_template(views, *a, &block)
63
+ Array(@views).each { |v| super(v, *a, &block) }
64
+ end
65
+
66
+ # Define our asynchronous scheduling mechanism, could be anything
67
+ # Chose EM.defer for simplicity
68
+ # This powers our asynchronous requests, and keeps us from blocking the main thread.
69
+ def native_async_schedule(&b)
70
+ EM.defer(&b)
71
+ end
72
+
73
+ # Needed to properly catch exceptions in async threads
74
+ def handle_exception!(context)
75
+ if context.message == 'Sinatra::NotFound'
76
+ error_msg = "Resource #{request.path} does not exist"
77
+ puts error_msg
78
+ ahalt(404, error_msg)
79
+ else
80
+ puts context.message
81
+ puts context.backtrace.join("\n")
82
+ ahalt(500, 'Uncaught exception occurred')
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,3 @@
1
+ require 'genesis/protocol/http/protocol'
2
+ require 'genesis/protocol/http/server'
3
+ require 'genesis/protocol/http/handler'
@@ -0,0 +1,10 @@
1
+ require 'genesis/agent'
2
+
3
+ module Genesis
4
+ module Snmp
5
+ # Define an agent for Snmp protocol
6
+ class Agent < Genesis::Agent
7
+ include Protocol
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ require 'genesis/handler'
2
+
3
+ module Genesis
4
+ module Snmp
5
+ # Implement a handler for SNMP traps
6
+ class Handler < Genesis::Handler
7
+ include Protocol
8
+
9
+ class << self
10
+ alias_method :trap, :register_route
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ module Genesis
2
+ module Snmp
3
+ # Implement support for SNMP protocol using pure-ruby snmp.
4
+ module Protocol
5
+ include Genesis::Protocol
6
+
7
+ def self.start_block
8
+ proc { Server.start_server }
9
+ end
10
+
11
+ def self.protocol
12
+ :snmp
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,81 @@
1
+ require 'snmp'
2
+ require 'socket'
3
+
4
+ require 'genesis/server'
5
+
6
+ module Genesis
7
+ module Snmp
8
+ # Implement an SNMP trap handling server
9
+ class Server < EM::Connection
10
+ include Genesis::Server
11
+ include Protocol
12
+
13
+ attr_accessor :mib, :community
14
+
15
+ def self.start_server
16
+ commstr = @args[:community] || ''
17
+ mib_dir = @args[:mib_dir] || SNMP::MIB::DEFAULT_MIB_PATH
18
+ mib_mods = @args[:mib_mods] || SNMP::Options.default_modules
19
+ mib = load_modules(mib_mods, mib_dir)
20
+ EM.open_datagram_socket('0.0.0.0', @port, self) do |conn|
21
+ conn.mib = mib
22
+ conn.community = commstr
23
+ conn.channel = @channel
24
+ conn.handle_routes = @handle_routes
25
+ end
26
+ end
27
+
28
+ def self.load_modules(module_list, mib_dir)
29
+ mib = SNMP::MIB.new
30
+ module_list.each { |m| mib.load_module(m, mib_dir) }
31
+ mib
32
+ end
33
+
34
+ def receive_data(data)
35
+ snmp_trap = handle_trap(data)
36
+ @channel << snmp_trap
37
+ route_trap(snmp_trap)
38
+ end
39
+
40
+ private
41
+
42
+ def handle_trap(data)
43
+ source_port, source_ip = Socket.unpack_sockaddr_in(get_peername)
44
+
45
+ message = SNMP::Message.decode(data, @mib)
46
+ snmp_trap = message.pdu
47
+
48
+ # If we configured a community and the message wasn't from our community, bail
49
+ close_connection if @community != '' && @community != message.community
50
+
51
+ # Handle inform requests, which want a response
52
+ handle_inform(snmp_trap, message, source_ip, source_port)
53
+
54
+ # Append source ip and return
55
+ snmp_trap.source_ip = source_ip
56
+ snmp_trap
57
+ end
58
+
59
+ def handle_inform(snmp_trap, message, source_ip, source_port)
60
+ return unless snmp_trap.is_a?(SNMP::InformRequest)
61
+ UDPSocket.new.send(message.response.encode, 0, source_ip, source_port)
62
+ end
63
+
64
+ def route_trap(snmp_trap)
65
+ @handle_routes.each do |verb, matchdata|
66
+ case verb
67
+ when 'trap'
68
+ route_trap_handler(snmp_trap, matchdata)
69
+ end
70
+ end
71
+ end
72
+
73
+ def route_trap_handler(snmp_trap, matchdata)
74
+ trap_oid = snmp_trap.trap_oid.join('.')
75
+ matchdata.each do |oid, blockdata|
76
+ blockdata[:block].call(snmp_trap) if oid =~ /#{trap_oid}/
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,55 @@
1
+ require 'snmp'
2
+
3
+ require 'genesis/protocol/snmp/protocol'
4
+ require 'genesis/protocol/snmp/server'
5
+ require 'genesis/protocol/snmp/handler'
6
+ require 'genesis/protocol/snmp/agent'
7
+
8
+ module Genesis
9
+ # Common helper methods for protocol
10
+ module Snmp
11
+ # Send an SNMP trap, returns the length of the trap message sent
12
+ def self.send_trap(sys_up_time, trap_oid, object_list = [], **kwargs)
13
+ manager(kwargs) do |mgr|
14
+ return mgr.trap_v2(sys_up_time, trap_oid, object_list)
15
+ end
16
+ end
17
+
18
+ # Send an SNMP get request
19
+ def self.get(oids = [], **kwargs)
20
+ manager(kwargs) do |mgr|
21
+ mgr.get(oids)
22
+ end
23
+ end
24
+
25
+ # FIXME: implement - these are tricky to test without an actual SNMP server
26
+ # # Send an SNMP set request
27
+ # def self.set(bindings = {}, **kwargs)
28
+ # manager(kwargs) do |mgr|
29
+ # bindings.each do |oid, value|
30
+ # mgr.set(SNMP::VarBind.new(oid, value)) # FIXME maybe try and infer type for varbind from value's type to avoid leaky abstraction?
31
+ # end
32
+ # end
33
+ # end
34
+
35
+ # # Walk an OID table rooted at any oids provided
36
+ # def self.walk(oids = [], **kwargs)
37
+ # manager(kwargs) do |mgr|
38
+ # mgr.walk(oids)
39
+ # end
40
+ # end
41
+
42
+ private
43
+
44
+ # Create a manager and yield it to perform the request
45
+ def self.manager(args)
46
+ host = args[:host] || '127.0.0.1'
47
+ port = args[:port] || 161
48
+ trapport = args[:trapport] || 162
49
+ community = args[:community] || 'public'
50
+ SNMP::Manager.open(Host: host, Port: port, TrapPort: trapport, Community: community) do |mgr|
51
+ yield mgr
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,20 @@
1
+ module Genesis
2
+ # Use some metaprogramming to DRY up protocol definition
3
+ module Protocol
4
+ def self.included(base) # rubocop:disable Metrics/MethodLength
5
+ class << base
6
+ def included(base)
7
+ protocol = self
8
+ base.define_singleton_method(:protocol) { protocol.protocol }
9
+ end
10
+
11
+ def server
12
+ Kernel.const_get((to_s.split('::')[0..-2] << 'Server').join('::'))
13
+ end
14
+
15
+ def start_block
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,169 @@
1
+ ## We can dynamically adjust the threadpool like below, if we want to.
2
+ ## It should be possible to make the threadpool elastic very easily, though this may impact performance
3
+ # module EventMachine
4
+ # def self.adjust_threadpool
5
+ #
6
+ # unless @threadpool.size == @threadpool_size.to_i
7
+ # spawn_threadpool
8
+ # end
9
+ #
10
+ # end
11
+
12
+ require 'em-synchrony'
13
+
14
+ module Genesis
15
+ # Main reactor class
16
+ # rubocop:disable ClassLength
17
+ class Reactor
18
+ def initialize(**kwargs)
19
+ reset
20
+ @poolsize = kwargs[:threads] || 100 # maximum concurrency - larger = longer boot and shutdown time
21
+ @protocols = kwargs[:protocols] || {}
22
+ @views = kwargs[:views] || {}
23
+ register_handlers(kwargs[:handlers] || {})
24
+ register_agents(kwargs[:agents] || [])
25
+ end
26
+
27
+ # Convenience wrapper to run indefinitely as daemon
28
+ def start
29
+ EM.synchrony do
30
+ run
31
+ end
32
+ end
33
+
34
+ # Run the reactor - must be called from EM.run or EM.synchrony
35
+ def run
36
+ if running?
37
+ initialize_protocols
38
+ initialize_threadpool
39
+ initialize_sighandlers
40
+ return true
41
+ else
42
+ fail 'Must run from within reactor'
43
+ end
44
+ end
45
+
46
+ # Check if the reactor is running
47
+ def running?
48
+ EM.reactor_running?
49
+ end
50
+
51
+ # Stop the reactor
52
+ def stop
53
+ puts 'Shutting down'
54
+ EM.stop
55
+ end
56
+
57
+ private
58
+
59
+ # Reset / initialize instance variables
60
+ def reset
61
+ @protocols = {}
62
+ @servers = {}
63
+ @routes = {}
64
+ @subscribers = {}
65
+ @agents = {}
66
+ @channels = {}
67
+ end
68
+
69
+ # Initialize signal handlers to cleanly shutdown
70
+ def initialize_sighandlers
71
+ trap(:INT) do
72
+ stop
73
+ exit
74
+ end
75
+ end
76
+
77
+ # Initialize servers for each protocol
78
+ def initialize_servers
79
+ @protocols.each do |protocol, _|
80
+ server = @servers[protocol.protocol]
81
+ block = server[:start]
82
+ server[:server].start(server[:port], @routes[protocol.protocol], views: @views, channel: @channels[protocol.protocol], &block)
83
+ end
84
+ end
85
+
86
+ # Initialize protocols to be handled
87
+ def initialize_protocols
88
+ @protocols.each do |protocol, _|
89
+ server = protocol.server
90
+ @servers[protocol.protocol] = { server: server, port: @protocols[protocol], start: protocol.start_block }
91
+ @channels[protocol.protocol] = EM::Channel.new
92
+ end
93
+ initialize_servers
94
+ initialize_subscribers
95
+ initialize_agents
96
+ end
97
+
98
+ # Sets the initial size of the threadpool
99
+ def initialize_threadpool
100
+ EM.threadpool_size = @poolsize
101
+ end
102
+
103
+ # Sets up agents
104
+ def initialize_agents
105
+ @agents.each do |protocol, agents|
106
+ agents.each do |data|
107
+ EM.add_periodic_timer(data[:interval]) do
108
+ EM.defer { data[:block].call(@channels[protocol]) }
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ # Set up subscriptions to channels
115
+ def initialize_subscribers
116
+ @subscribers.each do |type, subscribers|
117
+ channel = @channels[type]
118
+ if channel
119
+ subscribers.each do |subscriber|
120
+ channel.subscribe do |message|
121
+ EM.defer { subscriber.call(message) }
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ # Registers all handlers
129
+ def register_handlers(handlers)
130
+ handlers.each do |handler|
131
+ (handler.routes || {}).each do |match, data|
132
+ register_route(handler.protocol, data[:verb], match, data[:opts], data[:block])
133
+ end
134
+
135
+ (handler.subscribers || []).each do |data|
136
+ register_subscriber(handler.protocol, data[:block])
137
+ end
138
+ end
139
+ end
140
+
141
+ # Registers all agenst
142
+ def register_agents(agents)
143
+ agents.each do |agent|
144
+ (agent.agents || {}).each do |data|
145
+ register_agent(agent.protocol, data)
146
+ end
147
+ end
148
+ end
149
+
150
+ # Registers a route for a given protocol
151
+ def register_route(protocol, verb, match, args, block)
152
+ @routes[protocol] ||= {}
153
+ @routes[protocol][verb] ||= {}
154
+ @routes[protocol][verb][match] = { block: block, args: args }
155
+ end
156
+
157
+ # Registers a handler for a given protocol
158
+ def register_subscriber(protocol, block)
159
+ @subscribers[protocol] ||= []
160
+ @subscribers[protocol] << block
161
+ end
162
+
163
+ # Registers an agent for a given protocol
164
+ def register_agent(protocol, method)
165
+ @agents[protocol] ||= []
166
+ @agents[protocol] << method
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,39 @@
1
+ require 'eventmachine'
2
+
3
+ module Genesis
4
+ # Abstract base class for all servers
5
+ module Server
6
+ attr_accessor :handle_routes, :channel
7
+
8
+ def self.included(base)
9
+ base.extend ClassMethods
10
+ end
11
+
12
+ # Methods to be injected onto the class
13
+ module ClassMethods
14
+ def start(port, routes, **kwargs, &block)
15
+ @port = port
16
+ @handle_routes = routes || []
17
+ @channel = kwargs[:channel]
18
+ @args = kwargs
19
+
20
+ # Allow a custom, non EM, server to be run
21
+ if block_given? && block
22
+ yield
23
+ else
24
+ default_start
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def default_start
31
+ # But default to an EM server if nothing else is provided
32
+ EM.start_server '0.0.0.0', @port, self do |conn|
33
+ conn.channel = @channel
34
+ conn.handle_routes = @handle_routes
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ require 'find'
2
+
3
+ Find.find(File.join(File.dirname(File.dirname(__FILE__)), 'lib')) do |f|
4
+ $LOAD_PATH << f if File.directory? f
5
+ end
6
+
7
+ require 'genesis/reactor'
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: genesisreactor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dale Hamel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: em-synchrony
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: async_sinatra
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: thin
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.6.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.6.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: snmp
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.2.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 1.2.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 3.2.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 3.2.0
83
+ description: GenesisReactor provides a protocol agnostic framework for implementing
84
+ simple pub/sub message production and handling.
85
+ email: dale.hamel@srvthe.net
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - lib/genesis/agent.rb
91
+ - lib/genesis/handler.rb
92
+ - lib/genesis/protocol.rb
93
+ - lib/genesis/protocol/echo.rb
94
+ - lib/genesis/protocol/echo/agent.rb
95
+ - lib/genesis/protocol/echo/handler.rb
96
+ - lib/genesis/protocol/echo/protocol.rb
97
+ - lib/genesis/protocol/echo/server.rb
98
+ - lib/genesis/protocol/http.rb
99
+ - lib/genesis/protocol/http/async_monkeypatch.rb
100
+ - lib/genesis/protocol/http/handler.rb
101
+ - lib/genesis/protocol/http/protocol.rb
102
+ - lib/genesis/protocol/http/server.rb
103
+ - lib/genesis/protocol/snmp.rb
104
+ - lib/genesis/protocol/snmp/agent.rb
105
+ - lib/genesis/protocol/snmp/handler.rb
106
+ - lib/genesis/protocol/snmp/protocol.rb
107
+ - lib/genesis/protocol/snmp/server.rb
108
+ - lib/genesis/reactor.rb
109
+ - lib/genesis/server.rb
110
+ - lib/genesisreactor.rb
111
+ homepage: http://rubygems.org/gems/genesisreactor
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.4.6
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Event driven infrastructor automation framework
135
+ test_files: []
136
+ has_rdoc: