automate-em 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.
- data/LGPL3-LICENSE +165 -0
- data/README.textile +48 -0
- data/Rakefile +40 -0
- data/app/models/control_system.rb +20 -0
- data/app/models/controller_device.rb +21 -0
- data/app/models/controller_http_service.rb +17 -0
- data/app/models/controller_logic.rb +5 -0
- data/app/models/controller_zone.rb +10 -0
- data/app/models/dependency.rb +20 -0
- data/app/models/server.rb +12 -0
- data/app/models/setting.rb +38 -0
- data/app/models/trusted_device.rb +63 -0
- data/app/models/user_zone.rb +10 -0
- data/app/models/zone.rb +16 -0
- data/db/migrate/20111001022500_init.rb +147 -0
- data/db/migrate/20111017213801_one_time_key.rb +9 -0
- data/db/migrate/20111021071632_encrypt_setting.rb +9 -0
- data/db/migrate/20111110075444_servers.rb +15 -0
- data/db/migrate/20111114074538_default_port.rb +9 -0
- data/db/migrate/20111122073055_makebreak.rb +9 -0
- data/db/migrate/20111211062846_create_controller_http_services.rb +18 -0
- data/lib/automate-em.rb +155 -0
- data/lib/automate-em/constants.rb +6 -0
- data/lib/automate-em/core/communicator.rb +318 -0
- data/lib/automate-em/core/modules.rb +373 -0
- data/lib/automate-em/core/resolver_pool.rb +76 -0
- data/lib/automate-em/core/system.rb +356 -0
- data/lib/automate-em/device/datagram_server.rb +111 -0
- data/lib/automate-em/device/device.rb +140 -0
- data/lib/automate-em/device/device_connection.rb +689 -0
- data/lib/automate-em/device/tcp_control.rb +210 -0
- data/lib/automate-em/engine.rb +36 -0
- data/lib/automate-em/interfaces/OLD CODE/deferred.rb +67 -0
- data/lib/automate-em/interfaces/OLD CODE/telnet/ansi.rb +137 -0
- data/lib/automate-em/interfaces/OLD CODE/telnet/telnet.rb +137 -0
- data/lib/automate-em/interfaces/html5.rb +302 -0
- data/lib/automate-em/logic/logic.rb +76 -0
- data/lib/automate-em/service/http_service.rb +584 -0
- data/lib/automate-em/service/service.rb +48 -0
- data/lib/automate-em/status.rb +89 -0
- data/lib/automate-em/utilities.rb +195 -0
- data/lib/automate-em/version.rb +3 -0
- data/lib/generators/module/USAGE +8 -0
- data/lib/generators/module/module_generator.rb +47 -0
- data/lib/tasks/automate-em_tasks.rake +5 -0
- data/test/automate-em_test.rb +7 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +56 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/test_helper.rb +15 -0
- metadata +328 -0
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'atomic'
|
2
|
+
|
3
|
+
module AutomateEm
|
4
|
+
|
5
|
+
class Device
|
6
|
+
|
7
|
+
|
8
|
+
#
|
9
|
+
# This is how sending works
|
10
|
+
# Send recieves data, turns a mutex on and sends the data
|
11
|
+
# -- It goes into the recieve mutex critical section and sleeps waiting for a response
|
12
|
+
# -- a timeout is used as a backup in case no response is received
|
13
|
+
# The recieve function does the following
|
14
|
+
# -- If the send lock is not active it processes the received data
|
15
|
+
# -- otherwise it notifies the send function that data is avaliable
|
16
|
+
#
|
17
|
+
class Base < EventMachine::Connection
|
18
|
+
include Utilities
|
19
|
+
include DeviceConnection
|
20
|
+
|
21
|
+
#
|
22
|
+
# EM Callbacks: --------------------------------------------------------
|
23
|
+
#
|
24
|
+
#def post_init
|
25
|
+
# return unless @parent.respond_to?(:initiate_session)
|
26
|
+
#
|
27
|
+
# begin
|
28
|
+
# @parent.initiate_session(@tls_enabled)
|
29
|
+
# rescue => e
|
30
|
+
# #
|
31
|
+
# # save from bad user code (don't want to deplete thread pool)
|
32
|
+
# #
|
33
|
+
# EM.defer do
|
34
|
+
# logger.error "-- module #{@parent.class} error whilst calling: initiate_session --"
|
35
|
+
# logger.error e.message
|
36
|
+
# logger.error e.backtrace
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
#end
|
40
|
+
|
41
|
+
|
42
|
+
def connection_completed
|
43
|
+
# set status
|
44
|
+
resume if paused?
|
45
|
+
|
46
|
+
@connect_retry = @connect_retry || Atomic.new(0)
|
47
|
+
EM.defer do
|
48
|
+
@connect_retry.value = 0
|
49
|
+
end
|
50
|
+
|
51
|
+
if !@tls_enabled
|
52
|
+
@connected = true
|
53
|
+
@connecting = false
|
54
|
+
EM.defer do
|
55
|
+
call_connected
|
56
|
+
end
|
57
|
+
else
|
58
|
+
if !@parent.respond_to?(:certificates)
|
59
|
+
start_tls
|
60
|
+
else
|
61
|
+
begin
|
62
|
+
certs = @parent.certificates
|
63
|
+
start_tls(certs)
|
64
|
+
rescue => e
|
65
|
+
EM.defer do
|
66
|
+
AutomateEm.print_error(logger, e, {
|
67
|
+
:message => "module #{@parent.class} error whilst starting TLS with certificates",
|
68
|
+
:level => Logger::ERROR
|
69
|
+
})
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
@make_occured = true
|
76
|
+
end
|
77
|
+
|
78
|
+
def ssl_handshake_completed
|
79
|
+
@connected = true
|
80
|
+
@connecting = false
|
81
|
+
EM.defer do
|
82
|
+
call_connected(get_peer_cert) # this will mark the true connection complete stage for encrypted devices
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def unbind
|
88
|
+
@connected = false # set offline
|
89
|
+
@connecting = false
|
90
|
+
@disconnecting = false
|
91
|
+
|
92
|
+
if @config[:flush_buffer_on_disconnect]
|
93
|
+
process_response(@buf.flush, nil) unless @buf.nil?
|
94
|
+
else
|
95
|
+
@buf.flush unless @buf.nil? # Any incomplete from TCP stream is now invalid
|
96
|
+
end
|
97
|
+
|
98
|
+
@connect_retry = @connect_retry || Atomic.new(0)
|
99
|
+
|
100
|
+
if @config[:clear_queue_on_disconnect] || (@make_break && !@make_occured)
|
101
|
+
@send_queue.clear
|
102
|
+
end
|
103
|
+
@make_occured = false
|
104
|
+
|
105
|
+
EM.defer do
|
106
|
+
if !@shutting_down.value
|
107
|
+
|
108
|
+
@task_queue.push lambda {
|
109
|
+
@parent[:connected] = false
|
110
|
+
return unless @parent.respond_to?(:disconnected)
|
111
|
+
begin
|
112
|
+
@parent.disconnected
|
113
|
+
rescue => e
|
114
|
+
#
|
115
|
+
# save from bad user code (don't want to deplete thread pool)
|
116
|
+
#
|
117
|
+
AutomateEm.print_error(logger, e, {
|
118
|
+
:message => "module #{@parent.class} error whilst calling: disconnected",
|
119
|
+
:level => Logger::ERROR
|
120
|
+
})
|
121
|
+
end
|
122
|
+
}
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
if !@make_break
|
127
|
+
do_connect
|
128
|
+
elsif @send_queue.size() > 0
|
129
|
+
do_connect
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def do_connect
|
134
|
+
if @disconnecting
|
135
|
+
EM.next_tick do
|
136
|
+
do_connect
|
137
|
+
end
|
138
|
+
return
|
139
|
+
end
|
140
|
+
return if @connected # possible to get here
|
141
|
+
|
142
|
+
makebreak = @make_break
|
143
|
+
@connecting = true
|
144
|
+
EM.defer do
|
145
|
+
if !@shutting_down.value
|
146
|
+
begin
|
147
|
+
settings = DeviceModule.lookup(@parent) #.reload # Don't reload here (user driven)
|
148
|
+
|
149
|
+
@connect_retry.update { |v| v += 1}
|
150
|
+
|
151
|
+
if @connect_retry.value == 1 || makebreak
|
152
|
+
res = ResolverJob.new(settings.ip)
|
153
|
+
res.callback {|ip|
|
154
|
+
reconnect ip, settings.port
|
155
|
+
}
|
156
|
+
res.errback {|error|
|
157
|
+
EM.defer do
|
158
|
+
logger.info "module #{@parent.class} in tcp_control.rb, unbind"
|
159
|
+
logger.info "Reconnect failed for #{settings.ip}:#{settings.port} - #{error.inspect}"
|
160
|
+
end
|
161
|
+
@connect_retry.value = 2
|
162
|
+
do_reconnect(settings) unless makebreak
|
163
|
+
}
|
164
|
+
else
|
165
|
+
#
|
166
|
+
# log this once if had to retry more than once
|
167
|
+
#
|
168
|
+
if @connect_retry.value == 2
|
169
|
+
logger.info "module #{@parent.class} in tcp_control.rb, unbind"
|
170
|
+
logger.info "Reconnect failed for #{settings.ip}:#{settings.port}"
|
171
|
+
end
|
172
|
+
|
173
|
+
do_reconnect(settings)
|
174
|
+
end
|
175
|
+
rescue
|
176
|
+
AutomateEm.print_error(logger, e, {
|
177
|
+
:message => "module #{@parent.class} in tcp_control.rb, unbind\nFailed to lookup settings. Device probably going offline.",
|
178
|
+
:level => Logger::FATAL
|
179
|
+
})
|
180
|
+
|
181
|
+
# Do not attempt to reconnect this device!
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def do_reconnect(settings)
|
188
|
+
EM::Timer.new(5) do
|
189
|
+
if !@shutting_down.value
|
190
|
+
res = ResolverJob.new(settings.ip)
|
191
|
+
res.callback {|ip|
|
192
|
+
reconnect ip, settings.port
|
193
|
+
}
|
194
|
+
res.errback {|error|
|
195
|
+
do_reconnect(settings)
|
196
|
+
}
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def receive_data(data)
|
202
|
+
do_receive_data(data)
|
203
|
+
end
|
204
|
+
|
205
|
+
def do_send_data(data)
|
206
|
+
send_data(data)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module AutomateEm
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
engine_name :automate
|
4
|
+
|
5
|
+
|
6
|
+
rake_tasks do
|
7
|
+
load "tasks/automate-em_tasks.rake"
|
8
|
+
end
|
9
|
+
|
10
|
+
#
|
11
|
+
# Define the application configuration
|
12
|
+
#
|
13
|
+
config.before_initialize do |app| # Rails.configuration
|
14
|
+
app.config.automate = ActiveSupport::OrderedOptions.new
|
15
|
+
app.config.automate.module_paths = []
|
16
|
+
app.config.automate.log_level = Logger::INFO
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Discover the possible module location paths after initialisation is complete
|
21
|
+
#
|
22
|
+
config.after_initialize do |app|
|
23
|
+
|
24
|
+
app.config.assets.paths.each do |path|
|
25
|
+
Pathname.new(path).ascend do |v|
|
26
|
+
if ['app', 'vendor'].include?(v.basename.to_s)
|
27
|
+
app.config.automate.module_paths << "#{v.to_s}/modules"
|
28
|
+
break
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
app.config.automate.module_paths.uniq!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
#
|
4
|
+
# This reduces load on the reactor thread.
|
5
|
+
# Use as a helper if desired
|
6
|
+
#
|
7
|
+
module Control
|
8
|
+
class Deferred < EventMachine::Connection
|
9
|
+
def initialize(*args)
|
10
|
+
super
|
11
|
+
|
12
|
+
@selected = nil
|
13
|
+
@receive_queue = Queue.new
|
14
|
+
@command_lock = Mutex.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def post_init
|
18
|
+
return unless self.respond_to?(:initiate_session)
|
19
|
+
begin
|
20
|
+
self.initiate_session
|
21
|
+
rescue => e
|
22
|
+
if !@system.nil?
|
23
|
+
@system.logger.error "-- in defferred.rb, post_init : bad user code in #{self.class}.initiate_session --"
|
24
|
+
@system.logger.error e.message
|
25
|
+
@system.logger.error e.backtrace
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def connection_completed
|
31
|
+
if self.respond_to?(:connected)
|
32
|
+
EM.defer do
|
33
|
+
begin
|
34
|
+
self.connected
|
35
|
+
rescue => e
|
36
|
+
if !@system.nil?
|
37
|
+
@system.logger.error "-- in defferred.rb, connection_completed : bad user code in #{self.class}.connected --"
|
38
|
+
@system.logger.error e.message
|
39
|
+
@system.logger.error e.backtrace
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def unbind
|
47
|
+
@selected.disconnected(self) unless @selected.nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
def receive_data(data)
|
51
|
+
@receive_queue.push(data)
|
52
|
+
EM.defer do
|
53
|
+
begin
|
54
|
+
@command_lock.synchronize {
|
55
|
+
self.received
|
56
|
+
}
|
57
|
+
rescue => e
|
58
|
+
if !@system.nil?
|
59
|
+
@system.logger.error "-- in defferred.rb, receive_data : bad user code in #{self.class}.received --"
|
60
|
+
@system.logger.error e.message
|
61
|
+
@system.logger.error e.backtrace
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
#taken from the dorkbuster gem
|
2
|
+
|
3
|
+
module ANSI
|
4
|
+
Reset = "0"
|
5
|
+
Bright = "1"
|
6
|
+
|
7
|
+
Black = "30"
|
8
|
+
Red = "31"
|
9
|
+
Green = "32"
|
10
|
+
Yellow = "33"
|
11
|
+
Blue = "34"
|
12
|
+
Magenta = "35"
|
13
|
+
Cyan = "36"
|
14
|
+
White = "37"
|
15
|
+
|
16
|
+
BGBlack = "40"
|
17
|
+
BGRed = "41"
|
18
|
+
BGGreen = "42"
|
19
|
+
BGYellow = "43"
|
20
|
+
BGBlue = "44"
|
21
|
+
BGMagenta = "45"
|
22
|
+
BGCyan = "46"
|
23
|
+
BGWhite = "47"
|
24
|
+
|
25
|
+
Bright_Magenta = Bright+';'+BGBlack+';'+Magenta # "1;35;40"
|
26
|
+
|
27
|
+
class << self
|
28
|
+
def color(*colors)
|
29
|
+
"\033[#{colors.join(';')}m"
|
30
|
+
end
|
31
|
+
|
32
|
+
def colorize(str, start_color, end_color = Reset)
|
33
|
+
"#{color(start_color)}#{str}#{color(end_color)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def attr_is_fgcolor?(str)
|
37
|
+
str.to_i.between?(30, 37)
|
38
|
+
end
|
39
|
+
|
40
|
+
def attr_is_bgcolor?(str)
|
41
|
+
str.to_i.between?(40, 47)
|
42
|
+
end
|
43
|
+
|
44
|
+
def strip(str)
|
45
|
+
str.gsub(/\e\[[\d;]*[A-Za-z]/, "")
|
46
|
+
end
|
47
|
+
|
48
|
+
def strlen(str)
|
49
|
+
str.strip.length
|
50
|
+
end
|
51
|
+
|
52
|
+
def strclip(str, len)
|
53
|
+
out = ""
|
54
|
+
nout = 0
|
55
|
+
str.scan(/\e\[[\d;]*[A-Za-z]|[^\e]/) do |tok|
|
56
|
+
if tok[0] != ?\e
|
57
|
+
nout += 1
|
58
|
+
break if nout > len
|
59
|
+
end
|
60
|
+
out << tok
|
61
|
+
end
|
62
|
+
out
|
63
|
+
end
|
64
|
+
|
65
|
+
def strbreak(str, len)
|
66
|
+
out = []
|
67
|
+
buf = ""
|
68
|
+
nout = 0
|
69
|
+
str.scan(/\e\[[\d;]*[A-Za-z]|[^\e]/) do |tok|
|
70
|
+
if tok[0] != ?\e
|
71
|
+
nout += 1
|
72
|
+
if nout > len
|
73
|
+
out << buf
|
74
|
+
nout -= len
|
75
|
+
buf = ""
|
76
|
+
end
|
77
|
+
end
|
78
|
+
buf << tok
|
79
|
+
end
|
80
|
+
out << buf unless buf.empty?
|
81
|
+
out
|
82
|
+
end
|
83
|
+
|
84
|
+
def red(str); colorize(str, Red) end
|
85
|
+
def green(str); colorize(str, Green) end
|
86
|
+
def yellow(str); colorize(str, Yellow) end
|
87
|
+
def blue(str); colorize(str, Blue) end
|
88
|
+
def magenta(str); colorize(str, Magenta) end
|
89
|
+
def cyan(str); colorize(str, Cyan) end
|
90
|
+
|
91
|
+
def bright_magenta(str); colorize(str, Bright_Magenta) end
|
92
|
+
|
93
|
+
def set_scroll_fullscreen; "\e[r" end
|
94
|
+
def set_scroll_region(row_start, row_end); "\e[#{row_start};#{row_end}r" end
|
95
|
+
|
96
|
+
def set_cursor_pos(row, col); "\e[#{row};#{col}H" end
|
97
|
+
|
98
|
+
def cursor_left(cnt=1); "\e[#{cnt}D" end
|
99
|
+
def cursor_right(cnt=1); "\e[#{cnt}C" end
|
100
|
+
def cursor_up(cnt=1); "\e[#{cnt}A" end
|
101
|
+
def cursor_down(cnt=1); "\e[#{cnt}B" end
|
102
|
+
|
103
|
+
def save_cursor_pos; "\e[s" end
|
104
|
+
def restore_cursor_pos; "\e[u" end
|
105
|
+
|
106
|
+
def backspace_rubout(cnt=1); ("\b \b" * cnt) end
|
107
|
+
|
108
|
+
def erase_line; "\e[2K" end
|
109
|
+
def erase_eol; "\e[K" end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
if $0 == __FILE__
|
117
|
+
require 'test/unit'
|
118
|
+
|
119
|
+
class TestANSI < Test::Unit::TestCase
|
120
|
+
|
121
|
+
def test_strclip
|
122
|
+
assert_equal( "ab\e[34;56mc", ANSI.strclip("ab\e[34;56mcd", 3) )
|
123
|
+
assert_equal( "ab\e[34;56mc\e[12;34r\e[H", ANSI.strclip("ab\e[34;56mc\e[12;34r\e[Hd", 3) )
|
124
|
+
assert_equal( "ab\e[34;56mc\e[12;34r\e[Hd", ANSI.strclip("ab\e[34;56mc\e[12;34r\e[Hde", 4) )
|
125
|
+
assert_equal( "ab\e[34;56mc\e[12;34r\e[Hde", ANSI.strclip("ab\e[34;56mc\e[12;34r\e[Hde", 5) )
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_strbreak
|
129
|
+
assert_equal( ["ab\e[34;56mc", "d"], ANSI.strbreak("ab\e[34;56mcd", 3) )
|
130
|
+
assert_equal( ["ab\e[34;56m", "c\e[12;34r\e[Hd", "e"], ANSI.strbreak("ab\e[34;56mc\e[12;34r\e[Hde", 2) )
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
|