freeswitcher 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/AUTHORS CHANGED
@@ -1,14 +1,15 @@
1
1
  Following persons have contributed to freeswitcher.
2
2
  (Sorted by number of submitted patches, then alphabetically)
3
3
 
4
- 118 TJ Vanderpoel <bougy.man@gmail.com>
4
+ 123 TJ Vanderpoel <bougy.man@gmail.com>
5
5
  64 Jayson Vaughn <jayson@onedrop.home>
6
- 28 Michael Fellinger <m.fellinger@gmail.com>
7
- 11 Jayson Vaughn <jayson@onedrop.(none)>
6
+ 40 Michael Fellinger <m.fellinger@gmail.com>
7
+ 15 Jayson Vaughn <jayson@onedrop.(none)>
8
8
  9 Jayson Vaughn <jayson@onedrop.nationwide-recovery.com>
9
+ 7 Jayson Vaughn <vaughn.jayson@gmail.com>
9
10
  6 Mikael Bjerkeland <mikael@consoll.no>
10
11
  4 foo <jvaughn@hellspass.nationwide-recovery.com>
11
- 4 Jayson Vaughn <vaughn.jayson@gmail.com>
12
12
  3 Kevin Berry <kevin@opensourcealchemist.com>
13
+ 2 freeswitch <freeswitch@falcon.(none)>
13
14
  1 jayson vaughn <jayson@falcon.(none)>
14
15
  1 U-Paul-PC\Paul <Paul@Paul-PC.(none)>
data/CHANGELOG CHANGED
@@ -1,3 +1,92 @@
1
+ [55753af | Wed Jun 03 23:10:22 UTC 2009] Jayson Vaughn <vaughn.jayson@gmail.com>
2
+
3
+ * Updated outbound_event_socket.rb example
4
+
5
+ [234a17e | Wed Jun 03 23:01:56 UTC 2009] Jayson Vaughn <vaughn.jayson@gmail.com>
6
+
7
+ * Refactored api to be a method of FSR::Listener::Outbound
8
+
9
+ [0bc8973 | Wed Jun 03 21:55:02 UTC 2009] Jayson Vaughn <vaughn.jayson@gmail.com>
10
+
11
+ * Added FSR::App::Api
12
+
13
+ [9d2cc41 | Sat May 30 18:49:08 UTC 2009] Jayson Vaughn <jayson@onedrop.(none)>
14
+
15
+ * Made some changes so FSR is Ruby 1.9.1 compat
16
+
17
+ * Monkey patched, unfortunately, String class with alias :each
18
+ * :each_line compat with EventMachine
19
+
20
+ [a40e1ed | Sat May 30 18:10:35 UTC 2009] Jayson Vaughn <jayson@onedrop.(none)>
21
+
22
+ * Corrected typo in examples/outbound_event_socket.rb
23
+
24
+ [0a3f680 | Fri May 29 16:15:15 UTC 2009] Jayson Vaughn <jayson@onedrop.(none)>
25
+
26
+ * Added .to_s at end of Dir[load_path.join("*.rb").to_s] for Ruby 1.9.1
27
+
28
+
29
+
30
+ [f267c17 | Wed May 27 20:49:27 UTC 2009] Jayson Vaughn <jayson@onedrop.(none)>
31
+
32
+ * Updated header_and_content specs
33
+
34
+ [19ee736 | Sat May 23 18:34:18 UTC 2009] TJ Vanderpoel <bougy.man@gmail.com>
35
+
36
+ * Change example and readme to match what is demoed at sip:8084@falcon.rubyists.com
37
+
38
+ [5be4271 | Tue May 19 21:02:09 UTC 2009] freeswitch <freeswitch@falcon.(none)>
39
+
40
+ * try to load log4r for logging (Logger buffers, bugs with runit services), fall back to Logger from stdlib if log4r not found
41
+
42
+ [921251a | Tue May 19 20:13:47 UTC 2009] freeswitch <freeswitch@falcon.(none)>
43
+
44
+ * reverted regression to listeners, back to functional
45
+
46
+ [eb72db4 | Tue May 19 15:15:04 UTC 2009] TJ Vanderpoel <bougy.man@gmail.com>
47
+
48
+ * changed spacing in content#find
49
+
50
+ [c275898 | Tue May 19 15:12:39 UTC 2009] TJ Vanderpoel <bougy.man@gmail.com>
51
+
52
+ * improve the regex for matching a header: value in content of HeaderAndContentResponse
53
+
54
+ [4bfaf24 | Wed May 20 05:05:07 UTC 2009] Michael Fellinger <m.fellinger@gmail.com>
55
+
56
+ * headers/content come in as Array
57
+
58
+ [5640b6f | Wed May 20 04:54:42 UTC 2009] Michael Fellinger <m.fellinger@gmail.com>
59
+
60
+ * Fix the listener/outbound spec
61
+
62
+ [29527e2 | Tue May 19 23:20:24 UTC 2009] Michael Fellinger <m.fellinger@gmail.com>
63
+
64
+ * Minor cleanup
65
+
66
+ [38b98fa | Tue May 19 21:04:41 UTC 2009] Michael Fellinger <m.fellinger@gmail.com>
67
+
68
+ * Add some more outbound specs and refactor
69
+
70
+ [817e731 | Tue May 19 21:04:22 UTC 2009] Michael Fellinger <m.fellinger@gmail.com>
71
+
72
+ * Add HeaderAndContentResponse subclass that will take care of parsing the content if it should be parsed
73
+
74
+ [d44c3f0 | Tue May 19 20:45:48 UTC 2009] Michael Fellinger <m.fellinger@gmail.com>
75
+
76
+ * Minor refactor and some more specs for inbound listener
77
+
78
+ [4f945e5 | Tue May 19 20:28:53 UTC 2009] Michael Fellinger <m.fellinger@gmail.com>
79
+
80
+ * Refactor and basic specs of HeaderAndContentResponse, integration with inbound/outbound follow
81
+
82
+ [e3c3142 | Tue May 19 19:29:21 UTC 2009] Michael Fellinger <m.fellinger@gmail.com>
83
+
84
+ * A little bit less annoying require_relative look-alike
85
+
86
+ [e80cbc1 | Tue May 19 00:27:53 UTC 2009] TJ Vanderpoel <bougy.man@gmail.com>
87
+
88
+ * updated authors and changelog
89
+
1
90
  [9451ba8 | Tue May 19 00:26:26 UTC 2009] TJ Vanderpoel <bougy.man@gmail.com>
