ngauthier-active-listener 0.3.0 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION.yml +2 -2
- data/lib/active-listener.rb +107 -11
- data/test/active_listener-events.yml +5 -0
- data/test/active_listener_test.rb +58 -4
- metadata +3 -3
data/VERSION.yml
CHANGED
data/lib/active-listener.rb
CHANGED
@@ -1,9 +1,23 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'yaml'
|
3
3
|
|
4
|
+
# =ActiveListener
|
5
|
+
# Set up an activelistener config file in your config directory describing the
|
6
|
+
# tasks #ActiveListener should execute. Then, in an initializer, run
|
7
|
+
# #ActiveListener.autostart
|
4
8
|
class ActiveListener
|
9
|
+
# All the #Events that an #ActiveListener is firing
|
5
10
|
attr_reader :events
|
6
11
|
|
12
|
+
# Run #autostart in an initializer to run #ActiveListener when your
|
13
|
+
# Rails application initializes.
|
14
|
+
#
|
15
|
+
# ActiveListener.autostart(
|
16
|
+
# :config => File.join(RAILS_ROOT, 'config', 'active-listener.yml'),
|
17
|
+
# :pid_file => File.join(RAILS_ROOT, 'log', 'active-listener-'+RAILS_ENV+'.pid'),
|
18
|
+
# :log_file => File.join(RAILS_ROOT, 'log', 'active-listener-'+RAILS_ENV+'.log'),
|
19
|
+
# :rake_root => RAILS_ROOT
|
20
|
+
# )
|
7
21
|
def self.autostart(opts = {})
|
8
22
|
begin
|
9
23
|
config_file = File.expand_path(opts[:config])
|
@@ -22,30 +36,47 @@ class ActiveListener
|
|
22
36
|
"--",
|
23
37
|
"#{config_file}",
|
24
38
|
"#{log_file}",
|
25
|
-
"#{rake_root}"
|
39
|
+
"#{rake_root}",
|
26
40
|
].join(" ")
|
27
41
|
`#{command}`
|
28
42
|
end
|
29
43
|
|
44
|
+
# Stop an #ActiveListener by specifying a pid file
|
45
|
+
#
|
46
|
+
# ActiveListener.stop(:pid_file => File.join(RAILS_ROOT, 'log', 'active-listener.pid'))
|
30
47
|
def self.stop(opts = {})
|
31
48
|
pid_file = opts[:pid_file]
|
32
49
|
`start-stop-daemon --stop --oknodo --pidfile #{File.expand_path(pid_file)}`
|
33
50
|
end
|
34
51
|
|
52
|
+
# Create an #ActiveListener in the foreground. This is useful for a non-rails project.
|
53
|
+
#
|
54
|
+
# ActiveListener.new(
|
55
|
+
# :log_file => File.join('log', 'active-listener.log'),
|
56
|
+
# :rake_root => '.'
|
57
|
+
# )
|
35
58
|
def initialize(opts = {})
|
36
59
|
self.events = []
|
37
60
|
self.log_file = opts[:log_file]
|
38
61
|
self.rake_root = opts[:rake_root]
|
39
62
|
clear_log
|
40
63
|
log("ActiveListener Initialized")
|
41
|
-
|
64
|
+
load_config(opts[:config])
|
42
65
|
end
|
43
66
|
|
67
|
+
# Add an event to event listener.
|
68
|
+
#
|
69
|
+
# @al.add_event(Event.new(:task => 'my_task', :period => '10'))
|
44
70
|
def add_event(evt)
|
45
71
|
self.events.push(evt)
|
46
72
|
log("Added Event #{evt.inspect}")
|
47
73
|
end
|
48
74
|
|
75
|
+
# Fire any events that have passed their period
|
76
|
+
#
|
77
|
+
# @al.fire_events
|
78
|
+
#
|
79
|
+
# This will only fire events that have not been run within their period time of their last run
|
49
80
|
def fire_events
|
50
81
|
self.events.select{|e| e.time_to_fire < 0}.each do |evt|
|
51
82
|
log("Firing event: #{evt.inspect}")
|
@@ -54,6 +85,10 @@ class ActiveListener
|
|
54
85
|
self.events.sort{|x,y| x.time_to_fire <=> y.time_to_fire}
|
55
86
|
end
|
56
87
|
|
88
|
+
# Returns the time in seconds until the next event needs to be fired. Useful for sleeping
|
89
|
+
#
|
90
|
+
# sleep(@al.time_to_next_event)
|
91
|
+
# @al.fire_events
|
57
92
|
def time_to_next_event
|
58
93
|
if self.events.first
|
59
94
|
sleep_time = self.events.first.time_to_fire+0.01
|
@@ -63,22 +98,37 @@ class ActiveListener
|
|
63
98
|
return sleep_time
|
64
99
|
end
|
65
100
|
|
66
|
-
|
67
|
-
|
68
|
-
|
101
|
+
# Not functional yet.
|
102
|
+
def self.trigger(port, event)
|
103
|
+
|
69
104
|
end
|
70
105
|
|
106
|
+
# An individual #ActiveListener #Event
|
71
107
|
class Event
|
108
|
+
# Create a new #Event
|
109
|
+
#
|
110
|
+
# Event.new(
|
111
|
+
# :task => 'my:rake:task',
|
112
|
+
# :period => 50
|
113
|
+
# )
|
72
114
|
def initialize(opts = {})
|
73
115
|
self.task = opts[:task] || opts["task"]
|
74
116
|
self.period = opts[:period] || opts["period"]
|
117
|
+
self.trigger = opts[:trigger] || opts["trigger"]
|
75
118
|
self.last_fire = Time.now.to_f
|
76
119
|
end
|
77
120
|
|
121
|
+
# The amount of time until this event will need to be fired
|
78
122
|
def time_to_fire
|
79
|
-
|
123
|
+
if period
|
124
|
+
return last_fire + period - Time.now.to_f
|
125
|
+
else
|
126
|
+
# oh does! forever!
|
127
|
+
return 1.0/0.0
|
128
|
+
end
|
80
129
|
end
|
81
130
|
|
131
|
+
# Fire the event. I.e. run the rake task
|
82
132
|
def fire(opts = {})
|
83
133
|
self.last_fire = Time.now.to_f
|
84
134
|
Dir.chdir(opts[:rake_root]) if opts[:rake_root]
|
@@ -89,18 +139,43 @@ class ActiveListener
|
|
89
139
|
end
|
90
140
|
end
|
91
141
|
|
142
|
+
# Manual firing trigger (not implemented)
|
143
|
+
attr_reader :trigger
|
144
|
+
# The amount of time in seconds between firing this task
|
145
|
+
attr_reader :period
|
146
|
+
# The last time this event was fired
|
147
|
+
attr_reader :last_fire
|
148
|
+
# A string representation of a rake task. "my:task"
|
149
|
+
attr_reader :task
|
150
|
+
|
92
151
|
private
|
93
152
|
|
94
|
-
|
153
|
+
# Set the rake task
|
154
|
+
attr_writer :task
|
155
|
+
# Set the period
|
156
|
+
attr_writer :period
|
157
|
+
# Set the trigger
|
158
|
+
attr_writer :trigger
|
159
|
+
# Set last_fire time
|
160
|
+
attr_writer :last_fire
|
95
161
|
|
96
162
|
end
|
97
163
|
|
98
164
|
private
|
99
165
|
|
166
|
+
# Set the events this #ActiveListener has
|
100
167
|
attr_writer :events
|
101
|
-
|
102
|
-
|
103
|
-
|
168
|
+
# Log file path
|
169
|
+
attr_accessor :log_file
|
170
|
+
# Directory to run rake tasks from
|
171
|
+
attr_accessor :rake_root
|
172
|
+
# Port for triggers (not implemented)
|
173
|
+
attr_accessor :port
|
174
|
+
|
175
|
+
# Parse a config file to load up events.
|
176
|
+
#
|
177
|
+
# @al.load_config('active-listener.yml')
|
178
|
+
def load_config(config_file)
|
104
179
|
return if config_file.nil?
|
105
180
|
unless File.exists?(config_file)
|
106
181
|
log("Config file not found at #{config_file}")
|
@@ -112,13 +187,21 @@ class ActiveListener
|
|
112
187
|
yml["tasks"].each do |task|
|
113
188
|
self.add_event(Event.new(task))
|
114
189
|
end
|
190
|
+
port = yml["port"]
|
191
|
+
# puts "The port: #{port}"
|
192
|
+
if port
|
193
|
+
self.port = port
|
194
|
+
spawn_listener_thread
|
195
|
+
end
|
115
196
|
end
|
116
197
|
|
198
|
+
# Delete the log file
|
117
199
|
def clear_log
|
118
200
|
return unless log_file
|
119
201
|
FileUtils.rm_f log_file
|
120
202
|
end
|
121
|
-
|
203
|
+
|
204
|
+
# Log text to the log file
|
122
205
|
def log(text)
|
123
206
|
return unless log_file
|
124
207
|
f = File.new(log_file, 'a')
|
@@ -127,4 +210,17 @@ class ActiveListener
|
|
127
210
|
f.close
|
128
211
|
end
|
129
212
|
|
213
|
+
# Trigger an event (not implemented)
|
214
|
+
def trigger(trigger)
|
215
|
+
self.events.select{|e| e.trigger == trigger}.each do |evt|
|
216
|
+
log("Event triggered: #{evt.inspect}")
|
217
|
+
log(evt.fire(:rake_root => rake_root))
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Listen on a port for triggers (not implemented)
|
222
|
+
def spawn_listener_thread
|
223
|
+
# puts "Hey a port! #{port}"
|
224
|
+
end
|
225
|
+
|
130
226
|
end
|
@@ -23,7 +23,7 @@ class ActiveListenerTest < Test::Unit::TestCase
|
|
23
23
|
end
|
24
24
|
|
25
25
|
should "sleep when it has no events" do
|
26
|
-
@al.
|
26
|
+
sleep(@al.time_to_next_event)
|
27
27
|
end
|
28
28
|
|
29
29
|
context "with a file timer" do
|
@@ -44,7 +44,7 @@ class ActiveListenerTest < Test::Unit::TestCase
|
|
44
44
|
|
45
45
|
should "touch a file" do
|
46
46
|
assert !File.exists?(@sample_file)
|
47
|
-
@al.
|
47
|
+
sleep(@al.time_to_next_event)
|
48
48
|
@al.fire_events
|
49
49
|
assert File.exists?(@sample_file)
|
50
50
|
end
|
@@ -59,7 +59,7 @@ class ActiveListenerTest < Test::Unit::TestCase
|
|
59
59
|
FileUtils.rm_f(@sample_file)
|
60
60
|
@al.fire_events
|
61
61
|
assert !File.exists?(@sample_file)
|
62
|
-
@al.
|
62
|
+
sleep(@al.time_to_next_event)
|
63
63
|
assert @al.events[0].time_to_fire < 0
|
64
64
|
assert !File.exists?(@sample_file)
|
65
65
|
@al.fire_events
|
@@ -81,7 +81,7 @@ class ActiveListenerTest < Test::Unit::TestCase
|
|
81
81
|
@al = ActiveListener.new(:config => @config_path)
|
82
82
|
assert @al.events.size > 0
|
83
83
|
assert !File.exists?(@sample_file)
|
84
|
-
@al.
|
84
|
+
sleep(@al.time_to_next_event)
|
85
85
|
@al.fire_events
|
86
86
|
assert File.exists?(@sample_file)
|
87
87
|
end
|
@@ -160,6 +160,60 @@ class ActiveListenerTest < Test::Unit::TestCase
|
|
160
160
|
end
|
161
161
|
end
|
162
162
|
|
163
|
+
context "An event-based listener" do
|
164
|
+
|
165
|
+
setup do
|
166
|
+
@al = ActiveListener.new({})
|
167
|
+
@al.add_event(ActiveListener::Event.new(
|
168
|
+
:task => 'test:touch_file',
|
169
|
+
:trigger => "MY_TRIGGER"
|
170
|
+
))
|
171
|
+
@sample_file = File.join(File.dirname(__FILE__),'sample.txt')
|
172
|
+
FileUtils.rm_f @sample_file
|
173
|
+
end
|
174
|
+
|
175
|
+
teardown do
|
176
|
+
FileUtils.rm_f @sample_file
|
177
|
+
end
|
178
|
+
|
179
|
+
should "not fire any events at the beginning" do
|
180
|
+
assert !File.exists?(@sample_file)
|
181
|
+
assert @al.time_to_next_event.infinite?
|
182
|
+
@al.fire_events
|
183
|
+
assert !File.exists?(@sample_file)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "An auto-started event based listener" do
|
188
|
+
setup do
|
189
|
+
ActiveListener.stop(
|
190
|
+
:pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid')
|
191
|
+
)
|
192
|
+
sleep(0.5)
|
193
|
+
ActiveListener.autostart(
|
194
|
+
:config => File.join(File.dirname(__FILE__), 'active_listener-events.yml'),
|
195
|
+
:pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid'),
|
196
|
+
:log_file => File.join(File.dirname(__FILE__), 'active_listener.log'),
|
197
|
+
:rake_root => File.join(File.dirname(__FILE__), '..')
|
198
|
+
)
|
199
|
+
@sample_file = File.join(File.dirname(__FILE__),'sample.txt')
|
200
|
+
end
|
201
|
+
|
202
|
+
teardown do
|
203
|
+
ActiveListener.stop(
|
204
|
+
:pid_file => File.join(File.dirname(__FILE__), 'active_listener.pid')
|
205
|
+
)
|
206
|
+
sleep(1)
|
207
|
+
FileUtils.rm_f(File.join(File.dirname(__FILE__),'sample.txt'))
|
208
|
+
end
|
209
|
+
|
210
|
+
should "be able to be triggered" do
|
211
|
+
#assert !File.exists?(@sample_file)
|
212
|
+
#ActiveListener.trigger(20150,"MY_TRIGGER")
|
213
|
+
#assert File.exists?(@sample_file)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
163
217
|
private
|
164
218
|
|
165
219
|
def pid_running(pid)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ngauthier-active-listener
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Gauthier
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-02-
|
12
|
+
date: 2009-02-12 00:00:00 -08:00
|
13
13
|
default_executable: active-listener
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -23,12 +23,12 @@ extra_rdoc_files: []
|
|
23
23
|
|
24
24
|
files:
|
25
25
|
- VERSION.yml
|
26
|
-
- README.html
|
27
26
|
- README.markdown
|
28
27
|
- bin/active-listener
|
29
28
|
- lib/activelistener
|
30
29
|
- lib/active-listener.rb
|
31
30
|
- test/test_helper.rb
|
31
|
+
- test/active_listener-events.yml
|
32
32
|
- test/active_listener.log
|
33
33
|
- test/active_listener.pid
|
34
34
|
- test/active_listener.yml
|