hello_goodbye 0.1.0
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/.gitignore +24 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +308 -0
- data/Rakefile +10 -0
- data/VERSION +1 -0
- data/hello_goodbye.gemspec +24 -0
- data/hello_goodbye.rb +25 -0
- data/lib/hello_goodbye/console.rb +88 -0
- data/lib/hello_goodbye/consoles/foreman_console.rb +23 -0
- data/lib/hello_goodbye/consoles/manager_console.rb +35 -0
- data/lib/hello_goodbye/foreman.rb +117 -0
- data/lib/hello_goodbye/foremen_manager.rb +103 -0
- data/lib/hello_goodbye/json/request.rb +20 -0
- data/lib/hello_goodbye/json/response.rb +36 -0
- data/lib/hello_goodbye/version.rb +3 -0
- data/lib/hello_goodbye.rb +25 -0
- data/spec/hello_goodbye/console_spec.rb +67 -0
- data/spec/hello_goodbye/consoles/foreman_console_spec.rb +35 -0
- data/spec/hello_goodbye/consoles/manager_console_spec.rb +47 -0
- data/spec/hello_goodbye/foremen_manager_spec.rb +84 -0
- data/spec/hello_goodbye/foremen_spec.rb +64 -0
- data/spec/hello_goodbye/json/request_spec.rb +28 -0
- data/spec/hello_goodbye/json/response_spec.rb +35 -0
- data/spec/hello_goodbye_spec.rb +21 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/test_console.rb +23 -0
- data/spec/test_foreman.rb +15 -0
- metadata +179 -0
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
|
4
|
+
# rdoc generated
|
5
|
+
rdoc
|
6
|
+
|
7
|
+
# yard generated
|
8
|
+
doc
|
9
|
+
.yardoc
|
10
|
+
|
11
|
+
# bundler
|
12
|
+
.bundle
|
13
|
+
|
14
|
+
# jeweler generated
|
15
|
+
pkg
|
16
|
+
|
17
|
+
# For vim:
|
18
|
+
*.swp
|
19
|
+
|
20
|
+
# built gems
|
21
|
+
*.gem
|
22
|
+
|
23
|
+
vendor/bundle
|
24
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Joshua Murray
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,308 @@
|
|
1
|
+
HelloGoodbye
|
2
|
+
===============
|
3
|
+
A daemon manager with a TCP interface built on top of EventMachine.
|
4
|
+
|
5
|
+
Installation
|
6
|
+
------------------
|
7
|
+
gem build hello_goodbye.gemspec
|
8
|
+
gem install hello_goodbye-0.1.0.gem
|
9
|
+
|
10
|
+
The Foremen Manager
|
11
|
+
-------------------
|
12
|
+
The foremen manager is the mother-ship for all your custom foremen that will spawn workers (or do whatever you wish).
|
13
|
+
A foreman itself, the manager creates a TCP console of its own so foremen can be reviewed and managed from the manager
|
14
|
+
itself.
|
15
|
+
|
16
|
+
manager = HelloGoodbye::ForemenManager.new(:port => 8080, :server => "127.0.0.1")
|
17
|
+
# or...
|
18
|
+
manager = HelloGoodbye.manager(8080, "127.0.0.1")
|
19
|
+
|
20
|
+
To register foremen (before "start!"ing the manager), execute code like the following:
|
21
|
+
|
22
|
+
manager.register_foreman( :port => 8081, :class => HelloGoodbye::TestForeman )
|
23
|
+
|
24
|
+
If you want to capture errors (and you should -- if the manager goes down, everything is liable to go down with it),
|
25
|
+
pass a block to the on_error method as follows:
|
26
|
+
|
27
|
+
manager.on_error do |e|
|
28
|
+
# Do stuff.
|
29
|
+
end
|
30
|
+
|
31
|
+
When you're all set up, fire away with the start! method:
|
32
|
+
|
33
|
+
manager.start!
|
34
|
+
|
35
|
+
This will block. After this is executed, all your manager and all your foremen should be listening in on their respective ports
|
36
|
+
for your command.
|
37
|
+
|
38
|
+
Consoles
|
39
|
+
-------------
|
40
|
+
After making a TCP connection to one of the consoles, communication should occur to and from the console using one of the following standard JSON packages.
|
41
|
+
|
42
|
+
Commands issued to a service should be formatted as follows:
|
43
|
+
|
44
|
+
{
|
45
|
+
"command": "YOUR COMMAND"
|
46
|
+
}
|
47
|
+
|
48
|
+
Responses from the service will be formatted as follows:
|
49
|
+
|
50
|
+
{
|
51
|
+
"success": true,
|
52
|
+
"message": "MESSAGE FROM SERVICE",
|
53
|
+
"results": []
|
54
|
+
}
|
55
|
+
|
56
|
+
Note the following:
|
57
|
+
|
58
|
+
* **success** can be **true** for **false**
|
59
|
+
* **results** will either be an array of data relavent to the command, or will be absent.
|
60
|
+
|
61
|
+
The Manager Console
|
62
|
+
--------------------
|
63
|
+
Once started, your manager will be available for TCP connections, and will respond to the following commands:
|
64
|
+
<table>
|
65
|
+
<tr>
|
66
|
+
<th>Command</th><th>Response Message</th><th>Results</th><th>Action Performed</th>
|
67
|
+
</tr>
|
68
|
+
<tr>
|
69
|
+
<td>
|
70
|
+
hello
|
71
|
+
</td>
|
72
|
+
<td>
|
73
|
+
hello
|
74
|
+
</td>
|
75
|
+
<td>
|
76
|
+
None.
|
77
|
+
</td>
|
78
|
+
<td>
|
79
|
+
Nothing. Just a convenient way to "ping" the service.
|
80
|
+
</td>
|
81
|
+
</tr>
|
82
|
+
<tr>
|
83
|
+
<td>
|
84
|
+
goodbye
|
85
|
+
</td>
|
86
|
+
<td>
|
87
|
+
goodbye
|
88
|
+
</td>
|
89
|
+
<td>
|
90
|
+
None.
|
91
|
+
</td>
|
92
|
+
<td>
|
93
|
+
Closes the connection.
|
94
|
+
</td>
|
95
|
+
</tr>
|
96
|
+
<tr>
|
97
|
+
<td>
|
98
|
+
foremen
|
99
|
+
</td>
|
100
|
+
<td>
|
101
|
+
ok
|
102
|
+
</td>
|
103
|
+
<td>
|
104
|
+
An array of hashes with details about each forman.
|
105
|
+
</td>
|
106
|
+
<td>
|
107
|
+
Nothing.
|
108
|
+
</td>
|
109
|
+
</tr>
|
110
|
+
<tr>
|
111
|
+
<td>
|
112
|
+
start XX
|
113
|
+
</td>
|
114
|
+
<td>
|
115
|
+
"ok" if successful.
|
116
|
+
</td>
|
117
|
+
<td>
|
118
|
+
An array of started foreman ids.
|
119
|
+
</td>
|
120
|
+
<td>
|
121
|
+
The foreman with the name XX is started. If XX is "all", all stopped foremen
|
122
|
+
will be started.
|
123
|
+
|
124
|
+
XX will be "test" if the foreman name is TestForman.
|
125
|
+
Otherwise, if XX is an integer, the ID of the active foreman will be consulted
|
126
|
+
instead of the name.
|
127
|
+
</td>
|
128
|
+
</tr>
|
129
|
+
<tr>
|
130
|
+
<td>
|
131
|
+
stop XX
|
132
|
+
</td>
|
133
|
+
<td>
|
134
|
+
"ok" if successful.
|
135
|
+
</td>
|
136
|
+
<td>
|
137
|
+
An array of stopped foreman ids.
|
138
|
+
</td>
|
139
|
+
<td>
|
140
|
+
The foreman with the name XX is stopped. If XX is "all", all active foremen
|
141
|
+
will be stopped.
|
142
|
+
|
143
|
+
XX will be "test" if the foreman name is TestForman.
|
144
|
+
Otherwise, if XX is an integer, the ID of the active foreman will be consulted
|
145
|
+
instead of the name.
|
146
|
+
</td>
|
147
|
+
</tr>
|
148
|
+
<tr>
|
149
|
+
<td>
|
150
|
+
(Anything else)
|
151
|
+
</td>
|
152
|
+
<td>
|
153
|
+
unknown command
|
154
|
+
</td>
|
155
|
+
<td>
|
156
|
+
None.
|
157
|
+
</td>
|
158
|
+
<td>Nothing.</td>
|
159
|
+
</tr>
|
160
|
+
</table>
|
161
|
+
|
162
|
+
|
163
|
+
|
164
|
+
Custom Foremen
|
165
|
+
-------------------
|
166
|
+
Foremen that you build must inherit from HelloGoodbye::Foreman. Beyond that, you should only have to implement a few instance methods that will be executed when the corresponding console commands are executed during a TCP connection:
|
167
|
+
|
168
|
+
def start
|
169
|
+
# Start listening for events to respond to.
|
170
|
+
end
|
171
|
+
|
172
|
+
def stop
|
173
|
+
# Stop listening for events.
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
Foremen Console
|
178
|
+
-------------------
|
179
|
+
Once started, your foreman will be available for TCP connections, and will respond to the following commands:
|
180
|
+
<table>
|
181
|
+
<tr>
|
182
|
+
<th>Command</th><th>Response Message</th><th>Results</th><th>Action Performed</th>
|
183
|
+
</tr>
|
184
|
+
<tr>
|
185
|
+
<td>
|
186
|
+
hello
|
187
|
+
</td>
|
188
|
+
<td>
|
189
|
+
hello
|
190
|
+
</td>
|
191
|
+
<td>
|
192
|
+
None.
|
193
|
+
</td>
|
194
|
+
<td>
|
195
|
+
Nothing. Just a convenient way to "ping" the service.
|
196
|
+
</td>
|
197
|
+
</tr>
|
198
|
+
<tr>
|
199
|
+
<td>
|
200
|
+
goodbye
|
201
|
+
</td>
|
202
|
+
<td>
|
203
|
+
goodbye
|
204
|
+
</td>
|
205
|
+
<td>
|
206
|
+
None.
|
207
|
+
</td>
|
208
|
+
<td>
|
209
|
+
Closes the connection.
|
210
|
+
</td>
|
211
|
+
</tr>
|
212
|
+
<tr>
|
213
|
+
<td>
|
214
|
+
start
|
215
|
+
</td>
|
216
|
+
<td>
|
217
|
+
ok
|
218
|
+
</td>
|
219
|
+
<td>
|
220
|
+
Nothing.
|
221
|
+
</td>
|
222
|
+
<td>
|
223
|
+
Executes the foreman's static "start" method. Typically, this would execute whatever "daemon" will listen for events and spawn workers.
|
224
|
+
</td>
|
225
|
+
</tr>
|
226
|
+
<tr>
|
227
|
+
<td>
|
228
|
+
stop
|
229
|
+
</td>
|
230
|
+
<td>
|
231
|
+
ok
|
232
|
+
</td>
|
233
|
+
<td>
|
234
|
+
Nada
|
235
|
+
</td>
|
236
|
+
<td>
|
237
|
+
Executes the forman's "stop" method, stopping the foreman's daemon.
|
238
|
+
</td>
|
239
|
+
</tr>
|
240
|
+
<tr>
|
241
|
+
<td>
|
242
|
+
status
|
243
|
+
</td>
|
244
|
+
<td>
|
245
|
+
"running" or "stopped"
|
246
|
+
</td>
|
247
|
+
<td>
|
248
|
+
Nada
|
249
|
+
</td>
|
250
|
+
<td>
|
251
|
+
Nothing.
|
252
|
+
</td>
|
253
|
+
</tr>
|
254
|
+
<tr>
|
255
|
+
<td>
|
256
|
+
(Anything else not implemented by your custom foreman)
|
257
|
+
</td>
|
258
|
+
<td>
|
259
|
+
unknown command
|
260
|
+
</td>
|
261
|
+
<td>
|
262
|
+
None.
|
263
|
+
</td>
|
264
|
+
<td>
|
265
|
+
Nothing.
|
266
|
+
</td>
|
267
|
+
</tr>
|
268
|
+
</table>
|
269
|
+
|
270
|
+
Custom Consoles
|
271
|
+
------------------
|
272
|
+
Although there is a generic
|
273
|
+
```
|
274
|
+
HelloGoodbye::ForemanConsole
|
275
|
+
```
|
276
|
+
that will hopefully suit the needs for most usecases, custom consoles can easily be created and attached to custom foremen as needed.
|
277
|
+
|
278
|
+
First, to implement your custom console, inherit from
|
279
|
+
```
|
280
|
+
HelloGoodbye::ForemanConsole
|
281
|
+
```
|
282
|
+
and override
|
283
|
+
```
|
284
|
+
receive_command
|
285
|
+
```
|
286
|
+
.
|
287
|
+
|
288
|
+
To make your own class extensible, and to make use of the built in console commands implemented in the
|
289
|
+
```
|
290
|
+
HelloGoodbye::ForemanConsole
|
291
|
+
```
|
292
|
+
class, you'll want to start with the template below when overriding this method:
|
293
|
+
|
294
|
+
def receive_command(command)
|
295
|
+
# Process additional commands here.
|
296
|
+
# Return if processes successfully
|
297
|
+
super # Process the default commands. If no match, a failure response will be returned.
|
298
|
+
end
|
299
|
+
|
300
|
+
The last little catch is this: you must let your custom forman class know which console to use. To do this, in your Foreman class, assuming your console class is HelloGoodbye::TestConsole (yes, your console **must** be in the HelloGoodbye module ):
|
301
|
+
|
302
|
+
set_console_type :test # i.e. ":test" for TestConsole
|
303
|
+
|
304
|
+
Thus, the rules are as follow:
|
305
|
+
|
306
|
+
* Your console's class name must be prefixed with "Console".
|
307
|
+
* When setting this type with the class method, you must pass in a symbol matching the de-classified class name, minus the "Console" prefix.
|
308
|
+
|
data/Rakefile
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/hello_goodbye/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Joshua Murray"]
|
6
|
+
gem.email = ["joshua.murray@gmail.com"]
|
7
|
+
gem.description = %q{A daemon manager with a TCP interface built on top of EventMachine.}
|
8
|
+
gem.summary = %q{A daemon manager with a TCP interface built on top of EventMachine.}
|
9
|
+
gem.homepage = "https://github.com/joshcom/hello_goodbye"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "hello_goodbye"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = HelloGoodbye::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency "eventmachine", "0.12.10"
|
19
|
+
gem.add_dependency "json", "1.5.3"
|
20
|
+
gem.add_development_dependency "bundler"
|
21
|
+
gem.add_development_dependency "rake"
|
22
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
23
|
+
gem.add_development_dependency "rspec", "2.6.0"
|
24
|
+
end
|
data/hello_goodbye.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require File.expand_path('../hello_goodbye/foremen_manager',__FILE__)
|
6
|
+
|
7
|
+
module HelloGoodbye
|
8
|
+
|
9
|
+
# Resets the current foremen manager, so that the next time
|
10
|
+
# self.manager is called, a new ForemenManager instance will be
|
11
|
+
# created.
|
12
|
+
def self.reset!
|
13
|
+
@manager = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
# Create a new manager or use the existing manager. If an existing manager exists,
|
17
|
+
# port and server will be ignored.
|
18
|
+
# Parameters:
|
19
|
+
# * port: The port the manager should connect to.
|
20
|
+
# * server: The server the service will run from.
|
21
|
+
def self.manager(port=ForemenManager.default_manager_port,server=Foreman.default_server)
|
22
|
+
@manager ||= ForemenManager.new(:port => port, :server => server)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module HelloGoodbye
|
2
|
+
|
3
|
+
# Commands shared by all consoles:
|
4
|
+
# * 'hello' => Used to ping the server.
|
5
|
+
# Responds with 'hello'.
|
6
|
+
# * 'goodbye' => Used to close a connection.
|
7
|
+
# Responds with 'goodbye'.
|
8
|
+
class Console < EventMachine::Connection
|
9
|
+
|
10
|
+
require File.expand_path('../../hello_goodbye/consoles/foreman_console',__FILE__)
|
11
|
+
require File.expand_path('../../hello_goodbye/consoles/manager_console',__FILE__)
|
12
|
+
require File.expand_path('../../hello_goodbye/json/request',__FILE__)
|
13
|
+
require File.expand_path('../../hello_goodbye/json/response',__FILE__)
|
14
|
+
|
15
|
+
# :foreman
|
16
|
+
# A reference to the Foreman object that instantiated the console, so that
|
17
|
+
# the console can serve as an interface to this object.
|
18
|
+
attr_accessor :foreman
|
19
|
+
|
20
|
+
# Returns a standard console of a given type. I'm aware this logic is dumb.
|
21
|
+
# Parameters:
|
22
|
+
# * type
|
23
|
+
# ** :manager => ManagerConsole
|
24
|
+
def self.get(type)
|
25
|
+
case type
|
26
|
+
when :manager
|
27
|
+
ManagerConsole
|
28
|
+
when :foreman
|
29
|
+
ForemanConsole
|
30
|
+
else
|
31
|
+
if (obj = HelloGoodbye.const_get("#{type}_console".split('_').collect(&:capitalize).join))
|
32
|
+
obj
|
33
|
+
else
|
34
|
+
raise ArgumentError, "What type of console is #{type}?"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def foreman=(f)
|
40
|
+
f.console = self
|
41
|
+
@foreman = f
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns:
|
45
|
+
# true if data was handled, false if not.
|
46
|
+
def receive_command(command)
|
47
|
+
case command
|
48
|
+
when "hello"
|
49
|
+
send_response :success => true,
|
50
|
+
:message => "hello"
|
51
|
+
return true
|
52
|
+
when "goodbye"
|
53
|
+
send_response :success => true,
|
54
|
+
:message => "goodbye"
|
55
|
+
close_connection
|
56
|
+
return true
|
57
|
+
else
|
58
|
+
send_response :success => false,
|
59
|
+
:message => "unknown command"
|
60
|
+
end
|
61
|
+
false
|
62
|
+
end
|
63
|
+
|
64
|
+
# Parameters:
|
65
|
+
# hash
|
66
|
+
# * success => true or false
|
67
|
+
# * message => "Your message"
|
68
|
+
# * results => []
|
69
|
+
def send_response(hash)
|
70
|
+
send_data Response.new(hash).to_json
|
71
|
+
end
|
72
|
+
|
73
|
+
def receive_data(data)
|
74
|
+
data = data.strip
|
75
|
+
return false if data == ""
|
76
|
+
|
77
|
+
begin
|
78
|
+
json = Request.new(data)
|
79
|
+
rescue JSON::ParserError => e
|
80
|
+
send_response :success => false,
|
81
|
+
:message => "invalid json"
|
82
|
+
return false
|
83
|
+
end
|
84
|
+
|
85
|
+
receive_command(json.command)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module HelloGoodbye
|
2
|
+
class ForemanConsole < Console
|
3
|
+
def receive_command(command)
|
4
|
+
case command
|
5
|
+
when "start"
|
6
|
+
self.foreman.employ
|
7
|
+
send_response :success => true,
|
8
|
+
:message => "ok"
|
9
|
+
return true
|
10
|
+
when "stop"
|
11
|
+
self.foreman.unemploy
|
12
|
+
send_response :success => true,
|
13
|
+
:message => "ok"
|
14
|
+
return true
|
15
|
+
when "status"
|
16
|
+
send_response :success => true,
|
17
|
+
:message => self.foreman.status.to_s
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module HelloGoodbye
|
2
|
+
class ManagerConsole < Console
|
3
|
+
def receive_command(command)
|
4
|
+
case command
|
5
|
+
when /^start /
|
6
|
+
id = command.gsub(/^start /, "")
|
7
|
+
if (started_foremen = self.foreman.trigger_foreman(:start, id))
|
8
|
+
send_response :success => true,
|
9
|
+
:message => "ok",
|
10
|
+
:results => started_foremen
|
11
|
+
else
|
12
|
+
send_response :success => false,
|
13
|
+
:message => "no match for foreman '#{id}'"
|
14
|
+
end
|
15
|
+
return true
|
16
|
+
when /^stop /
|
17
|
+
id = command.gsub(/^stop /, "")
|
18
|
+
if (stopped_foremen = self.foreman.trigger_foreman(:stop,id))
|
19
|
+
send_response :success => true,
|
20
|
+
:message => "ok",
|
21
|
+
:results => stopped_foremen
|
22
|
+
else
|
23
|
+
send_response :success => false,
|
24
|
+
:message => "no match for foreman '#{id}'"
|
25
|
+
end
|
26
|
+
return true
|
27
|
+
when "foremen"
|
28
|
+
send_response :success => true, :message => "ok",
|
29
|
+
:results => self.foreman.report
|
30
|
+
return true
|
31
|
+
end
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module HelloGoodbye
|
2
|
+
class Foreman
|
3
|
+
|
4
|
+
attr_accessor :server, :port, :console, :my_id, :server_id
|
5
|
+
attr_reader :foreman_started
|
6
|
+
|
7
|
+
DEFAULT_SERVER = "127.0.0.1"
|
8
|
+
|
9
|
+
# Overrides the default ForemanConsole console type
|
10
|
+
# to fire up when #start! is called.
|
11
|
+
def self.set_console_type(console_sym)
|
12
|
+
@console_type = console_sym
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the current console type for this class.
|
16
|
+
def self.console_type
|
17
|
+
@console_type ||= :foreman
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.default_server
|
21
|
+
DEFAULT_SERVER
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parameters:
|
25
|
+
# options:
|
26
|
+
# * server =>
|
27
|
+
# * port => The port to run the server on
|
28
|
+
def initialize(options={})
|
29
|
+
self.server = options[:server]
|
30
|
+
self.port = options[:port]
|
31
|
+
@foreman_started = false
|
32
|
+
end
|
33
|
+
|
34
|
+
# Starts the foreman's worker spawning action.
|
35
|
+
def start
|
36
|
+
raise ArgumentError, "Foreman.start must be implemented by child class."
|
37
|
+
end
|
38
|
+
|
39
|
+
# Stops the foreman's worker spawning action.
|
40
|
+
def stop
|
41
|
+
raise ArgumentError, "Foreman.start must be implemented by child class."
|
42
|
+
end
|
43
|
+
|
44
|
+
# Starts the console for the foreman. Subclasses should implement this method,
|
45
|
+
# passing a block to super to start up any tasks (AMQB subscriber, etc)
|
46
|
+
# that may need to be done.
|
47
|
+
def start!
|
48
|
+
raise RuntimeError, "Foreman already started!" if @foreman_started == true
|
49
|
+
start_with_reactor do
|
50
|
+
self.start_console
|
51
|
+
yield if block_given?
|
52
|
+
end
|
53
|
+
@foreman_started = true
|
54
|
+
end
|
55
|
+
|
56
|
+
# Detects the name to report this foreman class as.
|
57
|
+
# For example, will be "test" for "HelloGoodbye::TestForeman".
|
58
|
+
def my_name
|
59
|
+
begin
|
60
|
+
self.class.name.match(/^HelloGoodbye::(.*)Foreman$/)[1].downcase
|
61
|
+
rescue
|
62
|
+
self.class.name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Reports the current status of the foreman.
|
67
|
+
# Returns:
|
68
|
+
# * :stopped if the foreman is not currently employing workers.
|
69
|
+
# * :running if the foreman is active
|
70
|
+
def status
|
71
|
+
@status || :stopped
|
72
|
+
end
|
73
|
+
|
74
|
+
# true if the foreman is currently employing workers
|
75
|
+
def running?
|
76
|
+
self.status == :running
|
77
|
+
end
|
78
|
+
|
79
|
+
# Sets the foreman status to either :running or :stopped
|
80
|
+
def status=(status)
|
81
|
+
@status = status.to_sym
|
82
|
+
end
|
83
|
+
|
84
|
+
# Sets the foreman status to :running and calls self.start
|
85
|
+
def employ
|
86
|
+
self.start
|
87
|
+
self.status = :running
|
88
|
+
end
|
89
|
+
|
90
|
+
# Sets the foreman status to :stopped and calls self.stop
|
91
|
+
def unemploy
|
92
|
+
self.stop
|
93
|
+
self.status = :stopped
|
94
|
+
end
|
95
|
+
|
96
|
+
def server
|
97
|
+
@server || DEFAULT_SERVER
|
98
|
+
end
|
99
|
+
|
100
|
+
def start_console
|
101
|
+
me = self
|
102
|
+
self.server_id = EM::start_server(self.server, self.port, Console.get(self.class.console_type)) do |c|
|
103
|
+
c.foreman = me
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def start_with_reactor(&block)
|
108
|
+
if EM.reactor_running?
|
109
|
+
block.call
|
110
|
+
else
|
111
|
+
EM.run {
|
112
|
+
block.call
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|