freeswitcher 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,13 +4,22 @@ require 'fsr/listener/header_and_content_response'
4
4
  describe FSL::HeaderAndContentResponse do
5
5
  HCR = FSL::HeaderAndContentResponse
6
6
 
7
- it "is initializable with 2 hash arguments" do
7
+ before do
8
8
  header = {:foo => "bar", :jumbo => "shrimp"}
9
- content = {:response => "w00t"}
10
- hcr = HCR.new({:headers => header, :content => content})
11
- hcr.headers.should.include? :foo
12
- hcr.content.should.include? :response
9
+ content = {:response => "w00t\n"}
10
+ @hcr = HCR.new({:headers => header, :content => content})
13
11
  end
12
+
13
+ it "is initializable with 2 hash arguments" do
14
+ @hcr.headers.should.include? :foo
15
+ @hcr.content.should.include? :response
16
+ end
17
+
18
+ it "strips newlines from content values" do
19
+ @hcr.content[:response].should == "w00t"
20
+ end
21
+ end
22
+
14
23
  =begin manveru's future specs
15
24
 
16
25
  it "can be created with headers" do
@@ -45,4 +54,3 @@ describe FSL::HeaderAndContentResponse do
45
54
  end
46
55
 
47
56
  =end
48
- end
@@ -1,30 +1,39 @@
1
1
  require 'spec/helper'
2
+ require 'lib/fsr'
2
3
  require "fsr/listener"
3
4
  require "fsr/listener/inbound"
4
- gem "tmm1-em-spec"
5
5
  require "em/spec"
6
6
 
7
7
  # Bare class to use for testing
8
8
  class InboundListener < FSR::Listener::Inbound
9
9
  attr_accessor :test_event
10
10
 
11
+ # Stub error? out
12
+ def error?
13
+ false
14
+ end
15
+
11
16
  def initialize(*args)
12
17
  super(*args)
13
18
  @test_event = nil
14
19
  end
15
20
 
16
- def on_event(event)
21
+ def on_event
17
22
  recvd_event << event
18
23
  end
19
24
 
20
25
  def recvd_event
21
26
  @recvd_event ||= []
22
27
  end
28
+ end
23
29
 
30
+ class InboundListener2 < InboundListener
31
+ def before_session
32
+ add_event(:TEST_EVENT) {recvd_event << event}
33
+ end
24
34
  end
25
35
 
26
36
  describe "Testing FSR::Listener::Inbound" do
27
-
28
37
  it "defines #post_init" do
29
38
  FSR::Listener::Inbound.method_defined?(:post_init).should == true
30
39
  end
@@ -35,13 +44,12 @@ describe "Testing FSR::Listener::Inbound" do
35
44
  FSL::Inbound.del_event_hook(:CHANNEL_CREATE)
36
45
  FSL::Inbound::HOOKS.size.should == 0
37
46
  end
38
-
39
47
  end
40
48
 
41
49
  EM.describe InboundListener do
42
-
43
50
  before do
44
- @listener = InboundListener.new("test", {:auth => 'SecretPassword'})
51
+ @listener = InboundListener.new(1234, {:auth => 'SecretPassword'})
52
+ @listener2 = InboundListener2.new(1234, {:auth => 'SecretPassword'})
45
53
  end
46
54
 
47
55
  should "be able to receive an event and call the on_event callback method" do
@@ -50,8 +58,15 @@ EM.describe InboundListener do
50
58
  done
51
59
  end
52
60
 
61
+ should "be able to add custom event hooks in the pre_session" do
62
+ @listener2.receive_data("Content-Length: 22\n\nEvent-Name: TEST_EVENT\n\n")
63
+ @listener2.recvd_event.first.content[:event_name].should.equal "TEST_EVENT"
64
+ done
65
+ end
66
+
53
67
  should "be able to add custom event hooks" do
54
- FSL::Inbound.add_event_hook(:HANGUP_EVENT) {|event| @listener.test_event = event}
68
+ listener = @listener
69
+ FSL::Inbound.add_event_hook(:HANGUP_EVENT) {listener.test_event = event}
55
70
  @listener.test_event.should.equal nil
