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.
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 +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
@@ -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