ruby-asterisk 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,3 @@
1
+ ## v0.0.1
2
+
3
+ * Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rami.gemspec
4
+ gemspec
@@ -0,0 +1,87 @@
1
+ # RUBY-ASTERISK
2
+
3
+ This gem add support to your Ruby or RubyOnRails projects to Asterisk Manager Interface
4
+
5
+ There was a project with the same name, but it appears to be discontinued so I decided to start a new project
6
+
7
+ ## Installation
8
+
9
+ ### Rails3
10
+
11
+ Add to your Gemfile and run the `bundle` command to install it.
12
+
13
+ ```ruby
14
+ gem "ruby-asterisk"
15
+ ```
16
+
17
+ ### Rails2
18
+
19
+ Simply run in your terminal
20
+
21
+ ```ruby
22
+ gem install ruby-asterisk
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ### INITIALIZE
28
+
29
+ To create a new AMI session, just call the following command
30
+
31
+ ```ruby
32
+ @ami = RubyAsterisk::AMI.new("192.168.1.1",5038)
33
+ ```
34
+
35
+ ### LOGIN
36
+
37
+ To log in, provide to the created sessions a valid username and password
38
+
39
+ ```ruby
40
+ @ami.login("mark","mysecret")
41
+ ```
42
+
43
+ Like all commands, it will return a Response command that could be parsed accordingly
44
+
45
+ ### CORE SHOW CHANNELS
46
+
47
+ To get a list of all channels currently active on your Asterisk installation, use the following command
48
+
49
+ ```ruby
50
+ @ami.core_show_channels
51
+ ```
52
+
53
+ ### PARKED CALLS
54
+
55
+ To get a list of all parked calls on your Asterisk PBX, use the following command
56
+
57
+ ```ruby
58
+ @ami.parked_calls
59
+ ```
60
+
61
+ ### ORIGINATE
62
+
63
+ To start a new call use the following command
64
+
65
+ ```ruby
66
+ @ami.originate("SIP/9100","OUTGOING","123456","1") # CALLER, CONTEXT, CALLEE, PRIORITY
67
+ ```
68
+
69
+
70
+ ### THE RESPONSE OBJECT
71
+
72
+ The response object contains all information about all data received from Asterisk. Here follows a list of all object's properties:
73
+
74
+ - type
75
+ - success
76
+ - action_id
77
+ - message
78
+ - data
79
+
80
+ The data property contains all additional information obtained from Asterisk, like for example the list of active channels after a "core show channels" command.
81
+
82
+ ## Development
83
+
84
+ Questions or problems? Please post them on the [issue tracker](https://github.com/emilianodellacasa/ruby-asterisk/issues). You can contribute changes by forking the project and submitting a pull request. You can ensure the tests passing by running `bundle` and `rake`.
85
+
86
+ This gem is created by Emiliano Della Casa and is under the MIT License and it is distributed by courtesy of [Engim srl](http://www.engim.eu/en).
87
+
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec'
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,84 @@
1
+ require "ruby-asterisk/version"
2
+ require "ruby-asterisk/request"
3
+ require "ruby-asterisk/response"
4
+
5
+ require 'net/telnet'
6
+
7
+ module RubyAsterisk
8
+ class AMI
9
+ attr_accessor :host, :port, :connected
10
+
11
+ def initialize(host,port)
12
+ self.host = host.to_s
13
+ self.port = port.to_i
14
+ self.connected = false
15
+ @session = nil
16
+ end
17
+
18
+ def connect
19
+ begin
20
+ @session = Net::Telnet::new("Host" => self.host,"Port" => self.port)
21
+ self.connected = true
22
+ rescue Exception => ex
23
+ false
24
+ end
25
+ end
26
+
27
+ def disconnect
28
+ begin
29
+ @session.close if self.connected
30
+ @session = nil
31
+ self.connected = false
32
+ true
33
+ rescue Exception => ex
34
+ puts ex
35
+ false
36
+ end
37
+ end
38
+
39
+ def login(username,password)
40
+ self.connect unless self.connected
41
+ request = Request.new("Login",{"Username" => username, "Secret" => password})
42
+ request.commands.each do |command|
43
+ @session.write(command)
44
+ end
45
+ @session.waitfor("String" => "ActionID: "+request.action_id, "Timeout" => 3) do |data|
46
+ request.response_data << data
47
+ end
48
+ Response.new("Login",request.response_data)
49
+ end
50
+
51
+ def core_show_channels
52
+ request = Request.new("CoreShowChannels")
53
+ request.commands.each do |command|
54
+ @session.write(command)
55
+ end
56
+ @session.waitfor("String" => "ActionID: "+request.action_id, "Timeout" => 3) do |data|
57
+ request.response_data << data
58
+ end
59
+ Response.new("CoreShowChannels",request.response_data)
60
+ end
61
+
62
+ def parked_calls
63
+ request = Request.new("ParkedCalls")
64
+ request.commands.each do |command|
65
+ @session.write(command)
66
+ end
67
+ @session.waitfor("String" => "ActionID: "+request.action_id, "Timeout" => 3) do |data|
68
+ request.response_data << data
69
+ end
70
+ Response.new("ParkedCalls",request.response_data)
71
+ end
72
+
73
+ def originate(caller,context,callee,priority)
74
+ request = Request.new("Originate",{"Channel" => caller, "Context" => context, "Exten" => callee, "Priority" => priority, "Callerid" => caller, "Timeout" => "30000" })
75
+ request.commands.each do |command|
76
+ @session.write(command)
77
+ end
78
+ @session.waitfor("String" => "ActionID: "+request.action_id, "Timeout" => 30) do |data|
79
+ request.response_data << data
80
+ end
81
+ Response.new("Originate",request.response_data)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,28 @@
1
+ module RubyAsterisk
2
+ class Request
3
+ attr_accessor :action, :action_id, :parameters, :response_data
4
+
5
+ def initialize(action,parameters={})
6
+ self.action = action
7
+ self.action_id = self.generate_action_id
8
+ self.parameters = parameters
9
+ self.response_data = ""
10
+ end
11
+
12
+ def commands
13
+ _commands=["Action: "+self.action+"\r\n","ActionID: "+self.action_id+"\r\n"]
14
+ self.parameters.each do |key,value|
15
+ _commands<<key+": "+value+"\r\n"
16
+ end
17
+ _commands[_commands.length-1]<<"\r\n"
18
+ _commands
19
+ end
20
+
21
+ protected
22
+
23
+ def generate_action_id
24
+ Random.rand(999).to_s
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,79 @@
1
+ module RubyAsterisk
2
+ class Response
3
+ attr_accessor :type, :success, :action_id, :message, :data
4
+
5
+ def initialize(type,response)
6
+ self.type = type
7
+ self.success = self._parse_successfull(response)
8
+ self.action_id = self._parse_action_id(response)
9
+ self.message = self._parse_message(response)
10
+ self.data = self._parse_data(response)
11
+ end
12
+
13
+ protected
14
+
15
+ def _parse_successfull(response)
16
+ response.include?("Response: Success")
17
+ end
18
+
19
+ def _parse_action_id(response)
20
+ _action_id = self._parse(response,"ActionID:")
21
+ end
22
+
23
+ def _parse_message(response)
24
+ _message = self._parse(response,"Message:")
25
+ end
26
+
27
+ def _parse(response,field)
28
+ _value = nil
29
+ response.each_line do |line|
30
+ if line.start_with?(field)
31
+ _value = line[line.rindex(":")+1..line.size].strip
32
+ end
33
+ end
34
+ _value
35
+ end
36
+
37
+ def _parse_data(response)
38
+ case self.type
39
+ when "CoreShowChannels"
40
+ self._parse_data_core_show_channels(response)
41
+ when "ParkedCalls"
42
+ self._parse_data_parked_calls(response)
43
+ when "Originate"
44
+ self._parse_originate_calls(response)
45
+ end
46
+ end
47
+
48
+ def _parse_originate_calls(response)
49
+ self._parse_objects(response,:dial,"Event: Dial")
50
+ end
51
+
52
+ def _parse_data_parked_calls(response)
53
+ self._parse_objects(response,:calls,"Event: ParkedCall")
54
+ end
55
+
56
+ def _parse_data_core_show_channels(response)
57
+ self._parse_objects(response,:channels,"Event: CoreShowChannel")
58
+ end
59
+
60
+ def _parse_objects(response,symbol_name,search_for)
61
+ _data = { symbol_name => [] }
62
+ parsing = false
63
+ object = nil
64
+ response.each_line do |line|
65
+ if line.start_with?(search_for)
66
+ _data[symbol_name] << object unless object.nil?
67
+ object = {}
68
+ parsing = true
69
+ elsif line.strip.empty?
70
+ parsing = false
71
+ elsif parsing
72
+ object[line.split(':')[0].strip]=line.split(':')[1].strip unless line.split(':')[1].nil?
73
+ end
74
+ end
75
+ _data[symbol_name] << object unless object.nil?
76
+ _data
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,3 @@
1
+ module Rami
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "ruby-asterisk/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "ruby-asterisk"
7
+ s.version = Rami::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Emiliano Della Casa"]
10
+ s.email = ["e.dellacasa@engim.eu"]
11
+ s.homepage = "http://github.com/emilianodellacasa/ruby-asterisk"
12
+ s.summary = %q{Asterisk Manager Interface in Ruby}
13
+ s.description = %q{Add support to your ruby or rails projects to Asterisk Manager Interface (AMI)}
14
+
15
+ s.rubyforge_project = "ruby-asterisk"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency "rake"
23
+ s.add_development_dependency 'rspec'
24
+ end
@@ -0,0 +1,88 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ describe RubyAsterisk::Response do
4
+
5
+ def core_show_channels_response
6
+ "Event: CoreShowChannel
7
+ ActionID: 839
8
+ Channel: SIP/195.62.226.4-00000025
9
+ UniqueID: 1335448133.61
10
+ Context: incoming
11
+ Extension: s
12
+ Priority: 1
13
+ ChannelState: 6
14
+ ChannelStateDesc: Up
15
+ Application: Parked Call
16
+ ApplicationData:
17
+ CallerIDnum: 3335313510
18
+ CallerIDname:
19
+ ConnectedLineNum:
20
+ ConnectedLineName:
21
+ Duration: 00:00:05
22
+ AccountCode:
23
+ BridgedChannel:
24
+ BridgedUniqueID:"
25
+ end
26
+
27
+ def parked_calls_response
28
+ "Event: ParkedCall
29
+ Parkinglot: default
30
+ Exten: 701
31
+ Channel: SIP/195.62.226.2-00000026
32
+ From: SIP/195.62.226.2-00000026
33
+ Timeout: 3
34
+ CallerIDNum: 3335313510
35
+ CallerIDName:
36
+ ConnectedLineNum:
37
+ ConnectedLineName:
38
+ ActionID: 899"
39
+ end
40
+
41
+ def originate_response
42
+ "Event: Dial
43
+ Privilege: call,all
44
+ SubEvent: End
45
+ Channel: SIP/9100-0000002b
46
+ UniqueID: 1335457364.68
47
+ DialStatus: CHANUNAVAIL"
48
+ end
49
+
50
+ describe ".new" do
51
+
52
+ describe "receiving a Core Show Channels request" do
53
+ it "should parse correctly data coming from Asterisk about channels" do
54
+ @response = RubyAsterisk::Response.new("CoreShowChannels",core_show_channels_response)
55
+ @response.data[:channels].should_not be_empty
56
+ end
57
+
58
+ it "should correctly fill the fields" do
59
+ @response = RubyAsterisk::Response.new("CoreShowChannels",core_show_channels_response)
60
+ @response.data[:channels][0]["CallerIDnum"].should eq("3335313510")
61
+ end
62
+ end
63
+
64
+ describe "receiving a Parked Calls request" do
65
+ it "should parse correctly data coming from Asterisk about calls" do
66
+ @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
67
+ @response.data[:calls].should_not be_empty
68
+ end
69
+
70
+ it "should correctly fill the fields" do
71
+ @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
72
+ @response.data[:calls][0]["Exten"].should eq("701")
73
+ end
74
+ end
75
+
76
+ describe "resceiving a Originate request" do
77
+ it "should parse correctly data coming from Asterisk about the call" do
78
+ @response = RubyAsterisk::Response.new("Originate",originate_response)
79
+ @response.data[:dial].should_not be_empty
80
+ end
81
+
82
+ it "should correctly fill the fields" do
83
+ @response = RubyAsterisk::Response.new("Originate",originate_response)
84
+ @response.data[:dial][0]["UniqueID"].should eq("1335457364.68")
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,143 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ describe RubyAsterisk do
4
+
5
+ def core_show_channels_response
6
+ "Event: CoreShowChannel
7
+ ActionID: 839
8
+ Channel: SIP/195.62.226.4-00000025
9
+ UniqueID: 1335448133.61
10
+ Context: incoming
11
+ Extension: s
12
+ Priority: 1
13
+ ChannelState: 6
14
+ ChannelStateDesc: Up
15
+ Application: Parked Call
16
+ ApplicationData:
17
+ CallerIDnum: 3335313510
18
+ CallerIDname:
19
+ ConnectedLineNum:
20
+ ConnectedLineName:
21
+ Duration: 00:00:05
22
+ AccountCode:
23
+ BridgedChannel:
24
+ BridgedUniqueID:"
25
+ end
26
+
27
+ def mock_request(stubs={})
28
+ (@mock_request ||= mock_model(RubyAsterisk::Request).as_null_object).tap do |request|
29
+ request.stub(stubs) unless stubs.empty?
30
+ end
31
+ end
32
+
33
+ before :each do
34
+ @session = RubyAsterisk::AMI.new("127.0.0.1",5038)
35
+ end
36
+
37
+ after :each do
38
+ @session.disconnect
39
+ end
40
+
41
+ describe ".new" do
42
+ it "initialize session with host" do
43
+ @session.host.should eq("127.0.0.1")
44
+ end
45
+
46
+ it "initialize session with host" do
47
+ @session.port.should eq(5038)
48
+ end
49
+
50
+ it "should start the session as disconnected" do
51
+ @session.connected.should_not be_true
52
+ end
53
+ end
54
+
55
+ describe ".connect" do
56
+ it "should return true if everything is ok" do
57
+ @session.connect.should be_true
58
+ end
59
+
60
+ it "should return false if everything if something went wrong" do
61
+ @session.port = 666
62
+ @session.connect.should_not be_true
63
+ @session.port = 5038
64
+ end
65
+
66
+ it "should change state to session as connected" do
67
+ @session.connect
68
+ @session.connected.should be_true
69
+ end
70
+ end
71
+
72
+ describe ".disconnect" do
73
+ it "should return true if everything is ok" do
74
+ @session.disconnect.should be_true
75
+ end
76
+
77
+ it "should change state to session as disconnected" do
78
+ @session.disconnect
79
+ @session.connected.should_not be_true
80
+ end
81
+ end
82
+
83
+ describe ".login" do
84
+ it "should return a response object" do
85
+ @session.login("mark","mysecret").should be_kind_of(RubyAsterisk::Response)
86
+ end
87
+
88
+ it "should return a response with type Login" do
89
+ @session.login("mark","mysecret").type.should eq("Login")
90
+ end
91
+
92
+ describe "if everything is ok" do
93
+ it "should return a successfull response" do
94
+ @session.login("mark","mysecret").success.should be_true
95
+ end
96
+
97
+ it "should fill the ActionID" do
98
+ @session.login("mark","mysecret").action_id.should_not be_nil
99
+ end
100
+
101
+ it "should fill the Message" do
102
+ @session.login("mark","mysecret").message.should_not be_nil
103
+ end
104
+ end
105
+
106
+ describe "if credentials are wrong" do
107
+ it "should not return a successfull response" do
108
+ @session.login("mark","wrong").success.should be_false
109
+ end
110
+ end
111
+ end
112
+
113
+ describe ".core_show_channels" do
114
+ it "should return a response object" do
115
+ @session.login("mark","mysecret")
116
+ @session.core_show_channels.should be_kind_of(RubyAsterisk::Response)
117
+ end
118
+
119
+ it "should contain additional data about channels" do
120
+ @session.login("mark","mysecret")
121
+ @session.core_show_channels.data[:channels].should_not be_nil
122
+ end
123
+ end
124
+
125
+ describe ".parked_calls" do
126
+ it "should return a response object" do
127
+ @session.login("mark","mysecret")
128
+ @session.parked_calls.should be_kind_of(RubyAsterisk::Response)
129
+ end
130
+
131
+ it "should contain additional data about parked calls" do
132
+ @session.login("mark","mysecret")
133
+ @session.parked_calls.data[:calls].should_not be_nil
134
+ end
135
+ end
136
+
137
+ describe ".originate" do
138
+ it "should return a response object" do
139
+ @session.login("mark","mysecret")
140
+ @session.originate("SIP/9100","OUTGOING","123456","1").should be_kind_of(RubyAsterisk::Response)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ require 'ruby-asterisk'
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-asterisk
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Emiliano Della Casa
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-04-27 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :development
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :development
36
+ version_requirements: *id002
37
+ description: Add support to your ruby or rails projects to Asterisk Manager Interface (AMI)
38
+ email:
39
+ - e.dellacasa@engim.eu
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - .gitignore
48
+ - .rspec
49
+ - CHANGELOG
50
+ - Gemfile
51
+ - README.md
52
+ - Rakefile
53
+ - lib/ruby-asterisk.rb
54
+ - lib/ruby-asterisk/request.rb
55
+ - lib/ruby-asterisk/response.rb
56
+ - lib/ruby-asterisk/version.rb
57
+ - ruby-asterisk.gemspec
58
+ - spec/ruby-asterisk/response_spec.rb
59
+ - spec/ruby-asterisk/ruby_asterisk_spec.rb
60
+ - spec/spec_helper.rb
61
+ homepage: http://github.com/emilianodellacasa/ruby-asterisk
62
+ licenses: []
63
+
64
+ post_install_message:
65
+ rdoc_options: []
66
+
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ requirements: []
82
+
83
+ rubyforge_project: ruby-asterisk
84
+ rubygems_version: 1.8.17
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Asterisk Manager Interface in Ruby
88
+ test_files: []
89
+