56
71
  @listener.receive_data("Content-Length: 24\n\nEvent-Name: HANGUP_EVENT\n\n")
57
72
  @listener.test_event.content[:event_name].should.equal "HANGUP_EVENT"
@@ -62,5 +77,4 @@ EM.describe InboundListener do
62
77
  @listener.auth.should.equal 'SecretPassword'
63
78
  done
64
79
  end
65
-
66
80
  end
@@ -1,12 +1,12 @@
1
1
  require "lib/fsr"
2
2
  require FSR::ROOT/".."/:spec/:helper
3
3
  require FSR::ROOT/:fsr/:listener/:outbound
4
- gem "tmm1-em-spec"
5
4
  require "em/spec"
6
5
 
7
6
  # Bare class to use for testing
8
7
  class MyListener < FSR::Listener::Outbound
9
- attr_accessor :recvd_reply, :state_machine_test
8
+ attr_accessor :recvd_reply, :state_machine_test, :state_machine_test2
9
+ attr_reader :queue
10
10
 
11
11
  def session_initiated
12
12
  end
@@ -31,6 +31,10 @@ class MyListener < FSR::Listener::Outbound
31
31
  @queue.unshift block if block_given?
32
32
  end
33
33
 
34
+ def set(var, value, &block)
35
+ @queue.unshift(block_given? ? block : lambda {})
36
+ end
37
+
34
38
  def test_state_machine
35
39
  @state_machine_test = nil
36
40
  do_something do
@@ -46,6 +50,12 @@ class MyListener < FSR::Listener::Outbound
46
50
  end
47
51
  end
48
52
 
53
+ def test_state_machine_without_blocks
54
+ answer
55
+ set("test", "test1")
56
+ set("another_one", "bites_the_dust")
57
+ end
58
+
49
59
  end
50
60
 
51
61
  # Begin testing MyListener
@@ -106,6 +116,20 @@ EM.describe MyListener do
106
116
  done
107
117
  end
108
118
 
119
+ should "use implicit blocks to 'fake' I/O blocking and wait for a response before calling the next implicit block" do
120
+ @listener.receive_data("Content-Length: 0\nEstablished-Session: session\n\n")
121
+ @listener.test_state_machine_without_blocks
122
+ @listener.queue.size.should.equal 3
123
+ @listener.receive_data("Content-Length: 3\n\nOk\n\n")
124
+ @listener.queue.size.should.equal 2
125
+ @listener.receive_data("Content-Length: 3\n\nOk\n\n")
126
+ @listener.queue.size.should.equal 1
127
+ @listener.receive_data("Content-Length: 3\n\nOk\n\n")
128
+ @listener.queue.empty?.should.equal true
129
+ done
130
+ end
131
+
132
+
109
133
  should "be able to update an existing session" do
110
134
  @listener.receive_data("Content-Length: 0\nUnique-ID: abcd-1234-efgh-5678\n\n")
111
135
  @listener.session.headers[:unique_id].should.equal "abcd-1234-efgh-5678"
data/spec/fsr/loading.rb CHANGED
@@ -4,7 +4,7 @@ require 'spec/helper'
4
4
  describe "Testing FSR module loading methods" do
5
5
  # When you add applications you must modify the expected apps_loaded behavior
6
6
  it "Loads all applications" do
7
- all_apps = [:play_and_get_digits, :uuid_dump, :uuid_setvar, :uuid_getvar, :read, :set, :transfer, :speak, :fs_sleep, :playback, :answer, :fifo, :bridge, :hangup, :conference, :fs_break, :log, :limit]
7
+ all_apps = [:play_and_get_digits, :uuid_dump, :uuid_setvar, :uuid_getvar, :read, :set, :transfer, :speak, :fs_sleep, :playback, :answer, :fifo, :bridge, :hangup, :conference, :fs_break, :log, :limit, :bind_meta_app, :execute_app]
8
8
  # Add any apps which will load to this set
9
9
  apps_loaded = FSR.load_all_applications
10
10
  apps_loaded.kind_of?(Array).should == true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: freeswitcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jayson Vaughn
@@ -12,7 +12,7 @@ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
14
 
