freeswitcher 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) 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/bin/oes_demo2.rb +26 -0
  10. data/lib/fsr.rb +86 -0
  11. data/lib/fsr/app.rb +72 -0
  12. data/lib/fsr/app/answer.rb +21 -0
  13. data/lib/fsr/app/bridge.rb +33 -0
  14. data/lib/fsr/app/conference.rb +29 -0
  15. data/lib/fsr/app/fifo.rb +38 -0
  16. data/lib/fsr/app/fs_break.rb +21 -0
  17. data/lib/fsr/app/fs_sleep.rb +24 -0
  18. data/lib/fsr/app/hangup.rb +22 -0
  19. data/lib/fsr/app/log.rb +24 -0
  20. data/lib/fsr/app/playback.rb +23 -0
  21. data/lib/fsr/app/set.rb +22 -0
  22. data/lib/fsr/app/speak.rb +25 -0
  23. data/lib/fsr/app/transfer.rb +24 -0
  24. data/lib/fsr/cmd.rb +57 -0
  25. data/lib/fsr/cmd/fsctl.rb +41 -0
  26. data/lib/fsr/cmd/originate.rb +46 -0
  27. data/lib/fsr/cmd/sofia.rb +40 -0
  28. data/lib/fsr/cmd/sofia/profile.rb +75 -0
  29. data/lib/fsr/cmd/sofia/status.rb +39 -0
  30. data/lib/fsr/cmd/sofia_contact.rb +31 -0
  31. data/lib/fsr/cmd/status.rb +25 -0
  32. data/lib/fsr/command_socket.rb +29 -0
  33. data/lib/fsr/database.rb +7 -0
  34. data/lib/fsr/database/call_limit.rb +21 -0
  35. data/lib/fsr/database/core.rb +30 -0
  36. data/lib/fsr/database/sofia_reg_external.rb +0 -0
  37. data/lib/fsr/database/sofia_reg_internal.rb +0 -0
  38. data/lib/fsr/database/voicemail_default.rb +0 -0
  39. data/lib/fsr/event_socket.rb +41 -0
  40. data/lib/fsr/fake_socket.rb +68 -0
  41. data/lib/fsr/listener.rb +10 -0
  42. data/lib/fsr/listener/header_and_content_response.rb +21 -0
  43. data/lib/fsr/listener/inbound.rb +61 -0
  44. data/lib/fsr/listener/inbound/event.rb +42 -0
  45. data/lib/fsr/listener/outbound.rb +62 -0
  46. data/lib/fsr/listener/outbound.rb.orig +131 -0
  47. data/spec/fsr/app.rb +8 -0
  48. data/spec/fsr/app/bridge.rb +17 -0
  49. data/spec/fsr/app/conference.rb +12 -0
  50. data/spec/fsr/app/fifo.rb +29 -0
  51. data/spec/fsr/cmd.rb +8 -0
  52. data/spec/fsr/cmd/originate.rb +12 -0
  53. data/spec/fsr/cmd/sofia.rb +69 -0
  54. data/spec/fsr/cmd/sofia/profile.rb +58 -0
  55. data/spec/fsr/listener.rb +12 -0
  56. data/spec/fsr/listener/inbound.rb +19 -0
  57. data/spec/fsr/listener/outbound.rb +19 -0
  58. data/spec/fsr/loading.rb +27 -0
  59. data/spec/helper.rb +14 -0
  60. data/tasks/package.rake +29 -0
  61. data/tasks/ride.rake +6 -0
  62. data/tasks/rspec.rake +21 -0
  63. data/tasks/spec.rake +59 -0
  64. metadata +229 -0