2
91
 
3
92
  * Version 0.3.1 fixes bug in FS_ROOT not being populated properly
@@ -516,6 +605,10 @@
516
605
 
517
606
 
518
607
 
608
+ [ab373dd | Tue Mar 24 00:52:38 UTC 2009] Michael Fellinger <m.fellinger@gmail.com>
609
+
610
+ * Remove cruft from form helper
611
+
519
612
  [0464d4e | Thu Mar 19 19:17:41 UTC 2009] Jayson Vaughn <jayson@onedrop.home>
520
613
 
521
614
  * Updated specs to include new apps
data/MANIFEST CHANGED
@@ -90,6 +90,7 @@ spec/fsr/cmd/originate.rb
90
90
  spec/fsr/cmd/sofia.rb
91
91
  spec/fsr/cmd/sofia/profile.rb
92
92
  spec/fsr/listener.rb
93
+ spec/fsr/listener/header_and_content_response.rb
93
94
  spec/fsr/listener/inbound.rb
94
95
  spec/fsr/listener/outbound.rb
95
96
  spec/fsr/loading.rb
data/README CHANGED
@@ -37,8 +37,12 @@ new calls/sessions will invoke the "session_initiated" callback method.
37
37
  answer do
38
38
  FSR::Log.info "***Reading DTMF from #{exten}"
39
39
  read("/home/freeswitch/freeswitch/sounds/music/8000/sweet.wav", 4, 10, "input", 7000) do |read_var|
40
- FSR::Log.info "***Success, grabbed #{read_var.strip} from #{exten}"
41
- hangup #Hangup the call
40
+ FSR::Log.info "***Success, grabbed #{read_var.strip} from #{exten}"
41
+ # Tell the caller what they entered
42
+ speak("Got the DTMF of: #{read_var}") do
43
+ #Hangup the call
44
+ hangup
45
+ end
42
46
  end
43
47
  end
44
48
 
@@ -12,9 +12,14 @@ class OutboundDemo < FSR::Listener::Outbound
12
12
 
13
13
  answer do
14
14
  FSR::Log.info "***Reading DTMF from #{exten}"
15
- read("/home/freeswitch/freeswitch/sounds/music/8000/sweet.wav", 4, 10, "input", 7000) do |read_var|
15
+ #######################################################
16
+ ## NOTE YOU MUST MAKE SURE YOU PASS A VALID WAV FILE ##
17
+ #######################################################
18
+ read("/usr/local/freeswitch/sounds/music/8000/sweet.wav", 4, 10, "input", 7000) do |read_var|
16
19
  FSR::Log.info "***Success, grabbed #{read_var.strip} from #{exten}"
17
- hangup #Hangup the call
20
+ # Tell the caller what they entered
21
+ # If you have mod_flite installed you should hear speech
22
+ speak("Got the DTMF of: #{read_var}")
18
23
  end
19
24
  end
20
25
 
