freec 0.2.6 → 0.2.8
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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +39 -0
- data/LICENSE.txt +21 -0
- data/README.rdoc +10 -17
- data/Rakefile +4 -40
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/freec.gemspec +30 -0
- data/lib/freec/version.rb +3 -0
- data/lib/freec.rb +9 -10
- data/lib/freec_base.rb +45 -46
- data/lib/freeswitch_applications.rb +19 -19
- metadata +82 -35
- data/spec/data/event.rb +0 -56
- data/spec/data/event_with_body.rb +0 -25
- data/spec/event_parser_spec.rb +0 -84
- data/spec/freec_base_spec.rb +0 -213
- data/spec/freeswitch_applications_spec.rb +0 -128
- data/spec/spec_helper.rb +0 -12
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: df2fa8a96256734d308ad216676ff07f879d6266
|
4
|
+
data.tar.gz: 7408f1183efa35c140a83515a9d8e40078823980
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d6ade697846f0b75566dedf0c0ccc3d0ea78895e8ffe4f42265544c6a8d5620678563717ad22fdf387b18dcfbefa859d4dc1ca674e892d85ec5612b43ff3472
|
7
|
+
data.tar.gz: 4283bc10510063f7a100a5a7bb7025f18b7932506e9b6bc978b1962192b49bd6b10a0cea97c42a595caf6a79d88411b07ab2c99869cd15221e10762412f922a5
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
freec (0.2.8)
|
5
|
+
daemons (~> 1.2.4)
|
6
|
+
gserver (~> 0.0.1)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
daemons (1.2.4)
|
12
|
+
diff-lcs (1.3)
|
13
|
+
gserver (0.0.1)
|
14
|
+
rake (10.5.0)
|
15
|
+
rspec (3.5.0)
|
16
|
+
rspec-core (~> 3.5.0)
|
17
|
+
rspec-expectations (~> 3.5.0)
|
18
|
+
rspec-mocks (~> 3.5.0)
|
19
|
+
rspec-core (3.5.4)
|
20
|
+
rspec-support (~> 3.5.0)
|
21
|
+
rspec-expectations (3.5.0)
|
22
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
23
|
+
rspec-support (~> 3.5.0)
|
24
|
+
rspec-mocks (3.5.0)
|
25
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
26
|
+
rspec-support (~> 3.5.0)
|
27
|
+
rspec-support (3.5.0)
|
28
|
+
|
29
|
+
PLATFORMS
|
30
|
+
ruby
|
31
|
+
|
32
|
+
DEPENDENCIES
|
33
|
+
bundler (~> 1.14)
|
34
|
+
freec!
|
35
|
+
rake (~> 10.0)
|
36
|
+
rspec (~> 3.0)
|
37
|
+
|
38
|
+
BUNDLED WITH
|
39
|
+
1.14.4
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Jan Kubr
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -6,20 +6,20 @@ Freec is a framework you can build voice applications on top of. It makes use of
|
|
6
6
|
|
7
7
|
= Usage
|
8
8
|
1. Install Freeswitch and point a chosen extension to the IP where your app will run:
|
9
|
-
|
9
|
+
|
10
10
|
<extension name="telfa">
|
11
11
|
<condition field="destination_number" expression="^.*$">
|
12
12
|
<action application="socket" data="127.0.0.1:8084 async full" />
|
13
13
|
</condition>
|
14
14
|
</extension>
|
15
|
-
|
15
|
+
|
16
16
|
2. Create a file with the main class of your application (e.g. Jukebox) and make it a subclass of Freec. Name the file according to the class name (e.g. jukebox.rb). Implement
|
17
17
|
a step method instructions for which will follow. Simple example:
|
18
|
-
|
18
|
+
|
19
19
|
#jukebox.rb
|
20
20
|
require 'rubygems'
|
21
21
|
require 'freec'
|
22
|
-
class Jukebox <
|
22
|
+
class Jukebox < FreecBase
|
23
23
|
def step
|
24
24
|
@step ||= 1
|
25
25
|
case @step
|
@@ -34,10 +34,12 @@ Freec is a framework you can build voice applications on top of. It makes use of
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
start
|
38
|
+
|
37
39
|
3. Run it with:
|
38
40
|
ruby jukebox.rb
|
39
41
|
|
40
|
-
= How does it work
|
42
|
+
= How does it work
|
41
43
|
The step method is called after each even is finished (e.g. file is played, recording is finished). Here is what you can do:
|
42
44
|
* read call variables from the hash in call_vars
|
43
45
|
* call one of the following methods (Freeswitch apps):
|
@@ -49,25 +51,16 @@ The step method is called after each even is finished (e.g. file is played, reco
|
|
49
51
|
* set_variable(name, value)
|
50
52
|
* any other via execute_app(app_name, params)
|
51
53
|
If you return nil or false from the step method, the call will be hungup.
|
52
|
-
|
54
|
+
|
53
55
|
= Cool stuff
|
54
56
|
* Your application's main file as well as everything you might have in the lib directory will be reloaded on each step in development mode.
|
55
|
-
* Passing -d will daemonize the application and automatically implies production mode.
|
57
|
+
* Passing -d will daemonize the application and automatically implies production mode.
|
56
58
|
* The log directory contains the log file and the pid file.
|
57
59
|
* There is a hidden feature.
|
58
60
|
|
59
61
|
= Stinks?
|
60
62
|
What Freec can do at the moment was enough for me to implement Telfa (http://telfapbx.com). If it doesn't fit your needs, you can:
|
61
|
-
1. Complain to
|
63
|
+
1. Complain to mail@jankubr.com .
|
62
64
|
2. Fork it and change yourself.
|
63
65
|
3. Check Liverpie (http://www.liverpie.com/) or Telegraph (http://code.google.com/p/telegraph/), Freec is inspired by them.
|
64
66
|
4. Write yours :-)
|
65
|
-
|
66
|
-
= License
|
67
|
-
Copyright © 2009 Jan Kubr
|
68
|
-
|
69
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
70
|
-
|
71
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
72
|
-
|
73
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1,42 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
3
|
|
4
|
-
|
5
|
-
task :clean do |t|
|
6
|
-
FileUtils.rm_rf "tmp"
|
7
|
-
FileUtils.rm_rf "pkg"
|
8
|
-
end
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
5
|
|
10
|
-
|
11
|
-
s.name = "freec"
|
12
|
-
s.version = '0.2.6'
|
13
|
-
s.author = "Jan Kubr"
|
14
|
-
s.email = "mail@jankubr.com"
|
15
|
-
s.homepage = "http://github.com/jankubr/freec"
|
16
|
-
s.platform = Gem::Platform::RUBY
|
17
|
-
s.summary = "The layer between your Ruby voice app and FreeSWITCH."
|
18
|
-
s.files = FileList["README*",
|
19
|
-
"Rakefile",
|
20
|
-
"{lib,spec}/**/*"].to_a
|
21
|
-
s.require_path = "lib"
|
22
|
-
s.rubyforge_project = "freec"
|
23
|
-
s.has_rdoc = false
|
24
|
-
s.extra_rdoc_files = FileList["README*"].to_a
|
25
|
-
s.rdoc_options << '--line-numbers' << '--inline-source'
|
26
|
-
s.add_dependency "daemons"
|
27
|
-
s.add_development_dependency 'rspec', '> 2.0.1'
|
28
|
-
end
|
29
|
-
|
30
|
-
desc "Generate a gemspec file"
|
31
|
-
task :gemspec do
|
32
|
-
File.open("#{spec.name}.gemspec", 'w') do |f|
|
33
|
-
f.write spec.to_ruby
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
require 'rspec/core/rake_task'
|
38
|
-
|
39
|
-
desc "Run all specs"
|
40
|
-
RSpec::Core::RakeTask.new(:spec) do |t|
|
41
|
-
t.pattern = FileList['spec/**/*.rb']
|
42
|
-
end
|
6
|
+
task default: :spec
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "freec"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/freec.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'freec/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "freec"
|
8
|
+
spec.version = Freec::VERSION
|
9
|
+
spec.authors = ["Jan Kubr"]
|
10
|
+
spec.email = ["mail@jankubr.com"]
|
11
|
+
|
12
|
+
spec.summary = "The layer between your Ruby voice app and FreeSWITCH."
|
13
|
+
spec.description = "The layer between your Ruby voice app and FreeSWITCH."
|
14
|
+
spec.homepage = "http://github.com/jankubr/freec"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_runtime_dependency 'gserver', '~> 0.0.1'
|
25
|
+
spec.add_runtime_dependency 'daemons', '~> 1.2.4'
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
28
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
29
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
30
|
+
end
|
data/lib/freec.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'freec/version'
|
1
2
|
lib_dir = File.dirname(__FILE__)
|
2
3
|
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
3
|
-
require
|
4
|
+
require 'gserver'
|
5
|
+
require 'freec_base'
|
4
6
|
require 'listener'
|
5
7
|
|
6
8
|
require 'fileutils'
|
@@ -9,7 +11,7 @@ require 'daemons/daemonize'
|
|
9
11
|
include Daemonize
|
10
12
|
|
11
13
|
def freec_app_file_name
|
12
|
-
$0.sub(/\.[^\.]*$/, '')
|
14
|
+
$0.sub(/\.[^\.]*$/, '')
|
13
15
|
end
|
14
16
|
|
15
17
|
def freec_app_class_name
|
@@ -21,7 +23,7 @@ def freec_app_log_dir
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def create_freec_app_log_dir
|
24
|
-
FileUtils.mkdir_p(freec_app_log_dir)
|
26
|
+
FileUtils.mkdir_p(freec_app_log_dir)
|
25
27
|
end
|
26
28
|
|
27
29
|
def freec_app_log_file
|
@@ -44,9 +46,9 @@ def freec_app_configuration_file
|
|
44
46
|
"#{ROOT}/config/config.yml"
|
45
47
|
end
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
ROOT = File.expand_path(File.dirname($0))
|
50
|
+
ENVIRONMENT = ARGV[0] == '-d' ? 'production' : 'development'
|
51
|
+
def start
|
50
52
|
create_freec_app_log_dir
|
51
53
|
load_freec_app_config
|
52
54
|
if ARGV[0] == '-d'
|
@@ -59,9 +61,6 @@ unless defined?(TEST)
|
|
59
61
|
server = Listener.new(freec_app_class_name, @@config)
|
60
62
|
server.audit = true
|
61
63
|
server.start
|
62
|
-
|
63
|
-
break if server.stopped?
|
64
|
-
sleep(1)
|
65
|
-
end
|
64
|
+
server.join
|
66
65
|
end
|
67
66
|
end
|
data/lib/freec_base.rb
CHANGED
@@ -1,28 +1,27 @@
|
|
1
1
|
require 'gserver'
|
2
|
-
require 'rubygems'
|
3
2
|
require 'uri'
|
4
3
|
|
5
4
|
require 'tools'
|
6
|
-
require
|
7
|
-
require
|
5
|
+
require 'freeswitch_applications'
|
6
|
+
require 'call_variables'
|
8
7
|
|
9
|
-
class
|
8
|
+
class FreecBase
|
10
9
|
include FreeswitchApplications
|
11
10
|
include CallVariables
|
12
|
-
|
11
|
+
|
13
12
|
attr_reader :call_vars, :event_body, :log, :config
|
14
|
-
|
13
|
+
|
15
14
|
def initialize(io, log, config) #:nodoc:
|
16
15
|
@call_vars = {}
|
17
16
|
@want_events_from = []
|
18
17
|
@last_app_executed = 'initial_step'
|
19
|
-
@io = io
|
18
|
+
@io = io
|
20
19
|
@log = log
|
21
20
|
@config = config
|
22
21
|
end
|
23
|
-
|
22
|
+
|
24
23
|
def handle_call #:nodoc:
|
25
|
-
call_initialization
|
24
|
+
call_initialization
|
26
25
|
loop do
|
27
26
|
subscribe_to_new_channel_events
|
28
27
|
if last_event_dtmf? && respond_to?(:on_dtmf)
|
@@ -38,7 +37,7 @@ class Freec
|
|
38
37
|
hangup unless @io.closed?
|
39
38
|
send_and_read('exit') unless @io.closed?
|
40
39
|
end
|
41
|
-
|
40
|
+
|
42
41
|
def wait_for(key, value)
|
43
42
|
@waiting_for_key = key && key.to_sym
|
44
43
|
@waiting_for_value = value
|
@@ -46,13 +45,13 @@ class Freec
|
|
46
45
|
|
47
46
|
def reset_wait_for
|
48
47
|
wait_for(nil, nil)
|
49
|
-
true
|
50
|
-
end
|
51
|
-
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
52
51
|
def execute_completed?
|
53
52
|
channel_execute_complete? || channel_destroyed_after_bridge? || disconnect_notice?
|
54
53
|
end
|
55
|
-
|
54
|
+
|
56
55
|
private
|
57
56
|
|
58
57
|
def call_initialization
|
@@ -62,17 +61,17 @@ private
|
|
62
61
|
|
63
62
|
def channel_execute_complete?
|
64
63
|
return true if @last_app_executed == 'initial_step'
|
65
|
-
complete = call_vars[:content_type] == 'text/event-plain' &&
|
64
|
+
complete = call_vars[:content_type] == 'text/event-plain' &&
|
66
65
|
call_vars[:event_name] == 'CHANNEL_EXECUTE_COMPLETE' &&
|
67
66
|
@last_app_executed == call_vars[:application]
|
68
67
|
@last_app_executed = nil if complete
|
69
68
|
complete
|
70
69
|
end
|
71
|
-
|
70
|
+
|
72
71
|
def channel_destroyed_after_bridge?
|
73
72
|
call_vars[:application] == 'bridge' && call_vars[:event_name] == 'CHANNEL_DESTROY'
|
74
73
|
end
|
75
|
-
|
74
|
+
|
76
75
|
def disconnect_notice?
|
77
76
|
@io.closed? || call_vars[:content_type] == 'text/disconnect-notice'
|
78
77
|
end
|
@@ -81,7 +80,7 @@ private
|
|
81
80
|
send(callback_name, *args) if respond_to?(callback_name)
|
82
81
|
rescue StandardError => e
|
83
82
|
log.error e.message
|
84
|
-
e.backtrace.each {|trace_line| log.error(trace_line)}
|
83
|
+
e.backtrace.each {|trace_line| log.error(trace_line)}
|
85
84
|
end
|
86
85
|
|
87
86
|
def reload_application_code
|
@@ -89,7 +88,7 @@ private
|
|
89
88
|
load($0)
|
90
89
|
lib_dir = "#{ROOT}/lib"
|
91
90
|
return unless File.exist?(lib_dir)
|
92
|
-
Dir.open(lib_dir).each do |file|
|
91
|
+
Dir.open(lib_dir).each do |file|
|
93
92
|
full_file_name = File.join(lib_dir, file)
|
94
93
|
next unless File.file?(full_file_name)
|
95
94
|
load(full_file_name)
|
@@ -100,62 +99,62 @@ private
|
|
100
99
|
send_and_read('connect')
|
101
100
|
parse_response
|
102
101
|
end
|
103
|
-
|
102
|
+
|
104
103
|
def subscribe_to_events
|
105
104
|
send_and_read('events plain all')
|
106
|
-
parse_response
|
107
|
-
send_and_read("filter Unique-ID #{@unique_id}")
|
108
|
-
parse_response
|
109
|
-
send_and_read("divert_events on")
|
105
|
+
parse_response
|
106
|
+
send_and_read("filter Unique-ID #{@unique_id}")
|
107
|
+
parse_response
|
108
|
+
send_and_read("divert_events on")
|
110
109
|
parse_response
|
111
110
|
end
|
112
|
-
|
111
|
+
|
113
112
|
def subscribe_to_new_channel_events
|
114
113
|
return unless call_vars[:event_name] == 'CHANNEL_BRIDGE'
|
115
114
|
@want_events_from << call_vars[:other_leg_unique_id]
|
116
115
|
send_and_read("filter Unique-ID #{call_vars[:other_leg_unique_id]}")
|
117
116
|
end
|
118
|
-
|
117
|
+
|
119
118
|
def waiting_for_this_response?
|
120
119
|
@waiting_for_key && @waiting_for_value && call_vars[@waiting_for_key] == @waiting_for_value
|
121
120
|
end
|
122
|
-
|
121
|
+
|
123
122
|
def last_event_dtmf?
|
124
123
|
call_vars[:content_type] == 'text/event-plain' && call_vars[:event_name] == 'DTMF'
|
125
124
|
end
|
126
|
-
|
125
|
+
|
127
126
|
def send_data(data)
|
128
127
|
log.debug "Sending: #{data}"
|
129
128
|
@io.write("#{data}\n\n") unless disconnect_notice?
|
130
129
|
end
|
131
|
-
|
130
|
+
|
132
131
|
def send_and_read(data)
|
133
132
|
send_data(data)
|
134
133
|
read_response
|
135
134
|
end
|
136
|
-
|
135
|
+
|
137
136
|
def read_and_parse_response
|
138
137
|
my_event = false
|
139
138
|
until my_event
|
140
139
|
read_response
|
141
140
|
my_event = parse_response
|
142
|
-
end
|
141
|
+
end
|
143
142
|
end
|
144
|
-
|
143
|
+
|
145
144
|
def read_response
|
146
145
|
return if disconnect_notice?
|
147
146
|
read_response_info
|
148
147
|
read_event_header
|
149
148
|
read_event_body
|
150
149
|
end
|
151
|
-
|
150
|
+
|
152
151
|
def read_response_info
|
153
152
|
@response = ''
|
154
153
|
begin
|
155
154
|
@response += read_line_from_io
|
156
|
-
end until @response[-2..-1] == "\n\n"
|
155
|
+
end until @response[-2..-1] == "\n\n"
|
157
156
|
end
|
158
|
-
|
157
|
+
|
159
158
|
def read_event_header
|
160
159
|
header_length = @response.sub(/^Content-Length: ([0-9]+)$.*/m, '\1').to_i
|
161
160
|
return if header_length == 0
|
@@ -163,23 +162,23 @@ private
|
|
163
162
|
begin
|
164
163
|
header += read_line_from_io
|
165
164
|
end until header[-2..-1] == "\n\n"
|
166
|
-
@response += header
|
165
|
+
@response += header
|
167
166
|
end
|
168
|
-
|
167
|
+
|
169
168
|
def read_event_body
|
170
169
|
body_length = @response.sub(/^Content-Length.*^Content-Length: ([0-9]+)$.*/m, '\1').to_i
|
171
170
|
return if body_length == 0
|
172
171
|
body = ''
|
173
|
-
begin
|
172
|
+
begin
|
174
173
|
body += read_block_from_io(body_length)
|
175
174
|
end until body.length == body_length
|
176
|
-
@response += body
|
175
|
+
@response += body
|
177
176
|
end
|
178
|
-
|
177
|
+
|
179
178
|
def parse_response
|
180
179
|
hash = {}
|
181
180
|
if @response =~ /^Content-Length.*^Content-Length/m
|
182
|
-
@event_body = @response.sub(/.*\n\n.*\n\n(.*)/m, '\1').strip
|
181
|
+
@event_body = @response.sub(/.*\n\n.*\n\n(.*)/m, '\1').strip
|
183
182
|
else
|
184
183
|
@event_body = nil
|
185
184
|
end
|
@@ -198,21 +197,21 @@ private
|
|
198
197
|
@response = ''
|
199
198
|
true
|
200
199
|
end
|
201
|
-
|
200
|
+
|
202
201
|
def read_line_from_io
|
203
202
|
line = @io.gets
|
204
203
|
raise io_disconnected_message unless line
|
205
204
|
line
|
206
205
|
end
|
207
|
-
|
206
|
+
|
208
207
|
def read_block_from_io(length)
|
209
208
|
block = @io.read(length)
|
210
209
|
raise io_disconnected_message unless block
|
211
210
|
block
|
212
211
|
end
|
213
|
-
|
212
|
+
|
214
213
|
def io_disconnected_message
|
215
214
|
"IO disconnected - FreeSWITCH crashed?"
|
216
215
|
end
|
217
|
-
|
218
|
-
end
|
216
|
+
|
217
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module FreeswitchApplications
|
2
|
-
|
2
|
+
|
3
3
|
# Answers the call.
|
4
4
|
def answer
|
5
5
|
execute_app('answer')
|
6
6
|
end
|
7
7
|
|
8
8
|
# Plays the file in file_name
|
9
|
-
# file_name is either an absolute path or path relative
|
9
|
+
# file_name is either an absolute path or path relative
|
10
10
|
# to the sound_prefix variable set in Freeswitch's vars.xml configuration file.
|
11
11
|
def playback(file_name)
|
12
12
|
execute_app('playback', file_name)
|
@@ -16,36 +16,36 @@ module FreeswitchApplications
|
|
16
16
|
def spell(string)
|
17
17
|
execute_app('phrase', "spell,#{string}")
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
# Says the given string
|
21
21
|
# Don't forget to set up your TTS engine and set variables tts_engine and tts_voice accordingly
|
22
22
|
# See e.g.: http://wiki.freeswitch.org/wiki/Mod_flite
|
23
23
|
def speak(string)
|
24
24
|
execute_app('speak', string)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
# Bridges the call to the given number or numbers (this param can be a number or an array of numbers).
|
28
28
|
def bridge(number_or_numbers, options = {})
|
29
29
|
number_or_numbers = number_or_numbers.join(",") if number_or_numbers.is_a?(Array)
|
30
30
|
execute_app("bridge", "#{number_or_numbers}")
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
# Transfers the call to the given extension
|
34
34
|
def transfer(extension)
|
35
35
|
execute_app("transfer", "#{extension}")
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
# Records the call to a file with the given file_name
|
39
|
-
# file_name is either an absolute path or path relative
|
39
|
+
# file_name is either an absolute path or path relative
|
40
40
|
# to the sound_prefix variable set in Freeswitch's vars.xml configuration file.
|
41
41
|
#
|
42
42
|
# Options:
|
43
43
|
# * <tt>:time_limit_secs</tt> overrides the default timeout, which is 600 seconds
|
44
44
|
def record(file_name, options = {})
|
45
|
-
options = {:
|
45
|
+
options = {time_limit_secs: 600}.merge(options) #no reverse_merge, no fun :-)
|
46
46
|
execute_app("record", "#{file_name} #{options[:time_limit_secs]}")
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
# Plays the file in file_name and reads input (key presses) from the user.
|
50
50
|
#
|
51
51
|
# Options:
|
@@ -55,10 +55,10 @@ module FreeswitchApplications
|
|
55
55
|
# * <tt>:min and :max</tt> options to override the default maximum and minimum of characters that will be read (both default to 1)
|
56
56
|
def read(file_name, options = {})
|
57
57
|
options[:terminators] = [options[:terminators]] if options[:terminators].is_a?(String)
|
58
|
-
options = {:
|
58
|
+
options = {timeout: 10, variable: 'input', min: 1, max: 1, terminators: ['#']}.merge(options)
|
59
59
|
execute_app("read", "#{options[:min]} #{options[:max]} #{file_name} #{options[:variable]} #{options[:timeout] * 1000} #{options[:terminators].join(',')}")
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
# Starts recording the call in file in file_name
|
63
63
|
#
|
64
64
|
def start_recording(file_name)
|
@@ -66,11 +66,11 @@ module FreeswitchApplications
|
|
66
66
|
end
|
67
67
|
|
68
68
|
# Stops recording the call in file in file_name
|
69
|
-
#
|
69
|
+
#
|
70
70
|
def stop_recording(file_name)
|
71
71
|
execute_app('stop_record_session', file_name)
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
# Sets a variable with the give name to the given value.
|
75
75
|
def set_variable(name, value)
|
76
76
|
execute_app('set', "#{name}=#{value}")
|
@@ -78,9 +78,9 @@ module FreeswitchApplications
|
|
78
78
|
|
79
79
|
# Hangs up the call.
|
80
80
|
def hangup
|
81
|
-
execute_app('hangup')
|
82
|
-
end
|
83
|
-
|
81
|
+
execute_app('hangup', 'USER_BUSY')
|
82
|
+
end
|
83
|
+
|
84
84
|
# Executes an app using the sendmsg command of Freeswitch.
|
85
85
|
# Use this if there is no method for the application you want to run.
|
86
86
|
#
|
@@ -88,7 +88,7 @@ module FreeswitchApplications
|
|
88
88
|
# * <tt>app</tt> is the application name
|
89
89
|
# * <tt>pars</tt> is a string of arguments of the app
|
90
90
|
# * <tt>lock</tt> can be set to false so Freeswitch won't wait for this app to finish before running the next one
|
91
|
-
def execute_app(app, pars = '', lock = true, unique_id = nil)
|
91
|
+
def execute_app(app, pars = '', lock = true, unique_id = nil)
|
92
92
|
@last_app_executed = app
|
93
93
|
unique_id = @unique_id unless unique_id
|
94
94
|
cmd = "sendmsg #{unique_id}"
|
@@ -97,5 +97,5 @@ module FreeswitchApplications
|
|
97
97
|
cmd << "\nexecute-app-arg: #{pars}" unless pars.blank?
|
98
98
|
cmd << "\nevent-lock:#{lock}"
|
99
99
|
send_data cmd
|
100
|
-
end
|
101
|
-
end
|
100
|
+
end
|
101
|
+
end
|