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 +7 -0
- data/lib/genesis/agent.rb +25 -0
- data/lib/genesis/handler.rb +30 -0
- data/lib/genesis/protocol/echo/agent.rb +10 -0
- data/lib/genesis/protocol/echo/handler.rb +14 -0
- data/lib/genesis/protocol/echo/protocol.rb +16 -0
- data/lib/genesis/protocol/echo/server.rb +23 -0
- data/lib/genesis/protocol/echo.rb +4 -0
- data/lib/genesis/protocol/http/async_monkeypatch.rb +19 -0
- data/lib/genesis/protocol/http/handler.rb +21 -0
- data/lib/genesis/protocol/http/protocol.rb +19 -0
- data/lib/genesis/protocol/http/server.rb +88 -0
- data/lib/genesis/protocol/http.rb +3 -0
- data/lib/genesis/protocol/snmp/agent.rb +10 -0
- data/lib/genesis/protocol/snmp/handler.rb +14 -0
- data/lib/genesis/protocol/snmp/protocol.rb +16 -0
- data/lib/genesis/protocol/snmp/server.rb +81 -0
- data/lib/genesis/protocol/snmp.rb +55 -0
- data/lib/genesis/protocol.rb +20 -0
- data/lib/genesis/reactor.rb +169 -0
- data/lib/genesis/server.rb +39 -0
- data/lib/genesisreactor.rb +7 -0
- metadata +136 -0
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,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,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,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
|
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:
|