@@ -0,0 +1,40 @@
1
+ require "fsr/app"
2
+ module FSR
3
+ module Cmd
4
+ class Sofia < Command
5
+ def initialize(fs_socket = nil)
6
+ @fs_socket = fs_socket # FSR::CommandSocket obj
7
+ end
8
+
9
+ # sofia status
10
+ def status(args = {})
11
+ require "fsr/cmd/sofia/status" # Require sofia/status
12
+ Status.new(@fs_socket, args)
13
+ end
14
+
15
+ # sofia profile
16
+ def profile(args = nil)
17
+ require "fsr/cmd/sofia/profile" # Require sofia/profile
18
+ if args == nil
19
+ Profile.new(@fs_socket, :command_string => "")
20
+ else
21
+ Profile.new(@fs_socket, args)
22
+ end
23
+ end
24
+
25
+ # Send the command to the event socket, using api by default.
26
+ def run(api_method = :api)
27
+ orig_command = "%s %s" % [api_method, raw]
28
+ Log.debug "saying #{orig_command}"
29
+ @fs_socket.say(orig_command)
30
+ end
31
+
32
+ # This method builds the API command to send to the freeswitch event socket
33
+ def raw
34
+ orig_command = "sofia"
35
+ end
36
+ end
37
+
38
+ register(:sofia, Sofia)
39
+ end
40
+ end
@@ -0,0 +1,75 @@
1
+ require "fsr/app"
2
+ module FSR
3
+ module Cmd
4
+ class Sofia
5
+ class Profile < Command
6
+ attr_reader :options
7
+ attr_accessor :fs_socket, :command_string, :name, :action
8
+
9
+ VALID_ACTIONS = [:start, :stop, :restart, :rescan]
10
+ def initialize(fs_socket = nil, options = nil)
11
+ @fs_socket = fs_socket # FSR::CommandSocket object
12
+ if options.kind_of?(String)
13
+ @command_string = options
14
+ else
15
+ raise "options must be a String or Hash" unless options.kind_of?(Hash)
16
+ @options = options
17
+ @action = @options[:action]
18
+ if @action
19
+ raise "Invalid action, must specify one of #{VALID_ACTIONS.inspect}" unless VALID_ACTIONS.include?(@action)
20
+ @name = @options[:name]
21
+ raise "Invalid profile name" unless @name.to_s.match(/\w/)
22
+ else
23
+ @command_string = @options[:command_string] # If user wants to send a raw "sofia profile"
24
+ end
25
+ end
26
+ @command_string ||= ""
27
+ end
28
+
29
+ VALID_ACTIONS.each do |action|
30
+ define_method(action, lambda { |name| @action, @name = action, name;self })
31
+ end
32
+
33
+ # Send the command to the event socket, using api by default.
34
+ def run(api_method = :api)
35
+ orig_command = "%s %s" % [api_method, raw]
36
+ Log.debug "saying #{orig_command}"
37
+ @fs_socket.say(orig_command)
38
+ end
39
+
40
+ def self.start(profile, socket = FSR::CommandSocket.new)
41
+ new(socket, :name => profile, :action => :start)
42
+ end
43
+
44
+ # Restart a sip_profile
45
+ def self.restart(profile, socket = FSR::CommandSocket.new)
46
+ new(socket, :name => profile, :action => :restart)
47
+ end
48
+
49
+ # Stop a sip_profile
50
+ def self.stop(profile, socket = FSR::CommandSocket.new)
51
+ new(socket, :name => profile, :action => :stop)
52
+ end
53
+
54
+ # Rescan a sip_profile
55
+ def self.rescan(profile, socket = FSR::CommandSocket.new)
56
+ new(socket, :name => profile, :action => :rescan)
57
+ end
58
+
59
+ # This method builds the API command to send to the freeswitch event socket
60
+ def raw
61
+ raise "Invalid action, must specify (start|stop|restart|rescan) as an action or pass a command_string" unless @command_string or @action
62
+ if @action
63
+ if @action_options
64
+ "sofia profile %s %s %s" % [@name, @action, @action_options]
65
+ else
66
+ "sofia profile %s %s" % [@name, @action]
67
+ end
68
+ else
69
+ "sofia profile %s" % @command_string
70
+ end.to_s.strip
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,39 @@
1
+ require "fsr/app"
2
+ module FSR
3
+ module Cmd
4
+ class Sofia
5
+ class Status < Command
6
+ attr_reader :fs_socket
7
+
8
+ def initialize(fs_socket = nil, args = {})
9
+ @fs_socket = fs_socket # FSR::CommandSocket object
10
+ @status = args[:status] # Status type; profile or gateway
11
+ @name = args[:name] # Name of profile or gateway
12
+ # If status is given, make sure it's profile or gateway
13
+ unless @status.nil?
14
+ raise "status must be profile or gateway" unless @status =~ /profile|gateway/i
15
+ end
16
+ if @status
17
+ raise "must provide a profile or gateway name" unless @name
18
+ end
19
+ end
20
+
21
+ # Send the command to the event socket, using api by default.
22
+ def run(api_method = :api)
23
+ orig_command = "%s %s" % [api_method, raw]
24
+ Log.debug "saying #{orig_command}"
25
+ @fs_socket.say(orig_command)
26
+ end
27
+
28
+ # This method builds the API command to send to the freeswitch event socket
29
+ def raw
30
+ if @status and @name
31
+ orig_command = "sofia status #{@status} #{@name}"
32
+ else
33
+ orig_command = "sofia status"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,31 @@
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 SofiaContact < Command
8
+ attr_reader :contact
9
+
10
+ def initialize(fs_socket = nil, contact = {})
11
+ @fs_socket = fs_socket # FSR::CommandSocket obj
12
+ @contact = contact[:contact]
13
+ puts @contact
14
+ end
15
+
16
+ # Send the command to the event socket, using api by default.
17
+ def run(api_method = :api)
18
+ orig_command = "%s %s" % [api_method, raw]
19
+ Log.debug "saying #{orig_command}"
20
+ @fs_socket.say(orig_command)
21
+ end
22
+
23
+ # This method builds the API command to send to the freeswitch event socket
24
+ def raw
25
+ orig_command = "sofia_contact #{@contact}"
26
+ end
27
+ end
28
+
29
+ register(:sofia_contact, SofiaContact)
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ require "fsr/app"
2
+ module FSR
3
+ module Cmd
4
+ class Status < Command
5
+
6
+ def initialize(fs_socket = nil)
7
+ @fs_socket = fs_socket # FSR::CommandSocket obj
8
+ end
9
+
10
+ # Send the command to the event socket, using bgapi by default.
11
+ def run(api_method = :api)
12
+ orig_command = "%s %s" % [api_method, raw]
13
+ Log.debug "saying #{orig_command}"
14
+ @fs_socket.say(orig_command)
15
+ end
16
+
17
+ # This method builds the API command to send to the freeswitch event socket
18
+ def raw
19
+ orig_command = "status"
20
+ end
21
+ end
22
+
23
+ register(:status, Status)
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ require "fsr/event_socket"
2
+ require "fsr/cmd"
3
+ module FSR
4
+ class CommandSocket < EventSocket
5
+ include Cmd
6
+
7
+ def initialize(args = {})
8
+ @server = args[:server] || "127.0.0.1"
9
+ @port = args[:port] || "8021"
10
+ @auth = args[:auth] || "ClueCon"
11
+ @socket = TCPSocket.new(@server, @port)
12
+ super(@socket)
13
+ # Attempt to login or raise an exception
14
+ unless login
15
+ raise "Unable to login, check your password!"
16
+ end
17
+ end
18
+
19
+ # Method to authenticate to FreeSWITCH
20
+ def login
21
+ #Clear buf from initial socket creation/opening
22
+ response
23
+ # Send auth string to FreeSWITCH
24
+ self << "auth #{@auth}"
25
+ #Return response, clear buf for rest of commands
26
+ response
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ # Logic to initialize the database here
2
+ require "sequel"
3
+ module FSR
4
+ module Database
5
+ end
6
+ end
7
+
@@ -0,0 +1,21 @@
1
+ require "fsr/database"
2
+ module FSR
3
+ module Database
4
+ module CallLimit
5
+ DB = Sequel.connect("sqlite:///" + File.join(FSR::FS_DB_PATH, "call_limit.db"))
6
+ class LimitData < Sequel::Model
7
+ end
8
+ LimitData.set_dataset :limit_data
9
+
10
+ class DbData < Sequel::Model
11
+ end
12
+ DbData.set_dataset :db_data
13
+
14
+ class GroupData < Sequel::Model
15
+ end
16
+ GroupData.set_dataset :group_data
17
+
18
+ LimitData.db, DbData.db, GroupData.db = [DB] * 3
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ require "fsr/database"
2
+ # This module maps to the Free Switch core.db database
3
+ #
4
+ # TODO Separate these models into their own subdirectories
5
+ module FSR
6
+ module Database
7
+ module Core
8
+ DB = Sequel.connect("sqlite://" + File.join(FSR::FS_DB_PATH, "core.db"))
9
+
10
+ class Complete < Sequel::Model
11
+ end
12
+ Complete.set_dataset :complete
13
+
14
+ class Alias < Sequel::Model
15
+ end
16
+
17
+ class Channel < Sequel::Model
18
+ end
19
+
20
+ class Call < Sequel::Model
21
+ end
22
+
23
+ class Interface < Sequel::Model
24
+ end
25
+
26
+ class Task < Sequel::Model
27
+ end
28
+ end
29
+ end
30
+ end
File without changes
File without changes
File without changes
@@ -0,0 +1,41 @@
1
+ module FSR
2
+ class EventSocket
3
+ attr_reader :socket
4
+
5
+ def initialize(socket)
6
+ @socket = socket
7
+ end
8
+
9
+ # Send a command and return response
10
+ def say(cmd)
11
+ @socket.send("#{cmd}\n\n",0)
12
+ response
13
+ end
14
+
15
+ # Send a command, do not return response
16
+ def <<(cmd)
17
+ @socket.send("#{cmd}\n\n",0)
18
+ end
19
+
20
+ # Grab result from command and create a hash, simple but works.
21
+ def get_header_and_body
22
+ headers, body = {}, ""
23
+ until line = @socket.gets and line.chomp.empty?
24
+ if (kv = line.chomp.split(/:\s+/,2)).size == 2
25
+ headers.store *kv
26
+ end
27
+ end
28
+ if (content_length = headers["Content-Length"].to_i) > 0
29
+ Log.debug "content_length is #{content_length}, grabbing from socket"
30
+ body << @socket.read(content_length)
31
+ end
32
+ headers.merge("body" => body.strip)
33
+ end
34
+
35
+ # Scrub result into a hash
36
+ def response
37
+ get_header_and_body
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,68 @@
1
+ ## Fake socket used for mock testing ##
2
+ #
3
+ require 'stringio'
4
+
5
+ module FSR
6
+ class FakeSocket
7
+ def initialize(remote_host, remote_port)
8
+ @remote_host, @remote_port = remote_host, remote_port
9
+
10
+ @input = StringIO.new('')
11
+ @buffer = []
12
+ end
13
+
14
+ def hostname
15
+ 'localhost'
16
+ end
17
+
18
+ def address
19
+ '127.0.0.1'
20
+ end
21
+
22
+ def eof?
23
+ @input.eof?
24
+ end
25
+ alias closed? eof?
26
+
27
+ def close
28
+ end
29
+
30
+ def print(*args)
31
+ @buffer << args.join
32
+ end
33
+
34
+ def read(len)
35
+ @input.read(len)
36
+ end
37
+
38
+ def fake_input
39
+ @input
40
+ end
41
+
42
+ def fake_buffer
43
+ @buffer
44
+ end
45
+ end
46
+ end
47
+
48
+ require 'bacon'
49
+ Bacon.summary_at_exit
50
+
51
+ describe FSR::FakeSocket do
52
+ it 'can be initialized' do
53
+ @socket = FSR::FakeSocket.new('google.com', 80)
54
+ @socket.should.not.be.nil
55
+ end
56
+
57
+ it 'can be filled with input which is then read' do
58
+ @socket.fake_input.write('foobar')
59
+ @socket.fake_input.pos = 0
60
+ @socket.read(6).should == 'foobar'
61
+ @socket.read(1).should == nil
62
+ end
63
+
64
+ it 'can receive input' do
65
+ @socket.print('foo')
66
+ @socket.fake_buffer.should == ['foo']
67
+ end
68
+ end
@@ -0,0 +1,10 @@
1
+ module FSR
2
+ module Listener
3
+
4
+ def receive_data(data)
5
+ FSR::Log.debug "Received #{data}"
6
+ end
7
+
8
+ end
9
+ end
10
+ FSL = FSR::Listener
@@ -0,0 +1,21 @@
1
+ require 'fsr/listener'
2
+
3
+ module FSR
4
+ module Listener
5
+ class HeaderAndContentResponse
6
+
7
+ attr_reader :headers, :content
8
+
9
+ def initialize(args = {})
10
+ @headers = args[:headers]
11
+ @content = args[:content]
12
+ end
13
+
14
+ # Keep backward compat with the other 2 people who use FSR
15
+ def body
16
+ @content
17
+ end
18
+
19
+ end
20
+ end
21
+ end