FreeSWITCHeR 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/License.txt +20 -0
  2. data/NEWS +3 -0
  3. data/README +85 -0
  4. data/Rakefile +82 -0
  5. data/bin/cmd_demo.rb +19 -0
  6. data/bin/ies_demo.rb +19 -0
  7. data/bin/ies_demo_with_hook.rb +27 -0
  8. data/bin/oes_demo.rb +22 -0
  9. data/lib/fsr.rb +86 -0
  10. data/lib/fsr/app.rb +72 -0
  11. data/lib/fsr/app/answer.rb +21 -0
  12. data/lib/fsr/app/bridge.rb +33 -0
  13. data/lib/fsr/app/conference.rb +29 -0
  14. data/lib/fsr/app/fifo.rb +38 -0
  15. data/lib/fsr/app/fs_break.rb +21 -0
  16. data/lib/fsr/app/fs_sleep.rb +24 -0
  17. data/lib/fsr/app/hangup.rb +22 -0
  18. data/lib/fsr/app/log.rb +24 -0
  19. data/lib/fsr/app/playback.rb +23 -0
  20. data/lib/fsr/app/set.rb +22 -0
  21. data/lib/fsr/app/speak.rb +25 -0
  22. data/lib/fsr/app/transfer.rb +24 -0
  23. data/lib/fsr/cmd.rb +57 -0
  24. data/lib/fsr/cmd/fsctl.rb +41 -0
  25. data/lib/fsr/cmd/originate.rb +46 -0
  26. data/lib/fsr/cmd/sofia.rb +40 -0
  27. data/lib/fsr/cmd/sofia/profile.rb +75 -0
  28. data/lib/fsr/cmd/sofia/status.rb +39 -0
  29. data/lib/fsr/cmd/sofia_contact.rb +31 -0
  30. data/lib/fsr/cmd/status.rb +25 -0
  31. data/lib/fsr/command_socket.rb +29 -0
  32. data/lib/fsr/database.rb +7 -0
  33. data/lib/fsr/database/call_limit.rb +21 -0
  34. data/lib/fsr/database/core.rb +30 -0
  35. data/lib/fsr/database/sofia_reg_external.rb +0 -0
  36. data/lib/fsr/database/sofia_reg_internal.rb +0 -0
  37. data/lib/fsr/database/voicemail_default.rb +0 -0
  38. data/lib/fsr/event_socket.rb +41 -0
  39. data/lib/fsr/fake_socket.rb +68 -0
  40. data/lib/fsr/listener.rb +10 -0
  41. data/lib/fsr/listener/header_and_content_response.rb +21 -0
  42. data/lib/fsr/listener/inbound.rb +61 -0
  43. data/lib/fsr/listener/inbound/event.rb +42 -0
  44. data/lib/fsr/listener/outbound.rb +62 -0
  45. data/spec/fsr/app.rb +8 -0
  46. data/spec/fsr/app/bridge.rb +17 -0
  47. data/spec/fsr/app/conference.rb +12 -0
  48. data/spec/fsr/app/fifo.rb +29 -0
  49. data/spec/fsr/cmd.rb +8 -0
  50. data/spec/fsr/cmd/originate.rb +12 -0
  51. data/spec/fsr/cmd/sofia.rb +69 -0
  52. data/spec/fsr/cmd/sofia/profile.rb +58 -0
  53. data/spec/fsr/listener.rb +12 -0
  54. data/spec/fsr/listener/inbound.rb +19 -0
  55. data/spec/fsr/listener/outbound.rb +19 -0
  56. data/spec/fsr/loading.rb +27 -0
  57. data/spec/helper.rb +14 -0
  58. data/tasks/package.rake +29 -0
  59. data/tasks/spec.rake +59 -0
  60. metadata +224 -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
@@ -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
@@ -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
@@ -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
@@ -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