15
- date: 2009-07-03 00:00:00 -05:00
15
+ date: 2009-11-18 00:00:00 -06:00
16
16
  default_executable:
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
@@ -25,7 +25,94 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: "0"
27
27
  version:
28
- description: &id001 |
28
+ description: "========================================================= FreeSWITCHeR Copyright (c) 2009 The Rubyists (Jayson Vaughn, Tj Vanderpoel, Michael Fellinger, Kevin Berry) Distributed under the terms of the MIT License. ========================================================== ABOUT ----- A ruby library for interacting with the \"FreeSWITCH\" (http://www.freeswitch.org) opensource telephony platform REQUIREMENTS ------------ * ruby (>= 1.8) * eventmachine (If you wish to use Outbound and Inbound listener) USAGE ----- An Outbound Event Listener Example that reads and returns DTMF input: -------------------------------------------------------------------- Simply just create a subclass of FSR::Listner::Outbound and all new calls/sessions will invoke the \"session_initiated\" callback method. <b>NOTE</b>: FSR uses blocks within the 'session_inititated' method to ensure that the next \"freeswich command\" is not executed until the previous \"Freeswitch command\" has finished. (Basically a continuation) This is kicked off by \"answer do\". #!/usr/bin/ruby require 'fsr' require 'fsr/listener/outbound' class OutboundDemo < FSR::Listener::Outbound def session_initiated exten = @session.headers[:caller_caller_id_number] FSR::Log.info \"*** Answering incoming call from #{exten}\" answer do FSR::Log.info \"***Reading DTMF from #{exten}\" read(\"/home/freeswitch/freeswitch/sounds/music/8000/sweet.wav\", 4, 10, \"input\", 7000) do |read_var| FSR::Log.info \"***Success, grabbed #{read_var.to_s.strip} from #{exten}\" # Tell the caller what they entered speak(\"Got the DTMF of: #{read_var.to_s.strip}\") do #Hangup the call hangup end end end end end FSR.start_oes! OutboundDemo, :port => 8084, :host => \"127.0.0.1\" An Inbound Event Socket Listener example using FreeSWITCHeR's hook system: -------------------------------------------------------------------------- #!/usr/bin/ruby require 'pp' require 'fsr' require \"fsr/listener/inbound\" # EXAMPLE 1 # This adds a hook on CHANNEL_CREATE events. You can also create a method to handle the event you're after. See the next example FSL::Inbound.add_event_hook(:CHANNEL_CREATE) { FSR::Log.info \"*** [#{event.content[:unique_id]}] Channel created - greetings from the hook!\" } # EXAMPLE 2 # Define a method to handle CHANNEL_HANGUP events. def custom_channel_hangup_handler(event) FSR::Log.info \"*** [#{event.content[:unique_id]}] Channel hangup. The event:\" pp event end # This adds a hook for EXAMPLE 2 FSL::Inbound.add_event_hook(:CHANNEL_HANGUP) { custom_channel_hangup_handler(event) } # Start FSR Inbound Listener FSR.start_ies!(FSL::Inbound, :host => \"localhost\", :port => 8021) An Inbound Event Socket Listener example using the on_event callback method instead of hooks: --------------------------------------------------------------------------------------------- #!/usr/bin/ruby require 'pp' require 'fsr' require \"fsr/listener/inbound\" class IesDemo < FSR::Listener::Inbound def on_event pp event.headers pp event.content[:event_name] end end FSR.start_ies!(IesDemo, :host => \"localhost\", :port => 8021, :auth => \"ClueCon\") An example of using FSR::CommandSocket to originate a new call in irb: ---------------------------------------------------------------------- irb(main):001:0> require 'fsr' => true irb(main):002:0> FSR.load_all_commands => [:sofia, :originate] irb(main):003:0> sock = FSR::CommandSocket.new => #<FSR::CommandSocket:0xb7a89104 @server=\"127.0.0.1\", @socket=#<TCPSocket:0xb7a8908c>, @port=\"8021\", @auth=\"ClueCon\"> irb(main):007:0> sock.originate(:target => 'sofia/gateway/carlos/8179395222', :endpoint => FSR::App::Bridge.new(\"user/bougyman\")).run => {\"Job-UUID\"=>\"732075a4-7dd5-4258-b124-6284a82a5ae7\", \"body\"=>\"\", \"Content-Type\"=>\"command/reply\", \"Reply-Text\"=>\"+OK Job-UUID: 732075a4-7dd5-4258-b124-6284a82a5ae7\"} SUPPORT ------- Home page at http://code.rubyists.com/projects/fs #rubyists on FreeNode"
29
+ email: FreeSWITCHeR@rubyists.com
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - .gitignore
38
+ - AUTHORS
39
+ - CHANGELOG
40
+ - License.txt
41
+ - MANIFEST
42
+ - NEWS
43
+ - README
44
+ - Rakefile
45
+ - examples/inbound_event_socket.rb
46
+ - examples/inbound_socket_events.rb
47
+ - examples/outbound_event_socket.rb
48
+ - freeswitcher.gemspec
49
+ - lib/fsr.rb
50
+ - lib/fsr/app.rb
51
+ - lib/fsr/app/answer.rb
52
+ - lib/fsr/app/bind_meta_app.rb
53
+ - lib/fsr/app/bridge.rb
54
+ - lib/fsr/app/conference.rb
55
+ - lib/fsr/app/execute_app.rb
56
+ - lib/fsr/app/fifo.rb
57
+ - lib/fsr/app/fs_break.rb
58
+ - lib/fsr/app/fs_sleep.rb
59
+ - lib/fsr/app/hangup.rb
60
+ - lib/fsr/app/limit.rb
61
+ - lib/fsr/app/log.rb
62
+ - lib/fsr/app/play_and_get_digits.rb
63
+ - lib/fsr/app/playback.rb
64
+ - lib/fsr/app/read.rb
65
+ - lib/fsr/app/set.rb
66
+ - lib/fsr/app/speak.rb
67
+ - lib/fsr/app/transfer.rb
68
+ - lib/fsr/app/uuid_dump.rb
69
+ - lib/fsr/app/uuid_getvar.rb
70
+ - lib/fsr/app/uuid_setvar.rb
71
+ - lib/fsr/cmd.rb
72
+ - lib/fsr/cmd/calls.rb
73
+ - lib/fsr/cmd/fsctl.rb
74
+ - lib/fsr/cmd/originate.rb
75
+ - lib/fsr/cmd/sofia.rb
76
+ - lib/fsr/cmd/sofia/profile.rb
77
+ - lib/fsr/cmd/sofia/status.rb
78
+ - lib/fsr/cmd/sofia_contact.rb
79
+ - lib/fsr/cmd/status.rb
80
+ - lib/fsr/cmd/uuid_dump.rb
81
+ - lib/fsr/command_socket.rb
82
+ - lib/fsr/database.rb
83
+ - lib/fsr/database/call_limit.rb
84
+ - lib/fsr/database/core.rb
85
+ - lib/fsr/database/sofia_reg_external.rb
86
+ - lib/fsr/database/sofia_reg_internal.rb
87
+ - lib/fsr/database/voicemail_default.rb
88
+ - lib/fsr/event_socket.rb
89
+ - lib/fsr/fake_socket.rb
90
+ - lib/fsr/listener.rb
91
+ - lib/fsr/listener/header_and_content_response.rb
92
+ - lib/fsr/listener/inbound.rb
93
+ - lib/fsr/listener/inbound/event.rb
94
+ - lib/fsr/listener/mock.rb
95
+ - lib/fsr/listener/outbound.rb
96
+ - lib/fsr/model/call.rb
97
+ - lib/fsr/version.rb
98
+ - tasks/authors.rake
99
+ - tasks/bacon.rake
100
+ - tasks/changelog.rake
101
+ - tasks/copyright.rake
102
+ - tasks/gem.rake
103
+ - tasks/gem_installer.rake
104
+ - tasks/install_dependencies.rake
105
+ - tasks/manifest.rake
106
+ - tasks/release.rake
107
+ - tasks/reversion.rake
108
+ - tasks/setup.rake
109
+ - tasks/spec.rake
110
+ - tasks/yard.rake
111
+ - spec/helper.rb
112
+ - spec/fsr_listener_helper.rb
113
+ has_rdoc: false
114
+ homepage: http://code.rubyists.com/projects/fs
115
+ post_install_message: |
29
116
  =========================================================
