librevox 0.9 → 1.0.0.alpha2
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 +5 -5
- data/README.md +252 -167
- data/lib/librevox/applications.rb +80 -67
- data/lib/librevox/client.rb +39 -0
- data/lib/librevox/command_socket.rb +12 -26
- data/lib/librevox/commands.rb +23 -23
- data/lib/librevox/listener/base.rb +49 -30
- data/lib/librevox/listener/inbound.rb +40 -15
- data/lib/librevox/listener/outbound.rb +40 -34
- data/lib/librevox/protocol/connection.rb +47 -0
- data/lib/librevox/protocol/response.rb +60 -0
- data/lib/librevox/runner.rb +37 -0
- data/lib/librevox/server.rb +33 -0
- data/lib/librevox/version.rb +5 -0
- data/lib/librevox.rb +32 -42
- metadata +66 -36
- data/Rakefile +0 -6
- data/TODO +0 -29
- data/lib/librevox/response.rb +0 -52
- data/librevox.gemspec +0 -37
- data/spec/helper.rb +0 -86
- data/spec/librevox/listener/spec_inbound.rb +0 -22
- data/spec/librevox/listener/spec_outbound.rb +0 -300
- data/spec/librevox/listener.rb +0 -142
- data/spec/librevox/spec_applications.rb +0 -238
- data/spec/librevox/spec_commands.rb +0 -103
- data/spec/librevox/spec_response.rb +0 -67
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Librevox
|
|
2
4
|
# All applications should call `application` with the following parameters:
|
|
3
5
|
#
|
|
@@ -8,8 +10,14 @@ module Librevox
|
|
|
8
10
|
module Applications
|
|
9
11
|
# Answers an incoming call or session.
|
|
10
12
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_answer
|
|
11
|
-
def answer
|
|
12
|
-
application "answer"
|
|
13
|
+
def answer
|
|
14
|
+
application "answer"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Parks a call, keeping it active without routing it anywhere.
|
|
18
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_park
|
|
19
|
+
def park
|
|
20
|
+
application "park"
|
|
13
21
|
end
|
|
14
22
|
|
|
15
23
|
# Make an attended transfer
|
|
@@ -17,27 +25,26 @@ module Librevox
|
|
|
17
25
|
# att_xfer("user/davis")
|
|
18
26
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_att_xfer
|
|
19
27
|
# @todo Add support for origination_cancel_key
|
|
20
|
-
def att_xfer
|
|
21
|
-
application "att_xfer", endpoint
|
|
28
|
+
def att_xfer(endpoint)
|
|
29
|
+
application "att_xfer", endpoint
|
|
22
30
|
end
|
|
23
31
|
|
|
24
32
|
# Binds an application to the specified call legs.
|
|
25
|
-
# @example
|
|
26
|
-
# bind_meta_app :
|
|
27
|
-
# :
|
|
28
|
-
# :
|
|
29
|
-
# :
|
|
30
|
-
# :
|
|
33
|
+
# @example
|
|
34
|
+
# bind_meta_app key: 2,
|
|
35
|
+
# listen_to: "a",
|
|
36
|
+
# respond_on: "s",
|
|
37
|
+
# application: "execute_extension",
|
|
38
|
+
# parameters: "dx XML features"
|
|
31
39
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_bind_meta_app
|
|
32
|
-
def bind_meta_app
|
|
40
|
+
def bind_meta_app(args = {})
|
|
33
41
|
arg_string =
|
|
34
42
|
args.values_at(:key, :listen_to, :respond_on, :application).join(" ")
|
|
35
43
|
arg_string += "::#{args[:parameters]}" if args[:parameters]
|
|
36
44
|
|
|
37
|
-
application "bind_meta_app", arg_string
|
|
45
|
+
application "bind_meta_app", arg_string
|
|
38
46
|
end
|
|
39
47
|
|
|
40
|
-
|
|
41
48
|
# Bridges an incoming call to an endpoint, optionally taking an array of
|
|
42
49
|
# channel variables to set. If given an array of arrays, each contained
|
|
43
50
|
# array of endpoints will be called simultaneously, with the next array
|
|
@@ -47,19 +54,16 @@ module Librevox
|
|
|
47
54
|
# bridge "user/coltrane", "user/backup-office"
|
|
48
55
|
# #=> user/coltrane,user/backup-office
|
|
49
56
|
# @example With channel variables
|
|
50
|
-
# bridge "user/coltrane", "user/backup-office", :
|
|
57
|
+
# bridge "user/coltrane", "user/backup-office", some_var: "value"
|
|
51
58
|
# #=> {some_var=value}user/coltrane,user/backup-office
|
|
52
59
|
# @example With failover
|
|
53
60
|
# bridge ['user/coltrane', 'user/davis'], ['user/sun-ra', 'user/taylor']
|
|
54
61
|
# #=> user/coltrane,user/davis|user/sun-ra,user/taylor
|
|
55
62
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_bridge
|
|
56
|
-
def bridge
|
|
63
|
+
def bridge(*args)
|
|
57
64
|
variables = if args.last.is_a? Hash
|
|
58
|
-
|
|
59
|
-
#
|
|
60
|
-
key_value_pairs = args.pop.sort {|x,y| x.to_s <=> y.to_s}
|
|
61
|
-
key_value_pairs.map! {|k,v| "#{k}=#{v}"}
|
|
62
|
-
"{#{key_value_pairs.join(",")}}"
|
|
65
|
+
pairs = args.pop.map {|k,v| "#{k}=#{v}"}
|
|
66
|
+
"{#{pairs.join(",")}}"
|
|
63
67
|
else
|
|
64
68
|
""
|
|
65
69
|
end
|
|
@@ -70,38 +74,38 @@ module Librevox
|
|
|
70
74
|
args.join ","
|
|
71
75
|
end
|
|
72
76
|
|
|
73
|
-
application "bridge", variables + endpoints
|
|
77
|
+
application "bridge", variables + endpoints
|
|
74
78
|
end
|
|
75
79
|
|
|
76
80
|
# Deflect a call by sending a REFER. Takes a SIP URI as argument, rerouting
|
|
77
81
|
# the call to that SIP URI.
|
|
78
82
|
#
|
|
79
83
|
# Beware that REFER only can be used on established calls. If a call hasn't
|
|
80
|
-
# been established with e.g. the {#answer} application, you should use
|
|
84
|
+
# been established with e.g. the {#answer} application, you should use
|
|
81
85
|
# {#redirect} instead.
|
|
82
86
|
# @example
|
|
83
87
|
# deflect "sip:miles@davis.com"
|
|
84
88
|
# @see #redirect
|
|
85
89
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_deflect
|
|
86
|
-
def deflect
|
|
87
|
-
application "deflect", uri
|
|
90
|
+
def deflect(uri)
|
|
91
|
+
application "deflect", uri
|
|
88
92
|
end
|
|
89
93
|
|
|
90
94
|
# Exports a channel variable from the A leg to the B leg. Variables and
|
|
91
95
|
# their values will be replicated in any new channels created from the one
|
|
92
96
|
# export was called.
|
|
93
|
-
#
|
|
94
|
-
# Set :
|
|
97
|
+
#
|
|
98
|
+
# Set `local: false` if the variable should only be exported to the B-leg.
|
|
95
99
|
#
|
|
96
100
|
# @example
|
|
97
101
|
# export "some_var"
|
|
98
102
|
# @example Only export to B-leg
|
|
99
|
-
# export "some_var", :
|
|
103
|
+
# export "some_var", local: false
|
|
100
104
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_export
|
|
101
|
-
def export
|
|
102
|
-
nolocal = args[:local] == false ? "nolocal:" : ""
|
|
105
|
+
def export(var, args = {})
|
|
106
|
+
nolocal = args[:local] == false ? "nolocal:" : ""
|
|
103
107
|
|
|
104
|
-
application "export", "#{nolocal}#{var}"
|
|
108
|
+
application "export", "#{nolocal}#{var}"
|
|
105
109
|
end
|
|
106
110
|
|
|
107
111
|
# Generate TGML tones
|
|
@@ -110,8 +114,8 @@ module Librevox
|
|
|
110
114
|
# @example Generate a DTMF string
|
|
111
115
|
# gentones "0800500005"
|
|
112
116
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_gentones
|
|
113
|
-
def gentones
|
|
114
|
-
application "gentones", tgml
|
|
117
|
+
def gentones(tgml)
|
|
118
|
+
application "gentones", tgml
|
|
115
119
|
end
|
|
116
120
|
|
|
117
121
|
# Hang up current channel
|
|
@@ -120,21 +124,21 @@ module Librevox
|
|
|
120
124
|
# @example Hang up with a reason
|
|
121
125
|
# hangup "USER_BUSY"
|
|
122
126
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_hangup
|
|
123
|
-
def hangup
|
|
124
|
-
application "hangup", cause
|
|
127
|
+
def hangup(cause = "")
|
|
128
|
+
application "hangup", cause
|
|
125
129
|
end
|
|
126
130
|
|
|
127
131
|
# Plays a sound file and reads DTMF presses.
|
|
128
|
-
# @example
|
|
132
|
+
# @example
|
|
129
133
|
# play_and_get_digits "please-enter.wav", "wrong-choice.wav",
|
|
130
|
-
# :
|
|
131
|
-
# :
|
|
132
|
-
# :
|
|
133
|
-
# :
|
|
134
|
-
# :
|
|
135
|
-
# :
|
|
134
|
+
# min: 1,
|
|
135
|
+
# max: 2,
|
|
136
|
+
# tries: 3,
|
|
137
|
+
# terminators: "#",
|
|
138
|
+
# timeout: 5000,
|
|
139
|
+
# regexp: '\d+'
|
|
136
140
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_play_and_get_digits
|
|
137
|
-
def play_and_get_digits
|
|
141
|
+
def play_and_get_digits(file, invalid_file, args = {})
|
|
138
142
|
min = args[:min] || 1
|
|
139
143
|
max = args[:max] || 2
|
|
140
144
|
tries = args[:tries] || 3
|
|
@@ -146,29 +150,29 @@ module Librevox
|
|
|
146
150
|
args = [min, max, tries, timeout, terminators, file, invalid_file,
|
|
147
151
|
variable, regexp].join " "
|
|
148
152
|
|
|
149
|
-
params = {:
|
|
153
|
+
params = {variable: variable}
|
|
150
154
|
|
|
151
|
-
application "play_and_get_digits", args, params
|
|
155
|
+
application "play_and_get_digits", args, params
|
|
152
156
|
end
|
|
153
157
|
|
|
154
158
|
# Plays a sound file on the current channel.
|
|
155
159
|
# @example
|
|
156
160
|
# playback "/path/to/file.wav"
|
|
157
161
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_playback
|
|
158
|
-
def playback
|
|
159
|
-
application "playback", file
|
|
162
|
+
def playback(file)
|
|
163
|
+
application "playback", file
|
|
160
164
|
end
|
|
161
165
|
|
|
162
166
|
# Pre-answer establishes early media but does not answer.
|
|
163
167
|
# @example
|
|
164
|
-
#
|
|
168
|
+
# pre_answer
|
|
165
169
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_pre_answer
|
|
166
|
-
def pre_answer
|
|
167
|
-
application "pre_answer"
|
|
170
|
+
def pre_answer
|
|
171
|
+
application "pre_answer"
|
|
168
172
|
end
|
|
169
173
|
|
|
170
174
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_read
|
|
171
|
-
def read
|
|
175
|
+
def read(file, args = {})
|
|
172
176
|
min = args[:min] || 1
|
|
173
177
|
max = args[:max] || 2
|
|
174
178
|
terminators = args[:terminators] || "#"
|
|
@@ -178,9 +182,9 @@ module Librevox
|
|
|
178
182
|
arg_string = "%s %s %s %s %s %s" % [min, max, file, variable, timeout,
|
|
179
183
|
terminators]
|
|
180
184
|
|
|
181
|
-
params = {:
|
|
185
|
+
params = {variable: variable}
|
|
182
186
|
|
|
183
|
-
application "read", arg_string, params
|
|
187
|
+
application "read", arg_string, params
|
|
184
188
|
end
|
|
185
189
|
|
|
186
190
|
# Records a message, with an optional limit on the maximum duration of the
|
|
@@ -188,11 +192,11 @@ module Librevox
|
|
|
188
192
|
# @example Without limit
|
|
189
193
|
# record "/path/to/new/file.wac"
|
|
190
194
|
# @example With 20 second limit
|
|
191
|
-
# record "/path/to/new/file.wac", :
|
|
195
|
+
# record "/path/to/new/file.wac", limit: 20
|
|
192
196
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_record
|
|
193
|
-
def record
|
|
197
|
+
def record(path, params = {})
|
|
194
198
|
args = [path, params[:limit]].compact.join(" ")
|
|
195
|
-
application "record", args
|
|
199
|
+
application "record", args
|
|
196
200
|
end
|
|
197
201
|
|
|
198
202
|
# Redirect a channel to another endpoint. You must take care to not
|
|
@@ -206,48 +210,57 @@ module Librevox
|
|
|
206
210
|
# redirect "sip:freddie@hubbard.org"
|
|
207
211
|
# @see #deflect
|
|
208
212
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_redirect
|
|
209
|
-
def redirect
|
|
210
|
-
application "redirect", uri
|
|
213
|
+
def redirect(uri)
|
|
214
|
+
application "redirect", uri
|
|
211
215
|
end
|
|
212
216
|
|
|
213
217
|
# Send SIP session respond code.
|
|
214
218
|
# @example Send 403 Forbidden
|
|
215
219
|
# respond 403
|
|
216
220
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_respond
|
|
217
|
-
def respond
|
|
218
|
-
application "respond", code.to_s
|
|
221
|
+
def respond(code)
|
|
222
|
+
application "respond", code.to_s
|
|
219
223
|
end
|
|
220
224
|
|
|
221
225
|
# Sets a channel variable.
|
|
222
226
|
# @example
|
|
223
227
|
# set "some_var", "some value"
|
|
224
228
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_set
|
|
225
|
-
def set
|
|
226
|
-
application "set", "#{variable}=#{value}"
|
|
229
|
+
def set(variable, value)
|
|
230
|
+
application "set", "#{variable}=#{value}"
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Sets multiple channel variables in a single application call.
|
|
234
|
+
# @example
|
|
235
|
+
# multiset "var1" => "val1", "var2" => "val2"
|
|
236
|
+
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_multiset
|
|
237
|
+
def multiset(vars)
|
|
238
|
+
args = "^^|" + vars.map { |k, v| "#{k}=#{v}" }.join("|")
|
|
239
|
+
application "multiset", args
|
|
227
240
|
end
|
|
228
241
|
|
|
229
242
|
# Transfers the current channel to a new context.
|
|
230
243
|
# @example
|
|
231
244
|
# transfer "new_context"
|
|
232
245
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_transfer
|
|
233
|
-
def transfer
|
|
234
|
-
application "transfer", context
|
|
246
|
+
def transfer(context)
|
|
247
|
+
application "transfer", context
|
|
235
248
|
end
|
|
236
249
|
|
|
237
250
|
# Unbinds a previously bound key with bind_meta_app
|
|
238
251
|
# @example
|
|
239
252
|
# unbind_meta_app 3
|
|
240
253
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_unbind_meta_app
|
|
241
|
-
def unbind_meta_app
|
|
242
|
-
application "unbind_meta_app", key.to_s
|
|
254
|
+
def unbind_meta_app(key)
|
|
255
|
+
application "unbind_meta_app", key.to_s
|
|
243
256
|
end
|
|
244
257
|
|
|
245
258
|
# Unset a channel variable.
|
|
246
259
|
# @example
|
|
247
260
|
# unset "foo"
|
|
248
261
|
# @see http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_unset
|
|
249
|
-
def unset
|
|
250
|
-
application "unset", variable
|
|
262
|
+
def unset(variable)
|
|
263
|
+
application "unset", variable
|
|
251
264
|
end
|
|
252
265
|
end
|
|
253
266
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'io/stream'
|
|
4
|
+
|
|
5
|
+
module Librevox
|
|
6
|
+
class Client
|
|
7
|
+
def initialize(handler, endpoint, **options)
|
|
8
|
+
@handler = handler
|
|
9
|
+
@endpoint = endpoint
|
|
10
|
+
@options = options
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr :endpoint
|
|
14
|
+
|
|
15
|
+
def connect(socket)
|
|
16
|
+
stream = IO::Stream(socket)
|
|
17
|
+
connection = Protocol::Connection.new(stream)
|
|
18
|
+
|
|
19
|
+
listener = @handler.new(connection, @options)
|
|
20
|
+
|
|
21
|
+
session_task = Async { listener.run_session }
|
|
22
|
+
connection.read_loop { |msg| listener.receive_message(msg) }
|
|
23
|
+
ensure
|
|
24
|
+
session_task&.stop
|
|
25
|
+
connection.close
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def run
|
|
29
|
+
loop do
|
|
30
|
+
@endpoint.connect do |socket|
|
|
31
|
+
connect(socket)
|
|
32
|
+
end
|
|
33
|
+
rescue IOError, Errno::ECONNREFUSED, Errno::ECONNRESET => e
|
|
34
|
+
Librevox.logger.error "Connection lost: #{e.message}. Reconnecting in 1s."
|
|
35
|
+
sleep 1
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'socket'
|
|
2
|
-
require '
|
|
3
|
-
require 'librevox/commands'
|
|
4
|
-
require 'librevox/applications'
|
|
4
|
+
require 'io/stream'
|
|
5
5
|
|
|
6
6
|
module Librevox
|
|
7
7
|
class CommandSocket
|
|
8
8
|
include Librevox::Commands
|
|
9
9
|
|
|
10
|
-
def initialize
|
|
10
|
+
def initialize(args = {})
|
|
11
11
|
@server = args[:server] || "127.0.0.1"
|
|
12
12
|
@port = args[:port] || "8021"
|
|
13
13
|
@auth = args[:auth] || "ClueCon"
|
|
@@ -17,39 +17,25 @@ module Librevox
|
|
|
17
17
|
|
|
18
18
|
def connect
|
|
19
19
|
@socket = TCPSocket.open(@server, @port)
|
|
20
|
-
|
|
20
|
+
stream = IO::Stream(@socket)
|
|
21
|
+
@connection = Protocol::Connection.new(stream)
|
|
22
|
+
@connection.write "auth #{@auth}\n\n"
|
|
21
23
|
read_response
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
def command
|
|
25
|
-
@
|
|
26
|
+
def command(*args)
|
|
27
|
+
@connection.write "#{super(*args)}\n\n"
|
|
26
28
|
read_response
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
def read_response
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
response.headers = read_headers
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
length = response.headers[:content_length].to_i
|
|
36
|
-
response.content = @socket.read(length) if length > 0
|
|
37
|
-
|
|
38
|
-
response
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def read_headers
|
|
42
|
-
headers = ""
|
|
43
|
-
|
|
44
|
-
while line = @socket.gets and !line.chomp.empty?
|
|
45
|
-
headers += line
|
|
32
|
+
while msg = @connection.read_message
|
|
33
|
+
return msg if msg.command_reply? || msg.api_response?
|
|
46
34
|
end
|
|
47
|
-
|
|
48
|
-
headers
|
|
49
35
|
end
|
|
50
36
|
|
|
51
37
|
def close
|
|
52
|
-
@
|
|
38
|
+
@connection.close
|
|
53
39
|
end
|
|
54
40
|
end
|
|
55
41
|
end
|
data/lib/librevox/commands.rb
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Librevox
|
|
2
4
|
# All commands should call `command` with the following parameters:
|
|
3
5
|
#
|
|
4
6
|
# `name` - name of the command
|
|
5
7
|
# `args` - arguments as a string (optional)
|
|
6
|
-
#
|
|
7
|
-
# Commands *must* pass on any eventual block passed to them.
|
|
8
8
|
module Commands
|
|
9
9
|
# Executes a generic API command, optionally taking arguments as string.
|
|
10
10
|
# @example
|
|
11
11
|
# socket.command "fsctl", "hupall normal_clearing"
|
|
12
12
|
# @see http://wiki.freeswitch.org/wiki/Mod_commands
|
|
13
|
-
def command
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
def command(name, args = "")
|
|
14
|
+
parts = ["api", name]
|
|
15
|
+
parts << args if args && !args.empty?
|
|
16
|
+
parts.join(" ")
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def status
|
|
20
|
-
command "status"
|
|
19
|
+
def status
|
|
20
|
+
command "status"
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
# Access the hash table that comes with FreeSWITCH.
|
|
@@ -25,53 +25,53 @@ module Librevox
|
|
|
25
25
|
# socket.hash :insert, :realm, :key, "value"
|
|
26
26
|
# socket.hash :select, :realm, :key
|
|
27
27
|
# socket.hash :delete, :realm, :key
|
|
28
|
-
def hash
|
|
29
|
-
command "hash", args.join("/")
|
|
28
|
+
def hash(*args)
|
|
29
|
+
command "hash", args.join("/")
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
# Originate a new call.
|
|
33
33
|
# @example Minimum options
|
|
34
|
-
# socket.originate 'sofia/user/coltrane', :
|
|
34
|
+
# socket.originate 'sofia/user/coltrane', extension: "1234"
|
|
35
35
|
# @example With :dialplan and :context
|
|
36
36
|
# @see http://wiki.freeswitch.org/wiki/Mod_commands#originate
|
|
37
|
-
def originate
|
|
37
|
+
def originate(url, args = {})
|
|
38
38
|
extension = args.delete(:extension)
|
|
39
39
|
dialplan = args.delete(:dialplan)
|
|
40
40
|
context = args.delete(:context)
|
|
41
41
|
|
|
42
42
|
vars = args.map {|k,v| "#{k}=#{v}"}.join(",")
|
|
43
43
|
|
|
44
|
-
arg_string = "{#{vars}}" +
|
|
44
|
+
arg_string = "{#{vars}}" +
|
|
45
45
|
[url, extension, dialplan, context].compact.join(" ")
|
|
46
|
-
command "originate", arg_string
|
|
46
|
+
command "originate", arg_string
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
# FreeSWITCH control messages.
|
|
50
50
|
# @example
|
|
51
51
|
# socket.fsctl :hupall, :normal_clearing
|
|
52
52
|
# @see http://wiki.freeswitch.org/wiki/Mod_commands#fsctl
|
|
53
|
-
def fsctl
|
|
54
|
-
command "fsctl", args.join(" ")
|
|
53
|
+
def fsctl(*args)
|
|
54
|
+
command "fsctl", args.join(" ")
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
def hupall
|
|
58
|
-
command "hupall", cause
|
|
57
|
+
def hupall(cause = nil)
|
|
58
|
+
command "hupall", cause
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
# Park call.
|
|
62
62
|
# @example
|
|
63
63
|
# socket.uuid_park "592567a2-1be4-11df-a036-19bfdab2092f"
|
|
64
64
|
# @see http://wiki.freeswitch.org/wiki/Mod_commands#uuid_park
|
|
65
|
-
def uuid_park
|
|
66
|
-
command "uuid_park", uuid
|
|
65
|
+
def uuid_park(uuid)
|
|
66
|
+
command "uuid_park", uuid
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
# Bridge two call legs together. At least one leg must be
|
|
69
|
+
# Bridge two call legs together. At least one leg must be answered.
|
|
70
70
|
# @example
|
|
71
71
|
# socket.uuid_bridge "592567a2-1be4-11df-a036-19bfdab2092f", "58b39c3a-1be4-11df-a035-19bfdab2092f"
|
|
72
72
|
# @see http://wiki.freeswitch.org/wiki/Mod_commands#uuid_bridge
|
|
73
|
-
def uuid_bridge
|
|
74
|
-
command "uuid_bridge", "#{uuid1} #{uuid2}"
|
|
73
|
+
def uuid_bridge(uuid1, uuid2)
|
|
74
|
+
command "uuid_bridge", "#{uuid1} #{uuid2}"
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
end
|
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require '
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'async/queue'
|
|
4
|
+
require 'async/semaphore'
|
|
4
5
|
|
|
5
6
|
module Librevox
|
|
6
7
|
module Listener
|
|
7
|
-
class Base
|
|
8
|
+
class Base
|
|
9
|
+
def initialize(connection = nil)
|
|
10
|
+
@connection = connection
|
|
11
|
+
@reply_queue = Async::Queue.new
|
|
12
|
+
@command_mutex = Async::Semaphore.new(1)
|
|
13
|
+
end
|
|
14
|
+
|
|
8
15
|
class << self
|
|
9
16
|
def hooks
|
|
10
17
|
@hooks ||= Hash.new {|hash, key| hash[key] = []}
|
|
11
18
|
end
|
|
12
19
|
|
|
13
|
-
def event
|
|
20
|
+
def event(event, &block)
|
|
14
21
|
hooks[event] << block
|
|
15
22
|
end
|
|
16
23
|
end
|
|
@@ -22,12 +29,12 @@ module Librevox
|
|
|
22
29
|
class CommandDelegate
|
|
23
30
|
include Librevox::Commands
|
|
24
31
|
|
|
25
|
-
def initialize
|
|
32
|
+
def initialize(listener)
|
|
26
33
|
@listener = listener
|
|
27
34
|
end
|
|
28
35
|
|
|
29
|
-
def command
|
|
30
|
-
@listener.command
|
|
36
|
+
def command(*args)
|
|
37
|
+
@listener.command(super(*args))
|
|
31
38
|
end
|
|
32
39
|
end
|
|
33
40
|
|
|
@@ -41,47 +48,59 @@ module Librevox
|
|
|
41
48
|
@command_delegate ||= CommandDelegate.new(self)
|
|
42
49
|
end
|
|
43
50
|
|
|
44
|
-
def command
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
def command(msg)
|
|
52
|
+
@command_mutex.acquire do
|
|
53
|
+
write "#{msg}\n\n"
|
|
54
|
+
@reply_queue.dequeue
|
|
55
|
+
end
|
|
48
56
|
end
|
|
49
57
|
|
|
50
58
|
attr_accessor :response
|
|
51
|
-
alias :event :response
|
|
52
|
-
|
|
53
|
-
def post_init
|
|
54
|
-
@command_queue = []
|
|
55
|
-
end
|
|
56
59
|
|
|
57
|
-
def
|
|
58
|
-
@response =
|
|
60
|
+
def receive_message(response)
|
|
61
|
+
@response = response
|
|
59
62
|
handle_response
|
|
60
63
|
end
|
|
61
64
|
|
|
62
65
|
def handle_response
|
|
63
|
-
if response.
|
|
64
|
-
@
|
|
66
|
+
if response.reply?
|
|
67
|
+
@reply_queue.push(response)
|
|
68
|
+
return
|
|
65
69
|
end
|
|
66
70
|
|
|
67
71
|
if response.event?
|
|
68
|
-
|
|
69
|
-
|
|
72
|
+
resp = response
|
|
73
|
+
Async do
|
|
74
|
+
on_event(resp)
|
|
75
|
+
invoke_event_hooks(resp)
|
|
76
|
+
end
|
|
70
77
|
end
|
|
71
78
|
end
|
|
72
79
|
|
|
73
80
|
# override
|
|
74
|
-
def on_event
|
|
81
|
+
def on_event(event)
|
|
75
82
|
end
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
def write(data)
|
|
85
|
+
@connection&.write(data)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def run_session
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def disconnect
|
|
92
|
+
@connection&.close
|
|
93
|
+
end
|
|
78
94
|
|
|
79
95
|
private
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
|
|
97
|
+
def invoke_event_hooks(resp)
|
|
98
|
+
event_name = resp.event.downcase.to_sym
|
|
99
|
+
hooks = self.class.hooks[event_name]
|
|
100
|
+
|
|
101
|
+
hooks.each do |block|
|
|
102
|
+
instance_exec(resp, &block)
|
|
103
|
+
end
|
|
85
104
|
end
|
|
86
105
|
end
|
|
87
106
|
end
|