freeswitcher 0.4.10 → 0.5.0
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.
- data/README +69 -13
- data/Rakefile +1 -1
- data/examples/play_and_get_digits.rb +34 -0
- data/lib/fsr.rb +4 -1
- data/lib/fsr/app/play_and_get_digits.rb +8 -0
- data/lib/fsr/app/playback.rb +8 -2
- data/lib/fsr/cmd/call_center.rb +156 -0
- data/lib/fsr/cmd/calls.rb +4 -4
- data/lib/fsr/cmd/channels.rb +47 -0
- data/lib/fsr/cmd/enum.rb +40 -0
- data/lib/fsr/cmd/sofia_contact.rb +2 -1
- data/lib/fsr/file_methods.rb +14 -0
- data/lib/fsr/listener/inbound.rb +27 -3
- data/lib/fsr/model.rb +11 -0
- data/lib/fsr/model/agent.rb +18 -0
- data/lib/fsr/model/call.rb +6 -41
- data/lib/fsr/model/channel.rb +13 -0
- data/lib/fsr/model/enum.rb +26 -0
- data/lib/fsr/model/queue.rb +15 -0
- data/lib/fsr/model/tier.rb +15 -0
- data/lib/rack/middleware.rb +83 -0
- data/spec/fsr/app.rb +2 -0
- data/spec/fsr/app/play_and_get_digits.rb +15 -0
- data/spec/fsr/app/playback.rb +15 -0
- data/spec/fsr/cmd/call_center.rb +58 -0
- data/spec/fsr/cmd/calls.rb +2 -2
- data/spec/fsr/cmd/channels.rb +18 -0
- data/spec/fsr/cmd/enum.rb +19 -0
- data/spec/fsr/file_methods.rb +36 -0
- data/spec/fsr/listener/inbound.rb +6 -6
- data/spec/fsr/loading.rb +1 -1
- metadata +139 -24
@@ -17,7 +17,8 @@ module FSR
|
|
17
17
|
def run(api_method = :api)
|
18
18
|
orig_command = "%s %s" % [api_method, raw]
|
19
19
|
Log.debug "saying #{orig_command}"
|
20
|
-
@fs_socket.say(orig_command)
|
20
|
+
resp = @fs_socket.say(orig_command)
|
21
|
+
resp["body"].match(%r{^error/}) ? nil : resp["body"]
|
21
22
|
end
|
22
23
|
|
23
24
|
# This method builds the API command to send to the freeswitch event socket
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module FSR
|
2
|
+
module App
|
3
|
+
module FileMethods
|
4
|
+
def test_files *files
|
5
|
+
files.each do |file|
|
6
|
+
next unless file =~ /^\//
|
7
|
+
next if File.open(file){|io| io.stat.file? }
|
8
|
+
raise(ArgumentError, "No such file - #{file}")
|
9
|
+
end
|
10
|
+
true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/fsr/listener/inbound.rb
CHANGED
@@ -18,6 +18,7 @@ module FSR
|
|
18
18
|
@subscribed_events = []
|
19
19
|
@subscribed_sub_events = []
|
20
20
|
@hooks = {}
|
21
|
+
@output_format = args[:output_format] || "json"
|
21
22
|
end
|
22
23
|
|
23
24
|
# post_init is called upon each "new" socket connection.
|
@@ -63,7 +64,21 @@ module FSR
|
|
63
64
|
# param content content from standard Header and Content protocol
|
64
65
|
def receive_request(header, content)
|
65
66
|
hash_header = headers_2_hash(header)
|
66
|
-
|
67
|
+
case hash_header[:content_type]
|
68
|
+
when "command/reply"
|
69
|
+
return handle_reply(header, content)
|
70
|
+
when "text/event-plain"
|
71
|
+
hash_content = headers_2_hash(content)
|
72
|
+
when "text/event-json"
|
73
|
+
require "json"
|
74
|
+
hash_content = JSON.parse(content)
|
75
|
+
when "auth/request"
|
76
|
+
return
|
77
|
+
else
|
78
|
+
FSR::Log.warn "Unhandled request (#{header}, #{content})"
|
79
|
+
return
|
80
|
+
end
|
81
|
+
hash_content ||= {}
|
67
82
|
event = HeaderAndContentResponse.new({:headers => hash_header, :content => hash_content})
|
68
83
|
event_name = event.content[:event_name].to_s.strip
|
69
84
|
unless event_name.empty?
|
@@ -109,9 +124,9 @@ module FSR
|
|
109
124
|
@subscribed_events << event
|
110
125
|
@subscribed_sub_events += sub_events
|
111
126
|
if custom = @subscribed_events.delete(:CUSTOM)
|
112
|
-
say "event
|
127
|
+
say "event #{@output_format} #{@subscribed_events.join(" ")} CUSTOM #{@subscribed_sub_events.join(" ")}"
|
113
128
|
else
|
114
|
-
say "event
|
129
|
+
say "event #{@output_format} #{@subscribed_events.join(" ")}"
|
115
130
|
end
|
116
131
|
end
|
117
132
|
|
@@ -129,6 +144,15 @@ module FSR
|
|
129
144
|
def on_event(event)
|
130
145
|
event
|
131
146
|
end
|
147
|
+
|
148
|
+
# handle_reply is the callback method when a command_reply is received
|
149
|
+
#
|
150
|
+
# param header The header of the data
|
151
|
+
# param content The content of the data
|
152
|
+
# return [header, content]
|
153
|
+
def handle_reply(header, content)
|
154
|
+
[header, content]
|
155
|
+
end
|
132
156
|
|
133
157
|
# add_event_hook adds an Event to listen for. When that Event is triggered, it will call the defined block
|
134
158
|
#
|
data/lib/fsr/model.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative "../model"
|
2
|
+
module FSR
|
3
|
+
module Model
|
4
|
+
class Agent
|
5
|
+
attr_reader :fields, :extension, :full_name
|
6
|
+
include FSR::Model
|
7
|
+
|
8
|
+
def initialize(headers, *data)
|
9
|
+
@fields = headers
|
10
|
+
@fields.each_with_index do |h,i|
|
11
|
+
(class << self; self; end).send(:define_method,h.to_sym) { data[i] }
|
12
|
+
end
|
13
|
+
|
14
|
+
@extension, @full_name = name.split("-", 2)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/fsr/model/call.rb
CHANGED
@@ -1,47 +1,12 @@
|
|
1
1
|
module FSR
|
2
2
|
module Model
|
3
3
|
class Call
|
4
|
-
attr_reader :
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
caller_cid_name,
|
11
|
-
caller_cid_num,
|
12
|
-
caller_dest_num,
|
13
|
-
caller_chan_name,
|
14
|
-
caller_uuid,
|
15
|
-
callee_cid_name,
|
16
|
-
callee_cid_num,
|
17
|
-
callee_dest_num,
|
18
|
-
callee_chan_name,
|
19
|
-
callee_uuid)
|
20
|
-
@created,
|
21
|
-
@created_epoch,
|
22
|
-
@function,
|
23
|
-
@caller_id_name,
|
24
|
-
@caller_id_number,
|
25
|
-
@caller_destination,
|
26
|
-
@caller_chan_name,
|
27
|
-
@caller_uuid,
|
28
|
-
@callee_id_name,
|
29
|
-
@callee_id_number,
|
30
|
-
@callee_destination,
|
31
|
-
@callee_channel_name,
|
32
|
-
@callee_uuid = created,
|
33
|
-
created_epoch,
|
34
|
-
function,
|
35
|
-
caller_cid_name,
|
36
|
-
caller_cid_num,
|
37
|
-
caller_dest_num,
|
38
|
-
caller_chan_name,
|
39
|
-
caller_uuid,
|
40
|
-
callee_cid_name,
|
41
|
-
callee_cid_num,
|
42
|
-
callee_dest_num,
|
43
|
-
callee_chan_name,
|
44
|
-
callee_uuid
|
4
|
+
attr_reader :fields
|
5
|
+
def initialize(headers, *data)
|
6
|
+
@fields = headers
|
7
|
+
@fields.each_with_index do |h,i|
|
8
|
+
(class << self; self; end).send(:define_method,h.to_sym) { data[i] }
|
9
|
+
end
|
45
10
|
end
|
46
11
|
end
|
47
12
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module FSR
|
2
|
+
module Model
|
3
|
+
class Channel
|
4
|
+
attr_reader :fields
|
5
|
+
def initialize(headers, *data)
|
6
|
+
@fields = headers
|
7
|
+
@fields.each_with_index do |h,i|
|
8
|
+
(class << self; self; end).send(:define_method,h.to_sym) { data[i] }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module FSR
|
2
|
+
module Model
|
3
|
+
class Enum
|
4
|
+
attr_reader :offered_routes, :supported_routes, :order, :pref, :service, :route
|
5
|
+
def initialize(offered_routes,
|
6
|
+
supported_routes,
|
7
|
+
order,
|
8
|
+
pref,
|
9
|
+
service,
|
10
|
+
route)
|
11
|
+
@offered_routes,
|
12
|
+
@supported_routes,
|
13
|
+
@order,
|
14
|
+
@pref,
|
15
|
+
@service,
|
16
|
+
@route,
|
17
|
+
= offered_routes,
|
18
|
+
supported_routes,
|
19
|
+
order,
|
20
|
+
pref,
|
21
|
+
service,
|
22
|
+
route
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative "../model"
|
2
|
+
module FSR
|
3
|
+
module Model
|
4
|
+
class Queue
|
5
|
+
attr_reader :fields
|
6
|
+
include FSR::Model
|
7
|
+
def initialize(headers, *data)
|
8
|
+
@fields = headers
|
9
|
+
@fields.each_with_index do |h,i|
|
10
|
+
(class << self; self; end).send(:define_method,h.to_sym) { data[i] }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative "../model"
|
2
|
+
module FSR
|
3
|
+
module Model
|
4
|
+
class Tier
|
5
|
+
attr_reader :fields
|
6
|
+
include FSR::Model
|
7
|
+
def initialize(headers, *data)
|
8
|
+
@fields = headers
|
9
|
+
@fields.each_with_index do |h,i|
|
10
|
+
(class << self; self; end).send(:define_method,h.to_sym) { data[i] }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# Copyright (c) 2008-2009 The Rubyists, LLC (effortless systems) <rubyists@rubyists.com>
|
2
|
+
# Distributed under the terms of the MIT license.
|
3
|
+
# The full text can be found in the LICENSE file included with this software
|
4
|
+
#
|
5
|
+
module FSR
|
6
|
+
module Rack
|
7
|
+
class Middleware
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
params = ::Rack::Request.new(env)
|
14
|
+
return @app.call(env) unless params["section"]
|
15
|
+
|
16
|
+
path = params["section"] + "/"
|
17
|
+
|
18
|
+
path << case path
|
19
|
+
when "dialplan/"
|
20
|
+
dp_req(params)
|
21
|
+
when "directory/"
|
22
|
+
dir_req(params)
|
23
|
+
when "configuration/"
|
24
|
+
conf_req(params)
|
25
|
+
end
|
26
|
+
|
27
|
+
env["PATH_INFO"] = "#{env['PATH_INFO']}/#{path}".squeeze('/')
|
28
|
+
@app.call(env)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def dp_req(params)
|
33
|
+
s = [params["Caller-Context"]]
|
34
|
+
s << params["Caller-Destination-Number"]
|
35
|
+
s << params["Caller-Caller-ID-Number"]
|
36
|
+
s.compact.join("/")
|
37
|
+
end
|
38
|
+
|
39
|
+
def dir_req(params)
|
40
|
+
s = []
|
41
|
+
if params["purpose"]
|
42
|
+
s << params["purpose"].gsub("-","_")
|
43
|
+
s << params["sip_profile"]
|
44
|
+
elsif params["action"] && params["action"] == "sip_auth"
|
45
|
+
s << "register"
|
46
|
+
s << params["sip_profile"]
|
47
|
+
s << params["sip_auth_username"]
|
48
|
+
elsif params["user"]
|
49
|
+
if params["action"] == "message-count"
|
50
|
+
s << "messages"
|
51
|
+
s << params["user"]
|
52
|
+
s << params["key_value"] if params["tag_name"] == "domain"
|
53
|
+
elsif params["Event-Calling-Function"]
|
54
|
+
case params["Event-Calling-Function"].to_s
|
55
|
+
when /voicemail/
|
56
|
+
s << "voicemail"
|
57
|
+
s << (params["sip_profile"] || "default")
|
58
|
+
s << params["user"]
|
59
|
+
when "user_outgoing_channel"
|
60
|
+
s << "user_outgoing"
|
61
|
+
s << params["user"]
|
62
|
+
s << params["domain"] if params["domain"]
|
63
|
+
when "user_data_function"
|
64
|
+
s << "user_data"
|
65
|
+
s << params["user"]
|
66
|
+
s << params["domain"] if params["domain"]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
s.join("/")
|
71
|
+
end
|
72
|
+
|
73
|
+
def conf_req(params)
|
74
|
+
s = []
|
75
|
+
if params["key_name"] == "name"
|
76
|
+
s << params["key_value"]
|
77
|
+
end
|
78
|
+
s.join("/")
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/spec/fsr/app.rb
CHANGED
@@ -49,3 +49,18 @@ describe "Testing FSR::App::PlayAndGetDigits" do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
end
|
52
|
+
|
53
|
+
describe "Testing FSR::App::PlayAndGetDigits - handling of non-existant files" do
|
54
|
+
|
55
|
+
it "Raise if files specifed absolutely aren't present" do
|
56
|
+
lambda { FSR::App::PlayAndGetDigits.new("/path/soundfile.wav", "/path/invalid.wav") }.
|
57
|
+
should.raise(Errno::ENOENT)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "Not raise if files specifed absolutely aren't present" do
|
61
|
+
file_name = File.expand_path(__FILE__)
|
62
|
+
lambda { FSR::App::PlayAndGetDigits.new(file_name, "invalid.wav") }.
|
63
|
+
should.not.raise(Errno::ENOENT)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
data/spec/fsr/app/playback.rb
CHANGED
@@ -9,3 +9,18 @@ describe "Testing FSR::App::Playback" do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
end
|
12
|
+
|
13
|
+
describe "Testing FSR::App::Playback - handling of non-existant files" do
|
14
|
+
|
15
|
+
it "Raise if files specifed absolutely aren't present" do
|
16
|
+
lambda { FSR::App::Playback.new("/path/non-existing.wav") }.
|
17
|
+
should.raise(Errno::ENOENT)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "Not raise if not an absolute file" do
|
21
|
+
file_name = File.expand_path(__FILE__)
|
22
|
+
lambda { FSR::App::Playback.new("shout://scfire-ntc-aa01.stream.aol.com/stream/1035") }.
|
23
|
+
should.not.raise(Errno::ENOENT)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require './spec/helper'
|
2
|
+
require "fsr/cmd"
|
3
|
+
FSR::Cmd.load_command("call_center")
|
4
|
+
|
5
|
+
describe "Testing FSR::Cmd::Callcenter" do
|
6
|
+
## Call Center ##
|
7
|
+
# Interface to mod_callcenter
|
8
|
+
it "FSR::Cmd::Callcenter should list agents " do
|
9
|
+
cmd = FSR::Cmd::CallCenter.new nil, :agent
|
10
|
+
cmd.list.raw.should == "callcenter_config agent list"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "FSR::Cmd::Callcenter should add an agent defaulting callback" do
|
14
|
+
cmd = FSR::Cmd::CallCenter.new nil, :agent
|
15
|
+
cmd.add("1000@default").raw.should == "callcenter_config agent add '1000@default' callback"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "FSR::Cmd::Callcenter should add an agent uuidstandby set" do
|
19
|
+
cmd = FSR::Cmd::CallCenter.new nil, :agent
|
20
|
+
cmd.add("1000@default", "uuid-standby").raw.should == "callcenter_config agent add '1000@default' uuid-standby"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "FSR::Cmd::Callcenter should delete an agent " do
|
24
|
+
cmd = FSR::Cmd::CallCenter.new nil, :agent
|
25
|
+
cmd.del("1000@default").raw.should == "callcenter_config agent del 1000@default"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "FSR::Cmd::Callcenter should set an attribute of an agent " do
|
29
|
+
cmd = FSR::Cmd::CallCenter.new nil, :agent
|
30
|
+
cmd.set("1000@default", :contact, 'user/1000').raw.should == "callcenter_config agent set contact '1000@default' 'user/1000'"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "FSR::Cmd::Callcenter should set an attribute with dashes in it on an agent " do
|
34
|
+
cmd = FSR::Cmd::CallCenter.new nil, :agent
|
35
|
+
cmd.set("1000@default", :max_no_answer, 10).raw.should == "callcenter_config agent set max_no_answer '1000@default' 10"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "FSR::Cmd::Callcenter should list tiers " do
|
39
|
+
cmd = FSR::Cmd::CallCenter.new nil, :tier
|
40
|
+
cmd.list("helpdesk@default").raw.should == "callcenter_config tier list helpdesk@default"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "FSR::Cmd::Callcenter should add a tier " do
|
44
|
+
cmd = FSR::Cmd::CallCenter.new nil, :tier
|
45
|
+
cmd.add("1000@default", "helpdesk@default").raw.should == "callcenter_config tier add helpdesk@default 1000@default 1"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "FSR::Cmd::Callcenter should delete a tier " do
|
49
|
+
cmd = FSR::Cmd::CallCenter.new nil, :tier
|
50
|
+
cmd.del("1000@default", "helpdesk@default").raw.should == "callcenter_config tier del helpdesk@default 1000@default"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "FSR::Cmd::Callcenter should set an attribute of a tier entry " do
|
54
|
+
cmd = FSR::Cmd::CallCenter.new nil, :tier
|
55
|
+
cmd.set("1000@default", "helpdesk@default", :state, "Logged Out").raw.should == "callcenter_config tier set state helpdesk@default 1000@default 'Logged Out'"
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/spec/fsr/cmd/calls.rb
CHANGED
@@ -6,8 +6,8 @@ describe "Testing FSR::Cmd::Calls" do
|
|
6
6
|
## Calls ##
|
7
7
|
# Interface to calls
|
8
8
|
it "FSR::Cmd::Calls should send show calls" do
|
9
|
-
|
10
|
-
|
9
|
+
cmd = FSR::Cmd::Calls.new
|
10
|
+
cmd.raw.should == "show calls"
|
11
11
|
end
|
12
12
|
|
13
13
|
end
|