30
117
  FreeSWITCHeR
31
118
  Copyright (c) 2009 The Rubyists (Jayson Vaughn, Tj Vanderpoel, Michael Fellinger, Kevin Berry)
@@ -50,7 +137,7 @@ description: &id001 |
50
137
  Simply just create a subclass of FSR::Listner::Outbound and all
51
138
  new calls/sessions will invoke the "session_initiated" callback method.
52
139
 
53
- <b>NOTE</b>: FSR uses blocks within the 'session_inititated' method to ensure that the next "freeswich command" is not executed until the previous "Freeswitch command" has finished. This is kicked off by "answer do"
140
+ <b>NOTE</b>: FSR uses blocks within the 'session_inititated' method to ensure that the next "freeswich command" is not executed until the previous "Freeswitch command" has finished. (Basically a continuation) This is kicked off by "answer do".
54
141
 
55
142
  #!/usr/bin/ruby
56
143
  require 'fsr'
@@ -65,9 +152,9 @@ description: &id001 |
65
152
  answer do
66
153
  FSR::Log.info "***Reading DTMF from #{exten}"
67
154
  read("/home/freeswitch/freeswitch/sounds/music/8000/sweet.wav", 4, 10, "input", 7000) do |read_var|
68
- FSR::Log.info "***Success, grabbed #{read_var.strip} from #{exten}"
155
+ FSR::Log.info "***Success, grabbed #{read_var.to_s.strip} from #{exten}"
69
156
  # Tell the caller what they entered