@@ -2,14 +2,137 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{freeswitcher}
5
- s.version = "0.3.1"
5
+ s.version = "0.4.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Jayson Vaughn", "Michael Fellinger", "Kevin Berry", "TJ Vanderpoel"]
9
- s.date = %q{2009-05-18}
10
- s.description = %q{========================================================= 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. 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.strip} from #{exten}" hangup #Hangup the call 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) {|event| 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) {|event| 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(event) pp event.headers pp event.content[:event_name] end end FSR.start_ies!(IesDemo, :host => "localhost", :port => 8021) 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}
9
+ s.date = %q{2009-06-03}
10
+ s.description = %q{=========================================================
11
+ FreeSWITCHeR
12
+ Copyright (c) 2009 The Rubyists (Jayson Vaughn, Tj Vanderpoel, Michael Fellinger, Kevin Berry)
13
+ Distributed under the terms of the MIT License.
14
+ ==========================================================
15
+
16
+ ABOUT
17
+ -----
18
+ A ruby library for interacting with the "FreeSWITCH" (http://www.freeswitch.org) opensource telephony platform
19
+
20
+ REQUIREMENTS
21
+ ------------
22
+ * ruby (>= 1.8)
23
+ * eventmachine (If you wish to use Outbound and Inbound listener)
24
+
25
+ USAGE
26
+ -----
27
+
28
+ An Outbound Event Listener Example that reads and returns DTMF input:
29
+ --------------------------------------------------------------------
30
+
31
+ Simply just create a subclass of FSR::Listner::Outbound and all
32
+ new calls/sessions will invoke the "session_initiated" callback method.
33
+
34
+ <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"
35
+
36
+ #!/usr/bin/ruby
37
+ require 'fsr'
38
+ require 'fsr/listener/outbound'
39
+
40
+ class OutboundDemo < FSR::Listener::Outbound
41
+
42
+ def session_initiated
43
+ exten = @session.headers[:caller_caller_id_number]
44
+ FSR::Log.info "*** Answering incoming call from #{exten}"
45
+
46
+ answer do
47
+ FSR::Log.info "***Reading DTMF from #{exten}"
48
+ read("/home/freeswitch/freeswitch/sounds/music/8000/sweet.wav", 4, 10, "input", 7000) do |read_var|
49
+ FSR::Log.info "***Success, grabbed #{read_var.strip} from #{exten}"
50
+ # Tell the caller what they entered
51
+ speak("Got the DTMF of: #{read_var}") do
52
+ #Hangup the call
53
+ hangup
54
+ end
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
62
+ FSR.start_oes! OutboundDemo, :port => 8084, :host => "127.0.0.1"
63
+
64
+ An Inbound Event Socket Listener example using FreeSWITCHeR's hook system:
65
+ --------------------------------------------------------------------------
66
+
67
+ #!/usr/bin/ruby
68
+ require 'pp'
69
+ require 'fsr'
70
+ require "fsr/listener/inbound"
71
+
72
+ # EXAMPLE 1
73
+ # 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
74
+ FSL::Inbound.add_event_hook(:CHANNEL_CREATE) {|event| FSR::Log.info "*** [#{event.content[:unique_id]}] Channel created - greetings from the hook!" }
75
+
76
+ # EXAMPLE 2
77
+ # Define a method to handle CHANNEL_HANGUP events.
78
+ def custom_channel_hangup_handler(event)
79
+ FSR::Log.info "*** [#{event.content[:unique_id]}] Channel hangup. The event:"
80
+ pp event
81
+ end
82
+
83
+ # This adds a hook for EXAMPLE 2
84
+ FSL::Inbound.add_event_hook(:CHANNEL_HANGUP) {|event| custom_channel_hangup_handler(event) }
85
+
86
+
87
+ # Start FSR Inbound Listener
88
+ FSR.start_ies!(FSL::Inbound, :host => "localhost", :port => 8021)
89
+
90
+
91
+ An Inbound Event Socket Listener example using the on_event callback method instead of hooks:
92
+ ---------------------------------------------------------------------------------------------
93
+
94
+ #!/usr/bin/ruby
95
+ require 'pp'
96
+ require 'fsr'
97
+ require "fsr/listener/inbound"
98
+
99
+
100
+ class IesDemo < FSR::Listener::Inbound
101
+
102
+ def on_event(event)
103
+ pp event.headers
104
+ pp event.content[:event_name]
105
+ end
106
+
107
+ end
108
+
109
+ FSR.start_ies!(IesDemo, :host => "localhost", :port => 8021)
110
+
111
+
112
+ An example of using FSR::CommandSocket to originate a new call in irb:
113
+ ----------------------------------------------------------------------
114
+
115
+ irb(main):001:0> require 'fsr'
116
+ => true
117
+
118
+ irb(main):002:0> FSR.load_all_commands
119
+ => [:sofia, :originate]
120
+
121
+ irb(main):003:0> sock = FSR::CommandSocket.new
122
+ => #<FSR::CommandSocket:0xb7a89104 @server="127.0.0.1", @socket=#<TCPSocket:0xb7a8908c>, @port="8021", @auth="ClueCon">
123
+
124
+ irb(main):007:0> sock.originate(:target => 'sofia/gateway/carlos/8179395222', :endpoint => FSR::App::Bridge.new("user/bougyman")).run
125
+ => {"Job-UUID"=>"732075a4-7dd5-4258-b124-6284a82a5ae7", "body"=>"", "Content-Type"=>"command/reply", "Reply-Text"=>"+OK Job-UUID: 732075a4-7dd5-4258-b124-6284a82a5ae7"}
126
+
127
+
128
+
129
+ SUPPORT
130
+ -------
131
+ Home page at http://code.rubyists.com/projects/fs
132
+ #rubyists on FreeNode
133
+ }
11
134
  s.email = %q{FreeSWITCHeR@rubyists.com}
12
- s.files = [".gitignore", "AUTHORS", "CHANGELOG", "License.txt", "MANIFEST", "NEWS", "README", "Rakefile", "examples/inbound_event_socket.rb", "examples/inbound_socket_events.rb", "examples/outbound_event_socket.rb", "freeswitcher.gemspec", "lib/fsr.rb", "lib/fsr/app.rb", "lib/fsr/app/answer.rb", "lib/fsr/app/bridge.rb", "lib/fsr/app/conference.rb", "lib/fsr/app/fifo.rb", "lib/fsr/app/fs_break.rb", "lib/fsr/app/fs_sleep.rb", "lib/fsr/app/hangup.rb", "lib/fsr/app/limit.rb", "lib/fsr/app/log.rb", "lib/fsr/app/play_and_get_digits.rb", "lib/fsr/app/playback.rb", "lib/fsr/app/read.rb", "lib/fsr/app/set.rb", "lib/fsr/app/speak.rb", "lib/fsr/app/transfer.rb", "lib/fsr/app/uuid_dump.rb", "lib/fsr/app/uuid_getvar.rb", "lib/fsr/app/uuid_setvar.rb", "lib/fsr/cmd.rb", "lib/fsr/cmd/calls.rb", "lib/fsr/cmd/fsctl.rb", "lib/fsr/cmd/originate.rb", "lib/fsr/cmd/sofia.rb", "lib/fsr/cmd/sofia/profile.rb", "lib/fsr/cmd/sofia/status.rb", "lib/fsr/cmd/sofia_contact.rb", "lib/fsr/cmd/status.rb", "lib/fsr/command_socket.rb", "lib/fsr/database.rb", "lib/fsr/database/call_limit.rb", "lib/fsr/database/core.rb", "lib/fsr/database/sofia_reg_external.rb", "lib/fsr/database/sofia_reg_internal.rb", "lib/fsr/database/voicemail_default.rb", "lib/fsr/event_socket.rb", "lib/fsr/fake_socket.rb", "lib/fsr/listener.rb", "lib/fsr/listener/header_and_content_response.rb", "lib/fsr/listener/inbound.rb", "lib/fsr/listener/inbound/event.rb", "lib/fsr/listener/outbound.rb", "lib/fsr/model/call.rb", "lib/fsr/version.rb", "tasks/authors.rake", "tasks/bacon.rake", "tasks/changelog.rake", "tasks/copyright.rake", "tasks/gem.rake", "tasks/gem_installer.rake", "tasks/install_dependencies.rake", "tasks/manifest.rake", "tasks/rcov.rake", "tasks/release.rake", "tasks/reversion.rake", "tasks/setup.rake", "tasks/spec.rake", "tasks/yard.rake", "spec/helper.rb", "spec/fsr/app.rb", "spec/fsr/app/answer.rb", "spec/fsr/app/bridge.rb", "spec/fsr/app/conference.rb", "spec/fsr/app/fifo.rb", "spec/fsr/app/fs_break.rb", "spec/fsr/app/fs_sleep.rb", "spec/fsr/app/hangup.rb", "spec/fsr/app/limit.rb", "spec/fsr/app/log.rb", "spec/fsr/app/play_and_get_digits.rb", "spec/fsr/app/playback.rb", "spec/fsr/app/set.rb", "spec/fsr/app/transfer.rb", "spec/fsr/cmd.rb", "spec/fsr/cmd/calls.rb", "spec/fsr/cmd/originate.rb", "spec/fsr/cmd/sofia.rb", "spec/fsr/cmd/sofia/profile.rb", "spec/fsr/listener.rb", "spec/fsr/listener/inbound.rb", "spec/fsr/listener/outbound.rb", "spec/fsr/loading.rb"]
135
+ s.files = [".gitignore", "AUTHORS", "CHANGELOG", "License.txt", "MANIFEST", "NEWS", "README", "Rakefile", "examples/inbound_event_socket.rb", "examples/inbound_socket_events.rb", "examples/outbound_event_socket.rb", "freeswitcher.gemspec", "lib/fsr.rb", "lib/fsr/app.rb", "lib/fsr/app/answer.rb", "lib/fsr/app/bridge.rb", "lib/fsr/app/conference.rb", "lib/fsr/app/fifo.rb", "lib/fsr/app/fs_break.rb", "lib/fsr/app/fs_sleep.rb", "lib/fsr/app/hangup.rb", "lib/fsr/app/limit.rb", "lib/fsr/app/log.rb", "lib/fsr/app/play_and_get_digits.rb", "lib/fsr/app/playback.rb", "lib/fsr/app/read.rb", "lib/fsr/app/set.rb", "lib/fsr/app/speak.rb", "lib/fsr/app/transfer.rb", "lib/fsr/app/uuid_dump.rb", "lib/fsr/app/uuid_getvar.rb", "lib/fsr/app/uuid_setvar.rb", "lib/fsr/cmd.rb", "lib/fsr/cmd/calls.rb", "lib/fsr/cmd/fsctl.rb", "lib/fsr/cmd/originate.rb", "lib/fsr/cmd/sofia.rb", "lib/fsr/cmd/sofia/profile.rb", "lib/fsr/cmd/sofia/status.rb", "lib/fsr/cmd/sofia_contact.rb", "lib/fsr/cmd/status.rb", "lib/fsr/command_socket.rb", "lib/fsr/database.rb", "lib/fsr/database/call_limit.rb", "lib/fsr/database/core.rb", "lib/fsr/database/sofia_reg_external.rb", "lib/fsr/database/sofia_reg_internal.rb", "lib/fsr/database/voicemail_default.rb", "lib/fsr/event_socket.rb", "lib/fsr/fake_socket.rb", "lib/fsr/listener.rb", "lib/fsr/listener/header_and_content_response.rb", "lib/fsr/listener/inbound.rb", "lib/fsr/listener/inbound/event.rb", "lib/fsr/listener/outbound.rb", "lib/fsr/model/call.rb", "lib/fsr/version.rb", "tasks/authors.rake", "tasks/bacon.rake", "tasks/changelog.rake", "tasks/copyright.rake", "tasks/gem.rake", "tasks/gem_installer.rake", "tasks/install_dependencies.rake", "tasks/manifest.rake", "tasks/rcov.rake", "tasks/release.rake", "tasks/reversion.rake", "tasks/setup.rake", "tasks/spec.rake", "tasks/yard.rake", "spec/helper.rb", "spec/fsr/app.rb", "spec/fsr/app/answer.rb", "spec/fsr/app/bridge.rb", "spec/fsr/app/conference.rb", "spec/fsr/app/fifo.rb", "spec/fsr/app/fs_break.rb", "spec/fsr/app/fs_sleep.rb", "spec/fsr/app/hangup.rb", "spec/fsr/app/limit.rb", "spec/fsr/app/log.rb", "spec/fsr/app/play_and_get_digits.rb", "spec/fsr/app/playback.rb", "spec/fsr/app/set.rb", "spec/fsr/app/transfer.rb", "spec/fsr/cmd.rb", "spec/fsr/cmd/calls.rb", "spec/fsr/cmd/originate.rb", "spec/fsr/cmd/sofia.rb", "spec/fsr/cmd/sofia/profile.rb", "spec/fsr/listener.rb", "spec/fsr/listener/header_and_content_response.rb", "spec/fsr/listener/inbound.rb", "spec/fsr/listener/outbound.rb", "spec/fsr/loading.rb"]
13
136
  s.homepage = %q{http://code.rubyists.com/projects/fs}
14
137
  s.post_install_message = %q{=========================================================
15
138
  FreeSWITCHeR
@@ -50,8 +173,12 @@ new calls/sessions will invoke the "session_initiated" callback method.
50
173
  answer do
51
174
  FSR::Log.info "***Reading DTMF from #{exten}"
52
175
  read("/home/freeswitch/freeswitch/sounds/music/8000/sweet.wav", 4, 10, "input", 7000) do |read_var|
53
- FSR::Log.info "***Success, grabbed #{read_var.strip} from #{exten}"
54
- hangup #Hangup the call
176
+ FSR::Log.info "***Success, grabbed #{read_var.strip} from #{exten}"
177
+ # Tell the caller what they entered
178
+ speak("Got the DTMF of: #{read_var}") do
179
+ #Hangup the call
180
+ hangup
181
+ end
55
182
  end
56
183
  end
57
184
 
@@ -133,13 +260,13 @@ Home page at http://code.rubyists.com/projects/fs
133
260
  }
134
261
  s.require_paths = ["lib"]
135
262
  s.rubyforge_project = %q{freeswitcher}
136
- s.rubygems_version = %q{1.3.1}
263
+ s.rubygems_version = %q{1.3.3}
137
264
  s.summary = %q{A library for interacting with the "FreeSWITCH":http://freeswitch.org telephony platform}
138
- s.test_files = ["spec/fsr/app.rb", "spec/fsr/app/answer.rb", "spec/fsr/app/bridge.rb", "spec/fsr/app/conference.rb", "spec/fsr/app/fifo.rb", "spec/fsr/app/fs_break.rb", "spec/fsr/app/fs_sleep.rb", "spec/fsr/app/hangup.rb", "spec/fsr/app/limit.rb", "spec/fsr/app/log.rb", "spec/fsr/app/play_and_get_digits.rb", "spec/fsr/app/playback.rb", "spec/fsr/app/set.rb", "spec/fsr/app/transfer.rb", "spec/fsr/cmd.rb", "spec/fsr/cmd/calls.rb", "spec/fsr/cmd/originate.rb", "spec/fsr/cmd/sofia.rb", "spec/fsr/cmd/sofia/profile.rb", "spec/fsr/listener.rb", "spec/fsr/listener/inbound.rb", "spec/fsr/listener/outbound.rb", "spec/fsr/loading.rb"]
265
+ s.test_files = ["spec/fsr/app.rb", "spec/fsr/app/answer.rb", "spec/fsr/app/bridge.rb", "spec/fsr/app/conference.rb", "spec/fsr/app/fifo.rb", "spec/fsr/app/fs_break.rb", "spec/fsr/app/fs_sleep.rb", "spec/fsr/app/hangup.rb", "spec/fsr/app/limit.rb", "spec/fsr/app/log.rb", "spec/fsr/app/play_and_get_digits.rb", "spec/fsr/app/playback.rb", "spec/fsr/app/set.rb", "spec/fsr/app/transfer.rb", "spec/fsr/cmd.rb", "spec/fsr/cmd/calls.rb", "spec/fsr/cmd/originate.rb", "spec/fsr/cmd/sofia.rb", "spec/fsr/cmd/sofia/profile.rb", "spec/fsr/listener.rb", "spec/fsr/listener/header_and_content_response.rb", "spec/fsr/listener/inbound.rb", "spec/fsr/listener/outbound.rb", "spec/fsr/loading.rb"]
139
266
 
140
267
  if s.respond_to? :specification_version then
141
268
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
142
- s.specification_version = 2
269
+ s.specification_version = 3
143
270
 
144
271
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
145
272
  s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
data/lib/fsr.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'logger'
2
1
  require 'socket'
3
2
  require 'pathname'
4
3
  require 'pp'
@@ -15,14 +14,19 @@ module FSR
15
14
  DEFAULT_CALLER_ID_NUMBER = '8675309'
16
15
  DEFAULT_CALLER_ID_NAME = "FSR"
17
16
 
18
- # Usage:
19
- #
20
- # Log.info('foo')
21
- # Log.debug('bar')
22
- # Log.warn('foobar')
23
- # Log.error('barfoo')
24
- Log = Logger.new($stdout)
25
- Log.level = Logger::INFO
17
+ # attempt to require log4r.
18
+ # if log4r is not available, load logger from stdlib
19
+ begin
20
+ require 'log4r'
21
+ Log = Log4r::Logger.new('FSR')
22
+ Log.outputters = Log4r::Outputter.stdout
23
+ Log.level = Log4r::INFO
24
+ rescue LoadError
25
+ $stderr.puts "No log4r found, falling back to standard ruby library Logger"
26
+ require 'logger'
27
+ Log = Logger.new(STDOUT)
28
+ Log.level = Logger::INFO
29
+ end
26
30
 
27
31
  ROOT = Pathname(__FILE__).dirname.expand_path.freeze
28
32
  $LOAD_PATH.unshift(FSR::ROOT)
@@ -62,7 +62,7 @@ module FSR
62
62
  # Load all of the commands we find in Cmd::LOAD_PATH
63
63
  def self.load_all(force_reload = false)
64
64
  LOAD_PATH.each do |load_path|
65
- Dir[load_path.join("*.rb")].each { |command_file| load_command(command_file, force_reload) }
65
+ Dir[load_path.join("*.rb").to_s].each { |command_file| load_command(command_file, force_reload) }
66
66
  end
67
67
  list
68
68
  end
@@ -7,4 +7,7 @@ module FSR
7
7
 
8
8
  end
9
9
  end
10
+ class String
11
+ alias :each :each_line
12
+ end
10
13
  FSL = FSR::Listener
@@ -58,6 +58,12 @@ module FSR
58
58
  self.respond_to?(:send_data) ? send_data(message) : message
59
59
  end
60
60
 
61
+ # API
62
+ def api(command, &block)
63
+ send_data("api #{command}\r\n\r\n")
64
+ @queue.unshift block if block_given?
65
+ end
66
+
61
67
  # Update_session
62
68
 
63
69
  def update_session(&block)
@@ -104,8 +110,12 @@ module FSR
104
110
  FSR::Log.info("@uuid_var is set => #{session_header_and_content.inspect} : #{content}")
105
111
  r, @uuid_var = session_header_and_content.content.strip, nil
106
112
  @queue.pop.call(r) if @queue.size > 0
107
- elsif session_header_and_content.content[:event_name] # If content includes an event_name, it must be a response from an api command
108
- check_for_updated_session(session_header_and_content, hash_content, hash_header)
113
+ elsif @api_request and session_header_and_content.headers[:content_type] == "api/response"
114
+ @queue.pop.call if @queue.size > 0
115
+ elsif session_header_and_content.content.class == Hash
116
+ if session_header_and_content.content[:event_name] # If content includes an event_name, it must be a response from an api command
117
+ check_for_updated_session(session_header_and_content, hash_content, hash_header)
118
+ end
109
119
  else
110
120
  update_state_machine(session_header_and_content)
111
121
  end
@@ -1,3 +1,3 @@
1
1
  module FSR
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -0,0 +1,48 @@
1
+ require 'spec/helper'
2
+ require 'fsr/listener/header_and_content_response'
3
+
4
+ describe FSL::HeaderAndContentResponse do
5
+ HCR = FSL::HeaderAndContentResponse
6
+
7
+ it "is initializable with 2 hash arguments" do
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
13
+ end
14
+ =begin manveru's future specs
15
+
16
+ it "can be created with headers" do
17
+ hcr = HCR.new(:headers => {:a => 'b', :c => 'd'})
18
+ hcr.headers.should == {:a => 'b', :c => 'd'}
19
+ end
20
+
21
+ it 'strips whitespace around header values' do
22
+ hcr = HCR.new(:headers => {:a => ' b', :c => "d\t\n"})
23
+ hcr.headers.should == {:a => 'b', :c => 'd'}
24
+ end
25
+
26
+ it "returns an empty string if there's no event-name" do
27
+ hcr = HCR.from_raw([""], [""])
28
+ hcr.class.should == HCR
29
+ hcr.event_name.should == ''
30
+ end
31
+
32
+ it "returns the event-name if there is one" do
33
+ hcr = HCR.from_raw([""], ["event-name: foo"])
34
+ hcr.event_name.should == 'foo'
35
+ hcr.class.should == HCR::ParsedContent
36
+ end
37
+
38
+ it "can check for an event name in content" do
39
+ hcr = HCR.new(:content => {:event_name => ' YAY', :stuff => "d"})
40
+ hcr.class.should == HCR
41
+
42
+ hcr.has_event_name?('YAY').should.not == nil
43
+ hcr.content[:event_name] = 'NOES'
44
+ hcr.has_event_name?('YAY').should == false
45
+ end
46
+
47
+ =end
48
+ end
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.3.1
4
+ version: 0.4.0
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-05-18 00:00:00 -05:00
15
+ date: 2009-06-03 00:00:00 -05:00
16
16
  default_executable:
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
@@ -25,90 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: "0"
27
27
  version:
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. 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.strip} from #{exten}\" hangup #Hangup the call 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) {|event| 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) {|event| 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(event) pp event.headers pp event.content[:event_name] end end FSR.start_ies!(IesDemo, :host => \"localhost\", :port => 8021) 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/bridge.rb
53
- - lib/fsr/app/conference.rb
54
- - lib/fsr/app/fifo.rb
55
- - lib/fsr/app/fs_break.rb
56
- - lib/fsr/app/fs_sleep.rb
57
- - lib/fsr/app/hangup.rb
58
- - lib/fsr/app/limit.rb
59
- - lib/fsr/app/log.rb
60
- - lib/fsr/app/play_and_get_digits.rb
61
- - lib/fsr/app/playback.rb
62
- - lib/fsr/app/read.rb
63
- - lib/fsr/app/set.rb
64
- - lib/fsr/app/speak.rb
65
- - lib/fsr/app/transfer.rb
66
- - lib/fsr/app/uuid_dump.rb
67
- - lib/fsr/app/uuid_getvar.rb
68
- - lib/fsr/app/uuid_setvar.rb
69
- - lib/fsr/cmd.rb
70
- - lib/fsr/cmd/calls.rb
71
- - lib/fsr/cmd/fsctl.rb
72
- - lib/fsr/cmd/originate.rb
73
- - lib/fsr/cmd/sofia.rb
74
- - lib/fsr/cmd/sofia/profile.rb
75
- - lib/fsr/cmd/sofia/status.rb
76
- - lib/fsr/cmd/sofia_contact.rb
77
- - lib/fsr/cmd/status.rb
78
- - lib/fsr/command_socket.rb
79
- - lib/fsr/database.rb
80
- - lib/fsr/database/call_limit.rb
81
- - lib/fsr/database/core.rb
82
- - lib/fsr/database/sofia_reg_external.rb
83
- - lib/fsr/database/sofia_reg_internal.rb
84
- - lib/fsr/database/voicemail_default.rb
85
- - lib/fsr/event_socket.rb
86
- - lib/fsr/fake_socket.rb
87
- - lib/fsr/listener.rb
88
- - lib/fsr/listener/header_and_content_response.rb
89
- - lib/fsr/listener/inbound.rb
90
- - lib/fsr/listener/inbound/event.rb
91
- - lib/fsr/listener/outbound.rb
92
- - lib/fsr/model/call.rb
93
- - lib/fsr/version.rb
94
- - tasks/authors.rake
95
- - tasks/bacon.rake
96
- - tasks/changelog.rake
97
- - tasks/copyright.rake
98
- - tasks/gem.rake
99
- - tasks/gem_installer.rake
100
- - tasks/install_dependencies.rake
101
- - tasks/manifest.rake
102
- - tasks/rcov.rake
103
- - tasks/release.rake
104
- - tasks/reversion.rake
105
- - tasks/setup.rake
106
- - tasks/spec.rake
107
- - tasks/yard.rake
108
- - spec/helper.rb
109
- has_rdoc: false
110
- homepage: http://code.rubyists.com/projects/fs
111
- post_install_message: |
28
+ description: &id001 |
112
29
  =========================================================
113
30
  FreeSWITCHeR
114
31
  Copyright (c) 2009 The Rubyists (Jayson Vaughn, Tj Vanderpoel, Michael Fellinger, Kevin Berry)
@@ -148,8 +65,12 @@ post_install_message: |
148
65
  answer do
149
66
  FSR::Log.info "***Reading DTMF from #{exten}"
150
67
  read("/home/freeswitch/freeswitch/sounds/music/8000/sweet.wav", 4, 10, "input", 7000) do |read_var|
151
- FSR::Log.info "***Success, grabbed #{read_var.strip} from #{exten}"
152
- hangup #Hangup the call
68
+ FSR::Log.info "***Success, grabbed #{read_var.strip} from #{exten}"
69
+ # Tell the caller what they entered
70
+ speak("Got the DTMF of: #{read_var}") do
71
+ #Hangup the call
72
+ hangup
73
+ end
153
74
  end
154
75
  end
155
76
 
@@ -229,6 +150,91 @@ post_install_message: |
229
150
  Home page at http://code.rubyists.com/projects/fs
230
151
  #rubyists on FreeNode
231
152
 
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/command_socket.rb
203
+ - lib/fsr/database.rb
204
+ - lib/fsr/database/call_limit.rb
205
+ - lib/fsr/database/core.rb
206
+ - lib/fsr/database/sofia_reg_external.rb
207
+ - lib/fsr/database/sofia_reg_internal.rb
208
+ - lib/fsr/database/voicemail_default.rb
209
+ - lib/fsr/event_socket.rb
210
+ - lib/fsr/fake_socket.rb
211
+ - lib/fsr/listener.rb
212
+ - lib/fsr/listener/header_and_content_response.rb
213
+ - lib/fsr/listener/inbound.rb
214
+ - lib/fsr/listener/inbound/event.rb
215
+ - lib/fsr/listener/outbound.rb
216
+ - lib/fsr/model/call.rb
217
+ - lib/fsr/version.rb
218
+ - tasks/authors.rake
219
+ - tasks/bacon.rake
220
+ - tasks/changelog.rake
221
+ - tasks/copyright.rake
222
+ - tasks/gem.rake
223
+ - tasks/gem_installer.rake
224
+ - tasks/install_dependencies.rake
225
+ - tasks/manifest.rake
226
+ - tasks/rcov.rake
227
+ - tasks/release.rake
228
+ - tasks/reversion.rake
229
+ - tasks/setup.rake
230
+ - tasks/spec.rake
231
+ - tasks/yard.rake
232
+ - spec/helper.rb
233
+ has_rdoc: true
234
+ homepage: http://code.rubyists.com/projects/fs
235
+ licenses: []
236
+
237
+ post_install_message: *id001
232
238
  rdoc_options: []
233
239
 
234
240
  require_paths:
@@ -248,9 +254,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
248
254
  requirements: []
249
255
 
250
256
  rubyforge_project: freeswitcher
251
- rubygems_version: 1.3.1
257
+ rubygems_version: 1.3.3
252
258
  signing_key:
253
- specification_version: 2
259
+ specification_version: 3
254
260
  summary: A library for interacting with the "FreeSWITCH":http://freeswitch.org telephony platform
255
261
  test_files:
256
262
  - spec/fsr/app.rb
@@ -273,6 +279,7 @@ test_files:
273
279
  - spec/fsr/cmd/sofia.rb
274
280
  - spec/fsr/cmd/sofia/profile.rb
275
281
  - spec/fsr/listener.rb
282
+ - spec/fsr/listener/header_and_content_response.rb
276
283
  - spec/fsr/listener/inbound.rb
277
284
  - spec/fsr/listener/outbound.rb
278
285
  - spec/fsr/loading.rb