bougyman-freeswitcher 0.0.9
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/License.txt +20 -0
- data/NEWS +3 -0
- data/README +85 -0
- data/Rakefile +82 -0
- data/bin/cmd_demo.rb +19 -0
- data/bin/ies_demo.rb +19 -0
- data/bin/ies_demo_with_hook.rb +27 -0
- data/bin/oes_demo.rb +22 -0
- data/lib/fsr.rb +86 -0
- data/lib/fsr/app.rb +72 -0
- data/lib/fsr/app/answer.rb +21 -0
- data/lib/fsr/app/bridge.rb +33 -0
- data/lib/fsr/app/conference.rb +29 -0
- data/lib/fsr/app/fifo.rb +38 -0
- data/lib/fsr/app/fs_break.rb +21 -0
- data/lib/fsr/app/fs_sleep.rb +24 -0
- data/lib/fsr/app/hangup.rb +22 -0
- data/lib/fsr/app/log.rb +24 -0
- data/lib/fsr/app/playback.rb +23 -0
- data/lib/fsr/app/set.rb +22 -0
- data/lib/fsr/app/speak.rb +25 -0
- data/lib/fsr/app/transfer.rb +24 -0
- data/lib/fsr/cmd.rb +57 -0
- data/lib/fsr/cmd/fsctl.rb +41 -0
- data/lib/fsr/cmd/originate.rb +46 -0
- data/lib/fsr/cmd/sofia.rb +40 -0
- data/lib/fsr/cmd/sofia/profile.rb +75 -0
- data/lib/fsr/cmd/sofia/status.rb +39 -0
- data/lib/fsr/cmd/sofia_contact.rb +31 -0
- data/lib/fsr/cmd/status.rb +25 -0
- data/lib/fsr/command_socket.rb +29 -0
- data/lib/fsr/database.rb +7 -0
- data/lib/fsr/database/call_limit.rb +21 -0
- data/lib/fsr/database/core.rb +30 -0
- data/lib/fsr/database/sofia_reg_external.rb +0 -0
- data/lib/fsr/database/sofia_reg_internal.rb +0 -0
- data/lib/fsr/database/voicemail_default.rb +0 -0
- data/lib/fsr/event_socket.rb +41 -0
- data/lib/fsr/fake_socket.rb +68 -0
- data/lib/fsr/listener.rb +10 -0
- data/lib/fsr/listener/header_and_content_response.rb +21 -0
- data/lib/fsr/listener/inbound.rb +61 -0
- data/lib/fsr/listener/inbound/event.rb +42 -0
- data/lib/fsr/listener/outbound.rb +62 -0
- data/spec/fsr/app.rb +8 -0
- data/spec/fsr/app/bridge.rb +17 -0
- data/spec/fsr/app/conference.rb +12 -0
- data/spec/fsr/app/fifo.rb +29 -0
- data/spec/fsr/cmd.rb +8 -0
- data/spec/fsr/cmd/originate.rb +12 -0
- data/spec/fsr/cmd/sofia.rb +69 -0
- data/spec/fsr/cmd/sofia/profile.rb +58 -0
- data/spec/fsr/listener.rb +12 -0
- data/spec/fsr/listener/inbound.rb +19 -0
- data/spec/fsr/listener/outbound.rb +19 -0
- data/spec/fsr/loading.rb +27 -0
- data/spec/helper.rb +14 -0
- data/tasks/package.rake +29 -0
- data/tasks/spec.rake +59 -0
- metadata +229 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Answer < Application
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def arguments
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
|
13
|
+
def sendmsg
|
14
|
+
"call-command: execute\nexecute-app-name: %s\n\n" % [app_name]
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
register(:answer, Answer)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Bridge < Application
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(target, opts = {})
|
9
|
+
# These are options that will precede the target address
|
10
|
+
@target = target
|
11
|
+
@options = opts || {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def arguments
|
15
|
+
[@target]
|
16
|
+
end
|
17
|
+
|
18
|
+
def modifiers
|
19
|
+
@options.map { |k,v| "%s=%s" % [k, v] }.join(",")
|
20
|
+
end
|
21
|
+
|
22
|
+
def raw
|
23
|
+
"%s({%s}%s)" % [app_name, modifiers, arguments.join(" ")]
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.execute(target, opts = {})
|
27
|
+
self.new(target, opts).raw
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
register(:bridge, Bridge)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Conference < Application
|
6
|
+
attr_reader :target, :profile
|
7
|
+
|
8
|
+
def initialize(conference_name, conference_profile = nil)
|
9
|
+
# These are options that will precede the target address
|
10
|
+
@target = conference_name
|
11
|
+
@profile = conference_profile || "ultrawideband"
|
12
|
+
end
|
13
|
+
|
14
|
+
def arguments
|
15
|
+
["%s@%s" % [@target, @profile]]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.execute(conference_name, conference_profile = nil)
|
19
|
+
self.new(conference_name, conference_profile).raw
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.[](conference_name)
|
23
|
+
self.execute(conference_name)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
register(:conference, Conference)
|
28
|
+
end
|
29
|
+
end
|
data/lib/fsr/app/fifo.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Fifo < Application
|
6
|
+
attr_accessor :name, :direction
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
def self.<<(name)
|
10
|
+
new(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.>>(name)
|
14
|
+
new(name, "out", :wait => true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(name, direction = nil, options = nil)
|
18
|
+
# These are options that will precede the target address
|
19
|
+
@name = name
|
20
|
+
@direction = direction || "in"
|
21
|
+
raise "Direction must be 'in' or 'out'" unless @direction.match(/^(?:in|out)$/)
|
22
|
+
@options = options || {}
|
23
|
+
raise "options must be a hash" unless @options.kind_of?(Hash)
|
24
|
+
end
|
25
|
+
|
26
|
+
def arguments
|
27
|
+
@args = [@name, @direction]
|
28
|
+
if @direction == "out"
|
29
|
+
@args << (options[:wait] ? "wait" : "nowait")
|
30
|
+
end
|
31
|
+
@args
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
register(:fifo, Fifo)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class FSBreak < Application
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def arguments
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
|
13
|
+
def sendmsg
|
14
|
+
"call-command: execute\nexecute-app-name: break\n\n"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
register(:fs_break, FSBreak)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class FSSleep < Application
|
6
|
+
attr_reader :milliseconds
|
7
|
+
|
8
|
+
def initialize(milliseconds)
|
9
|
+
# milliseconds to sleep
|
10
|
+
@milliseconds = milliseconds
|
11
|
+
end
|
12
|
+
def arguments
|
13
|
+
[@milliseconds]
|
14
|
+
end
|
15
|
+
|
16
|
+
def sendmsg
|
17
|
+
"call-command: execute\nexecute-app-name: sleep\nexecute-app-arg: %s\n\n" % [arguments.join(" ")]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
register(:fs_sleep, FSSleep)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module App
|
4
|
+
# http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_hangup
|
5
|
+
class Hangup < Application
|
6
|
+
def initialize(data = nil)
|
7
|
+
@data = data
|
8
|
+
end
|
9
|
+
|
10
|
+
def arguments
|
11
|
+
@data
|
12
|
+
end
|
13
|
+
|
14
|
+
def sendmsg
|
15
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\n\n" % [app_name, arguments]
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
register(:hangup, Hangup)
|
21
|
+
end
|
22
|
+
end
|
data/lib/fsr/app/log.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module App
|
4
|
+
# http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_log
|
5
|
+
class Log < Application
|
6
|
+
attr_reader :level, :text
|
7
|
+
|
8
|
+
def initialize(level = 1, text = "")
|
9
|
+
@level = level
|
10
|
+
@text = text
|
11
|
+
end
|
12
|
+
|
13
|
+
def arguments
|
14
|
+
[@level, @text]
|
15
|
+
end
|
16
|
+
|
17
|
+
def sendmsg
|
18
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join(" ")]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
register(:log, Log)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Playback < Application
|
6
|
+
attr_reader :wavfile
|
7
|
+
|
8
|
+
def initialize(wavfile)
|
9
|
+
# wav file you wish to play, full path
|
10
|
+
@wavfile = wavfile
|
11
|
+
end
|
12
|
+
def arguments
|
13
|
+
[@wavfile]
|
14
|
+
end
|
15
|
+
|
16
|
+
def sendmsg
|
17
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join(" ")]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
register(:playback, Playback)
|
22
|
+
end
|
23
|
+
end
|
data/lib/fsr/app/set.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module App
|
4
|
+
# http://wiki.freeswitch.org/wiki/Misc._Dialplan_Tools_set
|
5
|
+
class Set < Application
|
6
|
+
def initialize(key, value)
|
7
|
+
@key = key
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def arguments
|
12
|
+
[@key, @value]
|
13
|
+
end
|
14
|
+
|
15
|
+
def sendmsg
|
16
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join("=")]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
register(:set, Set)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require "fsr/app"
|
3
|
+
module FSR
|
4
|
+
module App
|
5
|
+
class Speak < Application
|
6
|
+
attr_reader :message
|
7
|
+
|
8
|
+
def initialize(message, opts = {})
|
9
|
+
# wav file you wish to play, full path
|
10
|
+
@message = message
|
11
|
+
@voice = opts[:voice] || "slt"
|
12
|
+
end
|
13
|
+
|
14
|
+
def arguments
|
15
|
+
["flite", @voice, @message]
|
16
|
+
end
|
17
|
+
|
18
|
+
def sendmsg
|
19
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join("|")]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
register(:speak, Speak)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module App
|
4
|
+
class Transfer < Application
|
5
|
+
attr_reader :destination_number, :dialplan, :context
|
6
|
+
|
7
|
+
def initialize(destination_number, dialplan = nil, context = nil)
|
8
|
+
@destination_number = destination_number
|
9
|
+
@dialplan = dialplan || "XML"
|
10
|
+
@context = context || "default"
|
11
|
+
end
|
12
|
+
|
13
|
+
def arguments
|
14
|
+
[@destination_number, @dialplan, @context]
|
15
|
+
end
|
16
|
+
|
17
|
+
def sendmsg
|
18
|
+
"call-command: execute\nexecute-app-name: %s\nexecute-app-arg: %s\nevent-lock:true\n\n" % [app_name, arguments.join(" ")]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
register(:transfer, Transfer)
|
23
|
+
end
|
24
|
+
end
|
data/lib/fsr/cmd.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module FSR
|
2
|
+
module Cmd
|
3
|
+
class Command
|
4
|
+
end
|
5
|
+
|
6
|
+
COMMANDS = {}
|
7
|
+
LOAD_PATH = [File.join(FSR::ROOT, "fsr", "cmd")]
|
8
|
+
|
9
|
+
def self.register(command, obj)
|
10
|
+
COMMANDS[command.to_sym] = obj
|
11
|
+
|
12
|
+
code = "def %s(*args, &block) COMMANDS[%p].new(self, *args, &block) end" % [command, command]
|
13
|
+
Cmd.module_eval(code)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.list
|
17
|
+
COMMANDS.keys
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.load_command(command, force_reload = false)
|
21
|
+
# If we get a path specification and it's an existing file, load it
|
22
|
+
if File.file?(command)
|
23
|
+
if force_reload
|
24
|
+
return load(command)
|
25
|
+
else
|
26
|
+
return require(command)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
Log.debug "Trying load paths"
|
30
|
+
# If we find a file named the same as the command passed in LOAD_PATH, load it
|
31
|
+
if found_command_path = LOAD_PATH.detect { |command_path| File.file?(File.join(command_path, "#{command}.rb")) }
|
32
|
+
command_file = Pathname.new(found_command_path).join(command)
|
33
|
+
Log.debug "Trying to load #{command_file}"
|
34
|
+
if force_reload
|
35
|
+
load command_file.to_s + ".rb"
|
36
|
+
else
|
37
|
+
require command_file
|
38
|
+
end
|
39
|
+
else
|
40
|
+
raise "#{command} not found in #{LOAD_PATH.join(":")}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Load all of the commands we find in Cmd::LOAD_PATH
|
45
|
+
def self.load_all(force_reload = false)
|
46
|
+
LOAD_PATH.each do |load_path|
|
47
|
+
Dir[File.join(load_path, "*.rb")].each { |command_file| load_command(command_file, force_reload) }
|
48
|
+
end
|
49
|
+
list
|
50
|
+
end
|
51
|
+
|
52
|
+
def commands
|
53
|
+
FSR::Cmd.list
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
FSC = FSR::Cmd
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# A lot of methods are missing here. The only one implemented is max_sessions
|
2
|
+
# The max_sessions getter currently returns the raw result but could instead return an Integer
|
3
|
+
|
4
|
+
require "fsr/app"
|
5
|
+
module FSR
|
6
|
+
module Cmd
|
7
|
+
class Fsctl < Command
|
8
|
+
attr_reader :command
|
9
|
+
|
10
|
+
def initialize(fs_socket = nil)
|
11
|
+
@fs_socket = fs_socket # FSR::CommandSocket obj
|
12
|
+
end
|
13
|
+
|
14
|
+
# Get max sessions
|
15
|
+
def max_sessions
|
16
|
+
@command = "max_sessions"
|
17
|
+
run
|
18
|
+
end
|
19
|
+
|
20
|
+
# Set max sessions
|
21
|
+
def max_sessions=(sessions)
|
22
|
+
@command = "max_sessions #{sessions}"
|
23
|
+
run
|
24
|
+
end
|
25
|
+
|
26
|
+
# Send the command to the event socket, using api by default.
|
27
|
+
def run(api_method = :api)
|
28
|
+
orig_command = "%s %s" % [api_method, raw]
|
29
|
+
Log.debug "saying #{orig_command}"
|
30
|
+
@fs_socket.say(orig_command)
|
31
|
+
end
|
32
|
+
|
33
|
+
# This method builds the API command to send to the freeswitch event socket
|
34
|
+
def raw
|
35
|
+
orig_command = "fsctl #{@command}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
register(:fsctl, Fsctl)
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "fsr/app"
|
2
|
+
module FSR
|
3
|
+
module Cmd
|
4
|
+
class Originate < Command
|
5
|
+
attr_accessor :target, :endpoint
|
6
|
+
attr_reader :fs_socket, :target_options
|
7
|
+
|
8
|
+
def initialize(fs_socket = nil, args = {})
|
9
|
+
# These are options that will precede the target address
|
10
|
+
@target_options = args[:target_options] || {:ignore_early_media => true}
|
11
|
+
raise "#{@target_options} must be a hash" unless @target_options.kind_of?(Hash)
|
12
|
+
|
13
|
+
@fs_socket = fs_socket # This socket must support say and <<
|
14
|
+
@target = args[:target] # The target address to call
|
15
|
+
# The origination endpoint (can be an extension (use a string) or application)
|
16
|
+
@endpoint = args[:endpoint] || args[:application]
|
17
|
+
|
18
|
+
@target_options[:origination_caller_id_number] ||= args[:caller_id_number] || FSR::DEFAULT_CALLER_ID_NUMBER
|
19
|
+
@target_options[:origination_caller_id_name] ||= args[:caller_id_name] || FSR::DEFAULT_CALLER_ID_NAME
|
20
|
+
@target_options[:originate_timeout] ||= args[:timeout] || @target_options[:timeout] || 30
|
21
|
+
@target_options[:ignore_early_media] ||= true
|
22
|
+
end
|
23
|
+
|
24
|
+
# Send the command to the event socket, using bgapi by default.
|
25
|
+
def run(api_method = :bgapi)
|
26
|
+
orig_command = "%s %s" % [api_method, raw]
|
27
|
+
Log.debug "saying #{orig_command}"
|
28
|
+
@fs_socket.say(orig_command)
|
29
|
+
end
|
30
|
+
|
31
|
+
# This method builds the API command to send to the freeswitch event socket
|
32
|
+
def raw
|
33
|
+
target_opts = @target_options.keys.sort { |a,b| a.to_s <=> b.to_s }.map { |k| "%s=%s" % [k, @target_options[k]] }.join(",")
|
34
|
+
if @endpoint.kind_of?(String)
|
35
|
+
orig_command = "originate {#{target_opts}}#{@target} #{@endpoint}"
|
36
|
+
elsif @endpoint.kind_of?(FSR::App::Application)
|
37
|
+
orig_command = "originate {#{target_opts}}#{@target} '&#{@endpoint.raw}'"
|
38
|
+
else
|
39
|
+
raise "Invalid endpoint"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
register(:originate, Originate)
|
45
|
+
end
|
46
|
+
end
|