genesisreactor 0.0.1

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.
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: