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.
Files changed (77) hide show
  1. data/LGPL3-LICENSE +165 -0
  2. data/README.textile +48 -0
  3. data/Rakefile +40 -0
  4. data/app/models/control_system.rb +20 -0
  5. data/app/models/controller_device.rb +21 -0
  6. data/app/models/controller_http_service.rb +17 -0
  7. data/app/models/controller_logic.rb +5 -0
  8. data/app/models/controller_zone.rb +10 -0
  9. data/app/models/dependency.rb +20 -0
  10. data/app/models/server.rb +12 -0
  11. data/app/models/setting.rb +38 -0
  12. data/app/models/trusted_device.rb +63 -0
  13. data/app/models/user_zone.rb +10 -0
  14. data/app/models/zone.rb +16 -0
  15. data/db/migrate/20111001022500_init.rb +147 -0
  16. data/db/migrate/20111017213801_one_time_key.rb +9 -0
  17. data/db/migrate/20111021071632_encrypt_setting.rb +9 -0
  18. data/db/migrate/20111110075444_servers.rb +15 -0
  19. data/db/migrate/20111114074538_default_port.rb +9 -0
  20. data/db/migrate/20111122073055_makebreak.rb +9 -0
  21. data/db/migrate/20111211062846_create_controller_http_services.rb +18 -0
  22. data/lib/automate-em.rb +155 -0
  23. data/lib/automate-em/constants.rb +6 -0
  24. data/lib/automate-em/core/communicator.rb +318 -0
  25. data/lib/automate-em/core/modules.rb +373 -0
  26. data/lib/automate-em/core/resolver_pool.rb +76 -0
  27. data/lib/automate-em/core/system.rb +356 -0
  28. data/lib/automate-em/device/datagram_server.rb +111 -0
  29. data/lib/automate-em/device/device.rb +140 -0
  30. data/lib/automate-em/device/device_connection.rb +689 -0
  31. data/lib/automate-em/device/tcp_control.rb +210 -0
  32. data/lib/automate-em/engine.rb +36 -0
  33. data/lib/automate-em/interfaces/OLD CODE/deferred.rb +67 -0
  34. data/lib/automate-em/interfaces/OLD CODE/telnet/ansi.rb +137 -0
  35. data/lib/automate-em/interfaces/OLD CODE/telnet/telnet.rb +137 -0
  36. data/lib/automate-em/interfaces/html5.rb +302 -0
  37. data/lib/automate-em/logic/logic.rb +76 -0
  38. data/lib/automate-em/service/http_service.rb +584 -0
  39. data/lib/automate-em/service/service.rb +48 -0
  40. data/lib/automate-em/status.rb +89 -0
  41. data/lib/automate-em/utilities.rb +195 -0
  42. data/lib/automate-em/version.rb +3 -0
  43. data/lib/generators/module/USAGE +8 -0
  44. data/lib/generators/module/module_generator.rb +47 -0
  45. data/lib/tasks/automate-em_tasks.rake +5 -0
  46. data/test/automate-em_test.rb +7 -0
  47. data/test/dummy/README.rdoc +261 -0
  48. data/test/dummy/Rakefile +7 -0
  49. data/test/dummy/app/assets/javascripts/application.js +15 -0
  50. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  51. data/test/dummy/app/controllers/application_controller.rb +3 -0
  52. data/test/dummy/app/helpers/application_helper.rb +2 -0
  53. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  54. data/test/dummy/config.ru +4 -0
  55. data/test/dummy/config/application.rb +56 -0
  56. data/test/dummy/config/boot.rb +10 -0
  57. data/test/dummy/config/database.yml +25 -0
  58. data/test/dummy/config/environment.rb +5 -0
  59. data/test/dummy/config/environments/development.rb +37 -0
  60. data/test/dummy/config/environments/production.rb +67 -0
  61. data/test/dummy/config/environments/test.rb +37 -0
  62. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  63. data/test/dummy/config/initializers/inflections.rb +15 -0
  64. data/test/dummy/config/initializers/mime_types.rb +5 -0
  65. data/test/dummy/config/initializers/secret_token.rb +7 -0
  66. data/test/dummy/config/initializers/session_store.rb +8 -0
  67. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  68. data/test/dummy/config/locales/en.yml +5 -0
  69. data/test/dummy/config/routes.rb +4 -0
  70. data/test/dummy/public/404.html +26 -0
  71. data/test/dummy/public/422.html +26 -0
  72. data/test/dummy/public/500.html +25 -0
  73. data/test/dummy/public/favicon.ico +0 -0
  74. data/test/dummy/script/rails +6 -0
  75. data/test/integration/navigation_test.rb +10 -0
  76. data/test/test_helper.rb +15 -0
  77. 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
+