70
- speak("Got the DTMF of: #{read_var}") do
157
+ speak("Got the DTMF of: #{read_var.to_s.strip}") do
71
158
  #Hangup the call
72
159
  hangup
73
160
  end
@@ -90,7 +177,7 @@ description: &id001 |
90
177
 
91
178
  # EXAMPLE 1
92
179
  # This adds a hook on CHANNEL_CREATE events. You can also create a method to handle the event you're after. See the next example
93
- FSL::Inbound.add_event_hook(:CHANNEL_CREATE) {|event| FSR::Log.info "*** [#{event.content[:unique_id]}] Channel created - greetings from the hook!" }
180
+ FSL::Inbound.add_event_hook(:CHANNEL_CREATE) { FSR::Log.info "*** [#{event.content[:unique_id]}] Channel created - greetings from the hook!" }
94
181
 
95
182
  # EXAMPLE 2
96
183
  # Define a method to handle CHANNEL_HANGUP events.
@@ -100,7 +187,7 @@ description: &id001 |
100
187
  end
101
188
 
102
189
  # This adds a hook for EXAMPLE 2
103
- FSL::Inbound.add_event_hook(:CHANNEL_HANGUP) {|event| custom_channel_hangup_handler(event) }
190
+ FSL::Inbound.add_event_hook(:CHANNEL_HANGUP) { custom_channel_hangup_handler(event) }
104
191
 
105
192
 
106
193
  # Start FSR Inbound Listener
@@ -118,7 +205,7 @@ description: &id001 |
118
205
 
119
206
  class IesDemo < FSR::Listener::Inbound
120
207
 
121
- def on_event(event)
208
+ def on_event
122
209
  pp event.headers
123
210
  pp event.content[:event_name]
124
211
  end
@@ -150,93 +237,6 @@ description: &id001 |
150
237
  Home page at http://code.rubyists.com/projects/fs
151
238
  #rubyists on FreeNode
152
239
 
