librevox 0.1.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +12 -4
- data/TODO +9 -8
- data/lib/librevox.rb +22 -5
- data/lib/librevox/applications.rb +139 -20
- data/lib/librevox/listener/base.rb +17 -13
- data/lib/librevox/listener/outbound.rb +16 -23
- data/librevox.gemspec +2 -2
- data/spec/librevox/listener.rb +26 -1
- data/spec/librevox/listener/spec_outbound.rb +8 -8
- data/spec/librevox/spec_applications.rb +115 -24
- metadata +2 -2
data/README.md
CHANGED
@@ -37,8 +37,8 @@ techniques:
|
|
37
37
|
require 'librevox'
|
38
38
|
|
39
39
|
class MyInbound < Librevox::Listener::Inbound
|
40
|
-
def on_event
|
41
|
-
puts "Got event: #{
|
40
|
+
def on_event e
|
41
|
+
puts "Got event: #{e.content[:event_name]}"
|
42
42
|
end
|
43
43
|
|
44
44
|
# You can add a hook for a certain event:
|
@@ -46,6 +46,12 @@ techniques:
|
|
46
46
|
# It is instance_eval'ed, so you can use your instance methods etc:
|
47
47
|
do_something
|
48
48
|
end
|
49
|
+
|
50
|
+
# If your hook block takes an argument, a Librevox::Response object for
|
51
|
+
# the given event is passed on:
|
52
|
+
event :channel_bridge do |e|
|
53
|
+
...
|
54
|
+
end
|
49
55
|
|
50
56
|
def do_something
|
51
57
|
...
|
@@ -64,15 +70,17 @@ but it only receives events related to that given session.
|
|
64
70
|
### Dialplan
|
65
71
|
|
66
72
|
When a call is made and Freeswitch connects to the outbound event listener,
|
67
|
-
|
73
|
+
`session_initiated` is called. This is where you set up your dialplan:
|
68
74
|
|
69
|
-
|
75
|
+
def session_initiated
|
70
76
|
answer
|
71
77
|
set "some_var", "some value"
|
72
78
|
playback "path/to/file"
|
73
79
|
hangup
|
74
80
|
end
|
75
81
|
|
82
|
+
All channel variables are available as a hash named `session`.
|
83
|
+
|
76
84
|
When using applications that expect a reply, such as `play_and_get_digits`,
|
77
85
|
you have to use callbacks to read the value, as the function itself returns
|
78
86
|
immediately due to the async nature of EventMachine:
|
data/TODO
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
+
- inbound listener: only subscribe to events w/ hooks, unless `events :all`
|
2
|
+
specified
|
3
|
+
|
4
|
+
- map more commands/applications.
|
5
|
+
|
6
|
+
- check command/application input and raise ArgumentError, possibly.
|
7
|
+
|
8
|
+
- filter events
|
9
|
+
|
1
10
|
- the execute_app/run_app business might be done better, simpler. e.g.
|
2
11
|
having to pass the block for every command becomes a bit tedious.
|
3
12
|
|
4
13
|
- move test suite from bacon -> test/unit.
|
5
14
|
|
6
|
-
- map more commands/applications.
|
7
|
-
|
8
15
|
- test how this works in async mode - I imagine that it might mess with
|
9
16
|
@command_queue
|
10
17
|
|
@@ -12,13 +19,7 @@
|
|
12
19
|
do e.g. originate("user/coltrane", :endpoint => bridge("user/davis")) and
|
13
20
|
it would translate to "originate user/coltrane &bridge(user/davis)"
|
14
21
|
|
15
|
-
- add logger.
|
16
|
-
|
17
|
-
- check command/application input and raise ArgumentError.
|
18
|
-
|
19
22
|
- maybe let commands handle the response, so something useful could be returned?
|
20
23
|
|
21
24
|
- possibly catch all exceptions, so everything doesn't die? or should this be
|
22
25
|
be the users responsibilty?
|
23
|
-
|
24
|
-
- filter events
|
data/lib/librevox.rb
CHANGED
@@ -1,9 +1,27 @@
|
|
1
|
+
require 'logger'
|
1
2
|
require 'eventmachine'
|
2
3
|
require 'librevox/listener/inbound'
|
3
4
|
require 'librevox/listener/outbound'
|
4
5
|
|
5
6
|
module Librevox
|
6
|
-
VERSION = "0.
|
7
|
+
VERSION = "0.2"
|
8
|
+
|
9
|
+
def self.options
|
10
|
+
@options ||= {
|
11
|
+
:log_file => STDOUT,
|
12
|
+
:log_level => Logger::INFO
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.logger
|
17
|
+
@logger ||= logger!
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.logger!
|
21
|
+
logger = Logger.new(options[:log_file])
|
22
|
+
logger.level = options[:log_level]
|
23
|
+
logger
|
24
|
+
end
|
7
25
|
|
8
26
|
# When called without a block, it will start the listener that is passed as
|
9
27
|
# first argument:
|
@@ -17,6 +35,7 @@ module Librevox
|
|
17
35
|
# run OtherListner
|
18
36
|
# end
|
19
37
|
def self.start(klass=nil, args={}, &block)
|
38
|
+
logger.info "Starting Librevox"
|
20
39
|
EM.run {
|
21
40
|
block_given? ? instance_eval(&block) : run(klass, args)
|
22
41
|
}
|
@@ -27,11 +46,9 @@ module Librevox
|
|
27
46
|
port = args.delete(:port)
|
28
47
|
|
29
48
|
if klass.ancestors.include? Librevox::Listener::Inbound
|
30
|
-
port
|
31
|
-
EM.connect host, port, klass, args
|
49
|
+
EM.connect host, port || "8021", klass, args
|
32
50
|
elsif klass.ancestors.include? Librevox::Listener::Outbound
|
33
|
-
port
|
34
|
-
EM.start_server host, port, klass, args
|
51
|
+
EM.start_server host, port || "8084", klass, args
|
35
52
|
end
|
36
53
|
end
|
37
54
|
end
|
@@ -8,10 +8,20 @@ module Librevox
|
|
8
8
|
# Applications *must* pass on any eventual block passed to them.
|
9
9
|
module Applications
|
10
10
|
# Answers an incoming call or session.
|
11
|
-
|
11
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_answer
|
12
|
+
def answer &b
|
12
13
|
execute_app "answer", &b
|
13
14
|
end
|
14
15
|
|
16
|
+
# Make an attended transfer
|
17
|
+
# @example
|
18
|
+
# att_xfer("user/davis")
|
19
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_att_xfer
|
20
|
+
# @todo Add support for origination_cancel_key
|
21
|
+
def att_xfer endpoint, &b
|
22
|
+
execute_app "att_xfer", endpoint, &b
|
23
|
+
end
|
24
|
+
|
15
25
|
# Binds an application to the specified call legs.
|
16
26
|
# @example
|
17
27
|
# bind_meta_app :key => 2,
|
@@ -20,28 +30,98 @@ module Librevox
|
|
20
30
|
# :application => "execute_extension",
|
21
31
|
# :parameters => "dx XML features"
|
22
32
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_bind_meta_app
|
23
|
-
def bind_meta_app
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
application = args[:application]
|
28
|
-
parameters = args[:parameters] ? "::#{args[:parameters]}" : ""
|
29
|
-
|
30
|
-
arg_string = "%s %s %s %s%s" % [key, listen_to, respond_on, application,
|
31
|
-
parameters]
|
33
|
+
def bind_meta_app args={}, &b
|
34
|
+
arg_string =
|
35
|
+
args.values_at(:key, :listen_to, :respond_on, :application).join(" ")
|
36
|
+
arg_string += "::#{args[:parameters]}" if args[:parameters]
|
32
37
|
|
33
38
|
execute_app "bind_meta_app", arg_string, &b
|
34
39
|
end
|
35
40
|
|
36
|
-
|
41
|
+
|
42
|
+
# Bridges an incoming call to an endpoint, optionally taking an array of
|
43
|
+
# channel variables to set. If given an array of arrays, each contained
|
44
|
+
# array of endpoints will be called simultaneously, with the next array
|
45
|
+
# of endpoints as failover. See the examples below for different constructs
|
46
|
+
# and the callstring it sends to FreeSWITCH.
|
37
47
|
# @example
|
38
48
|
# bridge "user/coltrane", "user/backup-office"
|
49
|
+
# #=> user/coltrane,user/backup-office
|
50
|
+
# @example With channel variables
|
51
|
+
# bridge "user/coltrane", "user/backup-office", :some_var => "value"
|
52
|
+
# #=> {some_var=value}user/coltrane,user/backup-office
|
53
|
+
# @example With failover
|
54
|
+
# bridge ['user/coltrane', 'user/davis'], ['user/sun-ra', 'user/taylor']
|
55
|
+
# #=> user/coltrane,user/davis|user/sun-ra,user/taylor
|
39
56
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_bridgecall
|
40
|
-
def bridge
|
41
|
-
|
57
|
+
def bridge *args, &b
|
58
|
+
variables = if args.last.is_a? Hash
|
59
|
+
# We need to sort the key/value pairs to facilitate testing.
|
60
|
+
# This can be removed once 1.8-compat is dropped.
|
61
|
+
key_value_pairs = args.pop.sort {|x,y| x.to_s <=> y.to_s}
|
62
|
+
key_value_pairs.map! {|k,v| "#{k}=#{v}"}
|
63
|
+
"{#{key_value_pairs.join(",")}}"
|
64
|
+
else
|
65
|
+
""
|
66
|
+
end
|
67
|
+
|
68
|
+
endpoints = if args.first.is_a? Array
|
69
|
+
args.map {|e| e.join(",")}.join("|")
|
70
|
+
else
|
71
|
+
args.join ","
|
72
|
+
end
|
73
|
+
|
74
|
+
execute_app "bridge", variables + endpoints, &b
|
75
|
+
end
|
76
|
+
|
77
|
+
# Deflect a call by sending a REFER. Takes a SIP URI as argument, rerouting
|
78
|
+
# the call to that SIP URI.
|
79
|
+
#
|
80
|
+
# Beware that REFER only can be used on established calls. If a call hasn't
|
81
|
+
# been established with e.g. the {#answer} application, you should use
|
82
|
+
# {#redirect} instead.
|
83
|
+
# @example
|
84
|
+
# deflect "sip:miles@davis.com"
|
85
|
+
# @see #redirect
|
86
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_deflect
|
87
|
+
def deflect uri, &b
|
88
|
+
execute_app "deflect", uri, &b
|
89
|
+
end
|
90
|
+
|
91
|
+
# Exports a channel variable from the A leg to the B leg. Variables and
|
92
|
+
# their values will be replicated in any new channels created from the one
|
93
|
+
# export was called.
|
94
|
+
#
|
95
|
+
# Set :local => false if the variable should only be exported to the B-leg.
|
96
|
+
#
|
97
|
+
# @example
|
98
|
+
# export "some_var"
|
99
|
+
# @example Only export to B-leg
|
100
|
+
# export "some_var", :local => false
|
101
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_export
|
102
|
+
def export var, args={}, &b
|
103
|
+
nolocal = args[:local] == false ? "nolocal:" : "" # ugly!!111
|
104
|
+
|
105
|
+
execute_app "export", "#{nolocal}#{var}", &b
|
106
|
+
end
|
107
|
+
|
108
|
+
# Generate TGML tones
|
109
|
+
# @example Generate a 500ms beep at 800Hz
|
110
|
+
# gentones "%(500,0,800)"
|
111
|
+
# @example Generate a DTMF string
|
112
|
+
# gentones "0800500005"
|
113
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_gentones
|
114
|
+
def gentones tgml, &b
|
115
|
+
execute_app "gentones", tgml, &b
|
42
116
|
end
|
43
117
|
|
44
|
-
|
118
|
+
# Hang up current channel
|
119
|
+
# @example
|
120
|
+
# hangup
|
121
|
+
# @example Hang up with a reason
|
122
|
+
# hangup "USER_BUSY"
|
123
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_hangup
|
124
|
+
def hangup cause="", &b
|
45
125
|
execute_app "hangup", cause, &b
|
46
126
|
end
|
47
127
|
|
@@ -55,7 +135,7 @@ module Librevox
|
|
55
135
|
# :timeout => 5000,
|
56
136
|
# :regexp => '\d+'
|
57
137
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_play_and_get_digits
|
58
|
-
def play_and_get_digits
|
138
|
+
def play_and_get_digits file, invalid_file, args={}, &b
|
59
139
|
min = args[:min] || 1
|
60
140
|
max = args[:max] || 2
|
61
141
|
tries = args[:tries] || 3
|
@@ -76,12 +156,20 @@ module Librevox
|
|
76
156
|
# @example
|
77
157
|
# playback "/path/to/file.wav"
|
78
158
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_playback
|
79
|
-
def playback
|
159
|
+
def playback file, &b
|
80
160
|
execute_app "playback", file, &b
|
81
161
|
end
|
82
162
|
|
163
|
+
# Pre-answer establishes early media but does not answer.
|
164
|
+
# @example
|
165
|
+
# pre_anser
|
166
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_pre_answer
|
167
|
+
def pre_answer &b
|
168
|
+
execute_app "pre_answer", &b
|
169
|
+
end
|
170
|
+
|
83
171
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_read
|
84
|
-
def read
|
172
|
+
def read file, args={}, &b
|
85
173
|
min = args[:min] || 1
|
86
174
|
max = args[:max] || 2
|
87
175
|
terminators = args[:terminators] || "#"
|
@@ -103,16 +191,31 @@ module Librevox
|
|
103
191
|
# @example With 20 second limit
|
104
192
|
# record "/path/to/new/file.wac", :limit => 20
|
105
193
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_record
|
106
|
-
def record
|
194
|
+
def record path, params={}, &b
|
107
195
|
args = [path, params[:limit]].compact.join(" ")
|
108
196
|
execute_app "record", args, &b
|
109
197
|
end
|
110
198
|
|
199
|
+
# Redirect a channel to another endpoint. You must take care to not
|
200
|
+
# redirect incompatible channels, as that wont have the desired effect.
|
201
|
+
# I.e. if you redirect to a SIP URI, it should be a SIP channel.
|
202
|
+
#
|
203
|
+
# #{redirect} can only be used on non-established calls, i.e. calls that
|
204
|
+
# has not been answered with the #{answer} application yet. If the call has
|
205
|
+
# been answered, use #{deflect} instead.
|
206
|
+
# @example
|
207
|
+
# redirect "sip:freddie@hubbard.org"
|
208
|
+
# @see #{deflect}
|
209
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_redirect
|
210
|
+
def redirect uri, &b
|
211
|
+
execute_app "redirect", uri, &b
|
212
|
+
end
|
213
|
+
|
111
214
|
# Sets a channel variable.
|
112
215
|
# @example
|
113
216
|
# set "some_var", "some value"
|
114
217
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_set
|
115
|
-
def set
|
218
|
+
def set variable, value, &b
|
116
219
|
execute_app "set", "#{variable}=#{value}", &b
|
117
220
|
end
|
118
221
|
|
@@ -120,8 +223,24 @@ module Librevox
|
|
120
223
|
# @example
|
121
224
|
# transfer "new_context"
|
122
225
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_transfer
|
123
|
-
def transfer
|
226
|
+
def transfer context, &b
|
124
227
|
execute_app "transfer", context, &b
|
125
228
|
end
|
229
|
+
|
230
|
+
# Unbinds a previously bound key with bind_meta_app
|
231
|
+
# @example
|
232
|
+
# unbind_meta_app 3
|
233
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_unbind_meta_app
|
234
|
+
def unbind_meta_app key, &b
|
235
|
+
execute_app "unbind_meta_app", key.to_s, &b
|
236
|
+
end
|
237
|
+
|
238
|
+
# Unset a channel variable.
|
239
|
+
# @example
|
240
|
+
# unset "foo"
|
241
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_unset
|
242
|
+
def unset variable, &b
|
243
|
+
execute_app "unset", variable, &b
|
244
|
+
end
|
126
245
|
end
|
127
246
|
end
|
@@ -38,7 +38,7 @@ module Librevox
|
|
38
38
|
|
39
39
|
def run_cmd(cmd, &block)
|
40
40
|
send_data "#{cmd}\n\n"
|
41
|
-
@
|
41
|
+
@command_queue << (block || lambda {})
|
42
42
|
end
|
43
43
|
|
44
44
|
attr_accessor :response
|
@@ -46,33 +46,37 @@ module Librevox
|
|
46
46
|
|
47
47
|
def post_init
|
48
48
|
@command_delegate = CommandDelegate.new(self)
|
49
|
-
@
|
49
|
+
@command_queue = []
|
50
50
|
end
|
51
51
|
|
52
52
|
def receive_request(header, content)
|
53
53
|
@response = Librevox::Response.new(header, content)
|
54
54
|
|
55
55
|
if response.event?
|
56
|
-
on_event
|
57
|
-
|
58
|
-
elsif response.api_response? && @
|
59
|
-
|
56
|
+
on_event response.dup
|
57
|
+
invoke_event_hooks
|
58
|
+
elsif response.api_response? && @command_queue.any?
|
59
|
+
invoke_command_queue
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
63
|
# override
|
64
|
-
def on_event
|
64
|
+
def on_event(event)
|
65
65
|
end
|
66
66
|
|
67
|
+
alias :done :close_connection_after_writing
|
68
|
+
|
67
69
|
private
|
68
|
-
def
|
69
|
-
self.class.hooks.each
|
70
|
-
|
71
|
-
|
70
|
+
def invoke_event_hooks
|
71
|
+
self.class.hooks.each {|name,block|
|
72
|
+
if name == response.event.downcase.to_sym
|
73
|
+
instance_exec response.dup, &block
|
74
|
+
end
|
75
|
+
}
|
72
76
|
end
|
73
77
|
|
74
|
-
def
|
75
|
-
block = @
|
78
|
+
def invoke_command_queue
|
79
|
+
block = @command_queue.shift
|
76
80
|
block.call(response)
|
77
81
|
end
|
78
82
|
end
|
@@ -4,14 +4,6 @@ require 'librevox/applications'
|
|
4
4
|
module Librevox
|
5
5
|
module Listener
|
6
6
|
class Outbound < Base
|
7
|
-
class << self
|
8
|
-
attr_reader :session_callback
|
9
|
-
|
10
|
-
def session(&block)
|
11
|
-
@session_callback = block
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
7
|
include Librevox::Applications
|
16
8
|
|
17
9
|
def execute_app(app, args="", params={}, &block)
|
@@ -25,10 +17,10 @@ module Librevox
|
|
25
17
|
@read_channel_var = params[:read_var]
|
26
18
|
|
27
19
|
if @read_channel_var
|
28
|
-
@
|
20
|
+
@application_queue << lambda {update_session}
|
29
21
|
end
|
30
22
|
|
31
|
-
@
|
23
|
+
@application_queue << (block || lambda {})
|
32
24
|
end
|
33
25
|
|
34
26
|
# This should probably be in Application#sendmsg instead.
|
@@ -37,46 +29,47 @@ module Librevox
|
|
37
29
|
end
|
38
30
|
|
39
31
|
attr_accessor :session
|
32
|
+
|
33
|
+
# Called when a new session is initiated.
|
34
|
+
def session_initiated
|
35
|
+
end
|
40
36
|
|
41
37
|
def post_init
|
42
38
|
super
|
43
39
|
@session = nil
|
44
|
-
@
|
40
|
+
@application_queue = []
|
45
41
|
|
46
42
|
send_data "connect\n\n"
|
47
43
|
send_data "myevents\n\n"
|
48
|
-
@
|
44
|
+
@application_queue << lambda {}
|
49
45
|
send_data "linger\n\n"
|
50
|
-
@
|
46
|
+
@application_queue << lambda {}
|
51
47
|
end
|
52
48
|
|
53
49
|
def receive_request(*args)
|
54
50
|
super(*args)
|
55
51
|
|
56
52
|
if session.nil?
|
57
|
-
@session = response
|
58
|
-
|
53
|
+
@session = response.headers
|
54
|
+
session_initiated
|
59
55
|
elsif response.event? && response.event == "CHANNEL_DATA"
|
60
|
-
@session = response
|
56
|
+
@session = response.content
|
61
57
|
resume_with_channel_var
|
62
58
|
elsif response.command_reply? && !response.event?
|
63
|
-
@
|
59
|
+
@application_queue.shift.call if @application_queue.any?
|
64
60
|
end
|
65
61
|
end
|
66
62
|
|
67
63
|
def resume_with_channel_var
|
68
64
|
if @read_channel_var
|
69
65
|
variable = "variable_#{@read_channel_var}".to_sym
|
70
|
-
value = @session
|
71
|
-
@
|
66
|
+
value = @session[variable]
|
67
|
+
@application_queue.shift.call(value) if @application_queue.any?
|
72
68
|
end
|
73
69
|
end
|
74
70
|
|
75
71
|
def update_session
|
76
|
-
send_data("api uuid_dump #{session
|
77
|
-
end
|
78
|
-
|
79
|
-
def session_initiated
|
72
|
+
send_data("api uuid_dump #{session[:unique_id]}\n\n")
|
80
73
|
end
|
81
74
|
end
|
82
75
|
end
|
data/librevox.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "librevox"
|
3
|
-
s.version = "0.
|
4
|
-
s.date = "2010-01-
|
3
|
+
s.version = "0.2"
|
4
|
+
s.date = "2010-01-26"
|
5
5
|
s.summary = "Ruby library for interacting with FreeSWITCH."
|
6
6
|
s.email = "harry@vangberg.name"
|
7
7
|
s.homepage = "http://github.com/ichverstehe/librevox"
|
data/spec/librevox/listener.rb
CHANGED
@@ -25,13 +25,18 @@ shared "events" do
|
|
25
25
|
|
26
26
|
@class.event(:some_event) {send_data "something"}
|
27
27
|
@class.event(:other_event) {send_data "something else"}
|
28
|
+
@class.event(:hook_with_arg) {|e| send_data "got event arg: #{e.object_id}"}
|
29
|
+
|
30
|
+
def @listener.on_event(e)
|
31
|
+
send_data "from on_event: #{e.object_id}"
|
32
|
+
end
|
28
33
|
|
29
34
|
# Establish session
|
30
35
|
@listener.receive_data("Content-Length: 0\nTest: Testing\n\n")
|
31
36
|
end
|
32
37
|
|
33
38
|
should "add event hook" do
|
34
|
-
@class.hooks.size.should ==
|
39
|
+
@class.hooks.size.should == 3
|
35
40
|
end
|
36
41
|
|
37
42
|
should "execute callback for event" do
|
@@ -42,11 +47,28 @@ shared "events" do
|
|
42
47
|
@listener.read_data.should == "something"
|
43
48
|
end
|
44
49
|
|
50
|
+
should "pass response duplicate as arg to hook block" do
|
51
|
+
@listener.receive_data("Content-Length: 25\n\nEvent-Name: HOOK_WITH_ARG\n\n")
|
52
|
+
reply = @listener.read_data
|
53
|
+
reply.should =~ /^got event arg: /
|
54
|
+
reply.should.not =~ /^got event arg: #{@listener.response.object_id}$/
|
55
|
+
end
|
56
|
+
|
45
57
|
should "expose response as event" do
|
46
58
|
@listener.receive_data("Content-Length: 23\n\nEvent-Name: OTHER_EVENT\n\n")
|
47
59
|
@listener.event.class.should == Librevox::Response
|
48
60
|
@listener.event.content[:event_name].should == "OTHER_EVENT"
|
49
61
|
end
|
62
|
+
|
63
|
+
should "call on_event" do
|
64
|
+
@listener.receive_data("Content-Length: 23\n\nEvent-Name: THIRD_EVENT\n\n")
|
65
|
+
@listener.read_data.should =~ /^from on_event/
|
66
|
+
end
|
67
|
+
|
68
|
+
should "call on_event with response duplicate as argument" do
|
69
|
+
@listener.receive_data("Content-Length: 23\n\nEvent-Name: THIRD_EVENT\n\n")
|
70
|
+
@listener.read_data.should.not =~ /^from on_event: #{@listener.response.object_id}$/
|
71
|
+
end
|
50
72
|
end
|
51
73
|
|
52
74
|
module Librevox::Commands
|
@@ -66,6 +88,9 @@ shared "api commands" do
|
|
66
88
|
describe "multiple api commands" do
|
67
89
|
before do
|
68
90
|
@listener.outgoing_data.clear
|
91
|
+
|
92
|
+
def @listener.on_event(e) end # Don't send anything, kthx.
|
93
|
+
|
69
94
|
@class.event(:api_test) {
|
70
95
|
api :sample_cmd, "foo" do
|
71
96
|
api :sample_cmd, "foo", "bar baz"
|
@@ -10,7 +10,7 @@ module Librevox::Applications
|
|
10
10
|
end
|
11
11
|
|
12
12
|
class OutboundTestListener < Librevox::Listener::Outbound
|
13
|
-
|
13
|
+
def session_initiated
|
14
14
|
send_data "session was initiated"
|
15
15
|
end
|
16
16
|
end
|
@@ -34,7 +34,7 @@ describe "Outbound listener" do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
should "establish a session" do
|
37
|
-
@listener.session.class.should.equal
|
37
|
+
@listener.session.class.should.equal Hash
|
38
38
|
end
|
39
39
|
|
40
40
|
should "call session callback after establishing new session" do
|
@@ -42,7 +42,7 @@ describe "Outbound listener" do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
should "make channel variables available through session" do
|
45
|
-
@listener.session
|
45
|
+
@listener.session[:caller_caller_id_number].should.equal "8675309"
|
46
46
|
end
|
47
47
|
|
48
48
|
behaves_like "events"
|
@@ -54,7 +54,7 @@ describe "Outbound listener" do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
class OutboundListenerWithNestedApps < Librevox::Listener::Outbound
|
57
|
-
|
57
|
+
def session_initiated
|
58
58
|
sample_app "foo" do
|
59
59
|
sample_app "bar"
|
60
60
|
end
|
@@ -106,7 +106,7 @@ module Librevox::Applications
|
|
106
106
|
end
|
107
107
|
|
108
108
|
class OutboundListenerWithReader < Librevox::Listener::Outbound
|
109
|
-
|
109
|
+
def session_initiated
|
110
110
|
reader_app do |data|
|
111
111
|
send_data "read this: #{data}"
|
112
112
|
end
|
@@ -136,7 +136,7 @@ describe "Outbound listener with app reading data" do
|
|
136
136
|
should "update session with new data" do
|
137
137
|
@listener.receive_data("Content-Type: command/reply\nContent-Length: 3\n\n+OK\n\n")
|
138
138
|
@listener.receive_data("Content-Type: command/reply\nContent-Length: 44\n\nEvent-Name: CHANNEL_DATA\nSession-Var: Second\n\n")
|
139
|
-
@listener.session
|
139
|
+
@listener.session[:session_var].should == "Second"
|
140
140
|
end
|
141
141
|
|
142
142
|
should "pass value of channel variable to block" do
|
@@ -148,7 +148,7 @@ end
|
|
148
148
|
|
149
149
|
class OutboundListenerWithNonNestedApps < Librevox::Listener::Outbound
|
150
150
|
attr_reader :queue
|
151
|
-
|
151
|
+
def session_initiated
|
152
152
|
sample_app "foo"
|
153
153
|
reader_app do |data|
|
154
154
|
send_data "the end: #{data}"
|
@@ -190,7 +190,7 @@ module Librevox::Commands
|
|
190
190
|
end
|
191
191
|
|
192
192
|
class OutboundListenerWithAppsAndApi < Librevox::Listener::Outbound
|
193
|
-
|
193
|
+
def session_initiated
|
194
194
|
sample_app "foo" do
|
195
195
|
api :sample_cmd, "bar" do
|
196
196
|
sample_app "baz"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec/helper'
|
2
2
|
require 'librevox/applications'
|
3
3
|
|
4
|
-
module
|
4
|
+
module AppTest
|
5
5
|
include Librevox::Applications
|
6
6
|
|
7
7
|
extend self
|
@@ -17,16 +17,24 @@ module ApplicationTest
|
|
17
17
|
end
|
18
18
|
|
19
19
|
describe Librevox::Applications do
|
20
|
-
|
20
|
+
describe "answer" do
|
21
|
+
should "answer" do
|
22
|
+
app = AppTest.answer
|
23
|
+
app[:name].should == "answer"
|
24
|
+
end
|
25
|
+
end
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
|
27
|
+
describe "att_xfer" do
|
28
|
+
should "transfer to endpoint" do
|
29
|
+
app = AppTest.att_xfer("user/davis")
|
30
|
+
app[:name].should == "att_xfer"
|
31
|
+
app[:args].should == "user/davis"
|
32
|
+
end
|
25
33
|
end
|
26
34
|
|
27
35
|
describe "bind_meta_app" do
|
28
36
|
should "bind meta app" do
|
29
|
-
app =
|
37
|
+
app = AppTest.bind_meta_app :key => "2",
|
30
38
|
:listen_to => :a,
|
31
39
|
:respond_on => :s,
|
32
40
|
:application => "hangup"
|
@@ -36,7 +44,7 @@ describe Librevox::Applications do
|
|
36
44
|
end
|
37
45
|
|
38
46
|
should "bind meta app with parameters" do
|
39
|
-
app =
|
47
|
+
app = AppTest.bind_meta_app :key => "2",
|
40
48
|
:listen_to => :a,
|
41
49
|
:respond_on => :s,
|
42
50
|
:application => "execute_extension",
|
@@ -47,33 +55,85 @@ describe Librevox::Applications do
|
|
47
55
|
end
|
48
56
|
end
|
49
57
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
58
|
+
describe "bridge" do
|
59
|
+
should "bridge to endpoints" do
|
60
|
+
app = AppTest.bridge('user/coltrane')
|
61
|
+
app[:name].should == "bridge"
|
62
|
+
app[:args].should == 'user/coltrane'
|
63
|
+
|
64
|
+
app = AppTest.bridge('user/coltrane', 'user/davis')
|
65
|
+
app[:args].should == 'user/coltrane,user/davis'
|
66
|
+
end
|
67
|
+
|
68
|
+
should "bridge with variables" do
|
69
|
+
app = AppTest.bridge('user/coltrane', 'user/davis', :foo => 'bar', :lol => 'cat')
|
70
|
+
app[:name].should == "bridge"
|
71
|
+
|
72
|
+
# fragile. hashes are not ordered in ruby 1.8
|
73
|
+
app[:args].should == "{foo=bar,lol=cat}user/coltrane,user/davis"
|
74
|
+
end
|
75
|
+
|
76
|
+
should "bridge with failover" do
|
77
|
+
app = AppTest.bridge(
|
78
|
+
['user/coltrane', 'user/davis'], ['user/sun-ra', 'user/taylor']
|
79
|
+
)
|
80
|
+
|
81
|
+
app[:name].should == "bridge"
|
82
|
+
app[:args].should == "user/coltrane,user/davis|user/sun-ra,user/taylor"
|
83
|
+
end
|
84
|
+
|
85
|
+
# should "bridge with per endpoint variables" do
|
86
|
+
# end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "deflect" do
|
90
|
+
should "deflect call" do
|
91
|
+
app = AppTest.deflect "sip:miles@davis.org"
|
92
|
+
app[:name].should == "deflect"
|
93
|
+
app[:args].should == "sip:miles@davis.org"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "export" do
|
98
|
+
should "export variable" do
|
99
|
+
app = AppTest.export 'some_var'
|
100
|
+
app[:name].should == "export"
|
101
|
+
app[:args].should == "some_var"
|
102
|
+
end
|
54
103
|
|
55
|
-
|
56
|
-
|
104
|
+
should "only export to b-leg " do
|
105
|
+
app = AppTest.export 'some_var', :local => false
|
106
|
+
app[:name].should == "export"
|
107
|
+
app[:args].should == "nolocal:some_var"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "gentones" do
|
112
|
+
should "generate tones" do
|
113
|
+
app = AppTest.gentones("%(500,0,800)")
|
114
|
+
app[:name].should == "gentones"
|
115
|
+
app[:args].should == "%(500,0,800)"
|
116
|
+
end
|
57
117
|
end
|
58
118
|
|
59
119
|
should "hangup" do
|
60
|
-
app =
|
120
|
+
app = AppTest.hangup
|
61
121
|
app[:name].should == "hangup"
|
62
122
|
|
63
|
-
app =
|
123
|
+
app = AppTest.hangup("some cause")
|
64
124
|
app[:args].should == "some cause"
|
65
125
|
end
|
66
126
|
|
67
127
|
describe "play_and_get_digits" do
|
68
128
|
should "have defaults" do
|
69
|
-
app =
|
129
|
+
app = AppTest.play_and_get_digits "please-enter", "wrong-try-again"
|
70
130
|
app[:name].should == "play_and_get_digits"
|
71
131
|
app[:args].should == "1 2 3 5000 # please-enter wrong-try-again read_digits_var \\d+"
|
72
132
|
app[:params][:read_var].should == "read_digits_var"
|
73
133
|
end
|
74
134
|
|
75
135
|
should "take params" do
|
76
|
-
app =
|
136
|
+
app = AppTest.play_and_get_digits "please-enter", "invalid-choice",
|
77
137
|
:min => 2,
|
78
138
|
:max => 3,
|
79
139
|
:tries => 4,
|
@@ -88,21 +148,28 @@ describe Librevox::Applications do
|
|
88
148
|
end
|
89
149
|
|
90
150
|
should "playback" do
|
91
|
-
app =
|
151
|
+
app = AppTest.playback("uri://some/file.wav")
|
92
152
|
app[:name].should == "playback"
|
93
153
|
app[:args].should == "uri://some/file.wav"
|
94
154
|
end
|
95
155
|
|
156
|
+
describe "pre_answer" do
|
157
|
+
should "pre_answer" do
|
158
|
+
app = AppTest.pre_answer
|
159
|
+
app[:name].should == "pre_answer"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
96
163
|
describe "read" do
|
97
164
|
should "read with defaults" do
|
98
|
-
app =
|
165
|
+
app = AppTest.read "please-enter.wav"
|
99
166
|
app[:name].should == "read"
|
100
167
|
app[:args].should == "1 2 please-enter.wav read_digits_var 5000 #"
|
101
168
|
app[:params][:read_var].should == "read_digits_var"
|
102
169
|
end
|
103
170
|
|
104
171
|
should "take params" do
|
105
|
-
app =
|
172
|
+
app = AppTest.read "please-enter.wav",
|
106
173
|
:min => 2,
|
107
174
|
:max => 3,
|
108
175
|
:terminators => "0",
|
@@ -116,27 +183,51 @@ describe Librevox::Applications do
|
|
116
183
|
|
117
184
|
describe "record" do
|
118
185
|
should "start recording" do
|
119
|
-
app =
|
186
|
+
app = AppTest.record "/path/to/file.mp3"
|
120
187
|
app[:name].should == "record"
|
121
188
|
app[:args].should == "/path/to/file.mp3"
|
122
189
|
end
|
123
190
|
|
124
191
|
should "start recording with time limit" do
|
125
|
-
app =
|
192
|
+
app = AppTest.record "/path/to/file.mp3", :limit => 15
|
126
193
|
app[:name].should == "record"
|
127
194
|
app[:args].should == "/path/to/file.mp3 15"
|
128
195
|
end
|
129
196
|
end
|
130
197
|
|
198
|
+
describe "redirect" do
|
199
|
+
should "redirect to URI" do
|
200
|
+
app = AppTest.redirect("sip:miles@davis.org")
|
201
|
+
app[:name].should == "redirect"
|
202
|
+
app[:args].should == "sip:miles@davis.org"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
131
206
|
should "set" do
|
132
|
-
app =
|
207
|
+
app = AppTest.set("foo", "bar")
|
133
208
|
app[:name].should == "set"
|
134
209
|
app[:args].should == "foo=bar"
|
135
210
|
end
|
136
211
|
|
137
212
|
should "transfer" do
|
138
|
-
app =
|
213
|
+
app = AppTest.transfer "new_extension"
|
139
214
|
app[:name].should == "transfer"
|
140
215
|
app[:args].should == "new_extension"
|
141
216
|
end
|
217
|
+
|
218
|
+
describe "unbind_meta_app" do
|
219
|
+
should "unbind" do
|
220
|
+
app = AppTest.unbind_meta_app 3
|
221
|
+
app[:name].should == "unbind_meta_app"
|
222
|
+
app[:args].should == "3"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe "unset" do
|
227
|
+
should "unset a variable" do
|
228
|
+
app = AppTest.unset('foo')
|
229
|
+
app[:name].should == "unset"
|
230
|
+
app[:args].should == "foo"
|
231
|
+
end
|
232
|
+
end
|
142
233
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: librevox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Harry Vangberg
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-26 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|