153
- email: FreeSWITCHeR@rubyists.com
154
- executables: []
155
-
156
- extensions: []
157
-
158
- extra_rdoc_files: []
159
-
160
- files:
161
- - .gitignore
162
- - AUTHORS
163
- - CHANGELOG
164
- - License.txt
165
- - MANIFEST
166
- - NEWS
167
- - README
168
- - Rakefile
169
- - examples/inbound_event_socket.rb
170
- - examples/inbound_socket_events.rb
171
- - examples/outbound_event_socket.rb
172
- - freeswitcher.gemspec
173
- - lib/fsr.rb
174
- - lib/fsr/app.rb
175
- - lib/fsr/app/answer.rb
176
- - lib/fsr/app/bridge.rb
177
- - lib/fsr/app/conference.rb
178
- - lib/fsr/app/fifo.rb
179
- - lib/fsr/app/fs_break.rb
180
- - lib/fsr/app/fs_sleep.rb
181
- - lib/fsr/app/hangup.rb
182
- - lib/fsr/app/limit.rb
183
- - lib/fsr/app/log.rb
184
- - lib/fsr/app/play_and_get_digits.rb
185
- - lib/fsr/app/playback.rb
186
- - lib/fsr/app/read.rb
187
- - lib/fsr/app/set.rb
188
- - lib/fsr/app/speak.rb
189
- - lib/fsr/app/transfer.rb
190
- - lib/fsr/app/uuid_dump.rb
191
- - lib/fsr/app/uuid_getvar.rb
192
- - lib/fsr/app/uuid_setvar.rb
193
- - lib/fsr/cmd.rb
194
- - lib/fsr/cmd/calls.rb
195
- - lib/fsr/cmd/fsctl.rb
196
- - lib/fsr/cmd/originate.rb
197
- - lib/fsr/cmd/sofia.rb
198
- - lib/fsr/cmd/sofia/profile.rb
199
- - lib/fsr/cmd/sofia/status.rb
200
- - lib/fsr/cmd/sofia_contact.rb
201
- - lib/fsr/cmd/status.rb
202
- - lib/fsr/cmd/uuid_dump.rb
203
- - lib/fsr/command_socket.rb
204
- - lib/fsr/database.rb
205
- - lib/fsr/database/call_limit.rb
206
- - lib/fsr/database/core.rb
207
- - lib/fsr/database/sofia_reg_external.rb
208
- - lib/fsr/database/sofia_reg_internal.rb
209
- - lib/fsr/database/voicemail_default.rb
210
- - lib/fsr/event_socket.rb
211
- - lib/fsr/fake_socket.rb
212
- - lib/fsr/listener.rb
213
- - lib/fsr/listener/header_and_content_response.rb
214
- - lib/fsr/listener/inbound.rb
215
- - lib/fsr/listener/inbound/event.rb
216
- - lib/fsr/listener/mock.rb
217
- - lib/fsr/listener/outbound.rb
218
- - lib/fsr/model/call.rb
219
- - lib/fsr/version.rb
220
- - tasks/authors.rake
221
- - tasks/bacon.rake
222
- - tasks/changelog.rake
223
- - tasks/copyright.rake
224
- - tasks/gem.rake
225
- - tasks/gem_installer.rake
226
- - tasks/install_dependencies.rake
227
- - tasks/manifest.rake
228
- - tasks/release.rake
229
- - tasks/reversion.rake
230
- - tasks/setup.rake
231
- - tasks/spec.rake
232
- - tasks/yard.rake
233
- - spec/helper.rb
234
- - spec/fsr_listener_helper.rb
235
- has_rdoc: true
236
- homepage: http://code.rubyists.com/projects/fs
237
- licenses: []
238
-
239
- post_install_message: *id001
240
240
  rdoc_options: []
241
241
 
242
242
  require_paths:
@@ -256,15 +256,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
256
256
  requirements: []
257
257
 
258
258
  rubyforge_project: freeswitcher
259
- rubygems_version: 1.3.4
259
+ rubygems_version: 1.3.1
260
260
  signing_key:
261
- specification_version: 3
261
+ specification_version: 2
262
262
  summary: A library for interacting with the "FreeSWITCH":http://freeswitch.org telephony platform
263
263
  test_files:
264
264
  - spec/fsr/app.rb
265
265
  - spec/fsr/app/answer.rb
266
+ - spec/fsr/app/bind_meta_app.rb
266
267
  - spec/fsr/app/bridge.rb
267
268
  - spec/fsr/app/conference.rb
269
+ - spec/fsr/app/execute_app.rb
268
270
  - spec/fsr/app/fifo.rb
269
271
  - spec/fsr/app/fs_break.rb
270
272
  - spec/fsr/app/fs_sleep.rb