ruby-asterisk 0.2.0 → 1.0.0
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.
- checksums.yaml +5 -5
- data/.claude/skills/ruby-asterisk-agi/SKILL.md +317 -0
- data/.claude/skills/ruby-asterisk-ami/SKILL.md +187 -0
- data/.claude/skills/ruby-asterisk-ari/SKILL.md +174 -0
- data/.claude/skills/ruby-asterisk-ari-websocket/SKILL.md +148 -0
- data/.github/workflows/ci.yml +79 -0
- data/.gitignore +48 -4
- data/.rubocop.yml +84 -0
- data/CHANGELOG.md +52 -0
- data/Gemfile +3 -1
- data/README.md +410 -108
- data/Rakefile +3 -5
- data/lib/ruby-asterisk/agi/protocol.rb +160 -0
- data/lib/ruby-asterisk/agi/server.rb +108 -0
- data/lib/ruby-asterisk/agi/session.rb +187 -0
- data/lib/ruby-asterisk/ami/client.rb +135 -0
- data/lib/ruby-asterisk/ami/commands/channel.rb +55 -0
- data/lib/ruby-asterisk/ami/commands/conference.rb +37 -0
- data/lib/ruby-asterisk/ami/commands/extension.rb +17 -0
- data/lib/ruby-asterisk/ami/commands/mailbox.rb +21 -0
- data/lib/ruby-asterisk/ami/commands/monitor.rb +33 -0
- data/lib/ruby-asterisk/ami/commands/queue.rb +39 -0
- data/lib/ruby-asterisk/ami/commands/sip.rb +25 -0
- data/lib/ruby-asterisk/ami/commands/system.rb +50 -0
- data/lib/ruby-asterisk/ami/event.rb +22 -0
- data/lib/ruby-asterisk/ami/event_list_aggregation.rb +82 -0
- data/lib/ruby-asterisk/ami/parser.rb +60 -0
- data/lib/ruby-asterisk/ami/promise.rb +108 -0
- data/lib/ruby-asterisk/ami/reactor.rb +162 -0
- data/lib/ruby-asterisk/ari/client.rb +94 -0
- data/lib/ruby-asterisk/ari/resources/base.rb +23 -0
- data/lib/ruby-asterisk/ari/resources/bridge.rb +22 -0
- data/lib/ruby-asterisk/ari/resources/channel.rb +26 -0
- data/lib/ruby-asterisk/ari/resources/collection.rb +27 -0
- data/lib/ruby-asterisk/ari/resources/endpoint.rb +22 -0
- data/lib/ruby-asterisk/ari/resources/playback.rb +18 -0
- data/lib/ruby-asterisk/ari/websocket/connection.rb +143 -0
- data/lib/ruby-asterisk/ari/websocket/event_handlers.rb +80 -0
- data/lib/ruby-asterisk/ari/websocket/heartbeat.rb +65 -0
- data/lib/ruby-asterisk/ari/websocket/reconnect.rb +54 -0
- data/lib/ruby-asterisk/ari/websocket/socket_adapter.rb +23 -0
- data/lib/ruby-asterisk/ari/websocket.rb +155 -0
- data/lib/ruby-asterisk/compat.rb +7 -0
- data/lib/ruby-asterisk/error.rb +10 -0
- data/lib/ruby-asterisk/parsing_constants.rb +71 -69
- data/lib/ruby-asterisk/request.rb +33 -14
- data/lib/ruby-asterisk/response.rb +43 -16
- data/lib/ruby-asterisk/response_builder.rb +18 -0
- data/lib/ruby-asterisk/response_parser.rb +10 -9
- data/lib/ruby-asterisk/version.rb +4 -2
- data/lib/ruby-asterisk.rb +5 -222
- data/ruby-asterisk.gemspec +23 -17
- data/spec/ruby-asterisk/agi/protocol_spec.rb +239 -0
- data/spec/ruby-asterisk/agi/server_spec.rb +199 -0
- data/spec/ruby-asterisk/agi/session_spec.rb +293 -0
- data/spec/ruby-asterisk/ami/async_client_spec.rb +256 -0
- data/spec/ruby-asterisk/ami/multi_event_spec.rb +57 -0
- data/spec/ruby-asterisk/ami/parser_spec.rb +190 -0
- data/spec/ruby-asterisk/ami/reactor_spec.rb +290 -0
- data/spec/ruby-asterisk/ami_client_spec.rb +68 -0
- data/spec/ruby-asterisk/ari/client_spec.rb +168 -0
- data/spec/ruby-asterisk/ari/resources/bridge_spec.rb +42 -0
- data/spec/ruby-asterisk/ari/resources/channel_spec.rb +57 -0
- data/spec/ruby-asterisk/ari/resources/collection_spec.rb +66 -0
- data/spec/ruby-asterisk/ari/resources/endpoint_spec.rb +30 -0
- data/spec/ruby-asterisk/ari/resources/playback_spec.rb +33 -0
- data/spec/ruby-asterisk/ari/websocket_integration_spec.rb +86 -0
- data/spec/ruby-asterisk/ari/websocket_spec.rb +374 -0
- data/spec/ruby-asterisk/immutability_spec.rb +148 -0
- data/spec/ruby-asterisk/request_spec.rb +29 -9
- data/spec/ruby-asterisk/response_spec.rb +46 -47
- data/spec/spec_helper.rb +12 -0
- data/spec/support/mock_ami_server.rb +50 -0
- data/spec/support/mock_ari_websocket_server.rb +114 -0
- metadata +138 -18
- data/CHANGELOG +0 -3
- data/spec/ruby-asterisk/ruby_asterisk_spec.rb +0 -192
|
@@ -1,17 +1,37 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'spec_helper'
|
|
3
4
|
describe RubyAsterisk::Request do
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
request = RubyAsterisk::Request.new("Originate",{"Channel" => "1234", "Context" => "test", "Exten" => "1", "Priority" => "1", "Callerid" => "1234", "Timeout" => "30000", "Variable" => "var1=15" })
|
|
5
|
+
describe 'of type Originate' do
|
|
6
|
+
it 'should set a Variable option if set' do
|
|
7
|
+
request = RubyAsterisk::Request.new('Originate', { 'Channel' => '1234', 'Context' => 'test', 'Exten' => '1', 'Priority' => '1', 'Callerid' => '1234', 'Timeout' => '30000', 'Variable' => 'var1=15' })
|
|
8
8
|
request.commands.include?("Variable: var1=15\r\n").should_not be_nil
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
it
|
|
12
|
-
request = RubyAsterisk::Request.new(
|
|
13
|
-
request.commands.include?(
|
|
11
|
+
it 'should not set a Variable option if not set' do
|
|
12
|
+
request = RubyAsterisk::Request.new('Originate', { 'Channel' => '1234', 'Context' => 'test', 'Exten' => '1', 'Priority' => '1', 'Callerid' => '1234', 'Timeout' => '30000', 'Variable' => nil })
|
|
13
|
+
request.commands.include?('Variable: var=15').should == false
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
|
-
end
|
|
17
16
|
|
|
17
|
+
describe 'action_id' do
|
|
18
|
+
it 'generates one when none is supplied' do
|
|
19
|
+
request = RubyAsterisk::Request.new('Ping')
|
|
20
|
+
|
|
21
|
+
expect(request.action_id).not_to be_empty
|
|
22
|
+
expect(request.commands.join).to include("ActionID: #{request.action_id}\r\n")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'uses the supplied action_id' do
|
|
26
|
+
request = RubyAsterisk::Request.new('Status', {}, action_id: 'my-own-id')
|
|
27
|
+
|
|
28
|
+
expect(request.action_id).to eq('my-own-id')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'emits exactly one ActionID header' do
|
|
32
|
+
request = RubyAsterisk::Request.new('Status', { 'Channel' => 'SIP/alice' }, action_id: 'my-own-id')
|
|
33
|
+
|
|
34
|
+
expect(request.commands.join.scan(/^ActionID:/).size).to eq(1)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
require 'spec_helper'
|
|
3
4
|
describe RubyAsterisk::Response do
|
|
4
|
-
|
|
5
5
|
def sip_peers_response
|
|
6
6
|
"Response: Success
|
|
7
7
|
Message: Peer status list will follow
|
|
@@ -96,90 +96,89 @@ describe RubyAsterisk::Response do
|
|
|
96
96
|
Status: 0\n\n"
|
|
97
97
|
end
|
|
98
98
|
|
|
99
|
-
describe
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
@response = RubyAsterisk::Response.new("CoreShowChannels",core_show_channels_response)
|
|
99
|
+
describe '.new' do
|
|
100
|
+
describe 'receiving a Core Show Channels request' do
|
|
101
|
+
it 'should parse correctly data coming from Asterisk about channels' do
|
|
102
|
+
@response = RubyAsterisk::Response.new('CoreShowChannels', [core_show_channels_response])
|
|
104
103
|
@response.data[:channels].should_not be_empty
|
|
105
104
|
end
|
|
106
105
|
|
|
107
|
-
it
|
|
108
|
-
@response = RubyAsterisk::Response.new(
|
|
109
|
-
@response.data[:channels][0][
|
|
106
|
+
it 'should correctly fill the fields' do
|
|
107
|
+
@response = RubyAsterisk::Response.new('CoreShowChannels', [core_show_channels_response])
|
|
108
|
+
@response.data[:channels][0]['CallerIDnum'].should eq('123456')
|
|
110
109
|
end
|
|
111
110
|
|
|
112
|
-
it
|
|
113
|
-
@response = RubyAsterisk::Response.new(
|
|
111
|
+
it 'should have no channels if answer is empty' do
|
|
112
|
+
@response = RubyAsterisk::Response.new('CoreShowChannels', [empty_core_show_channels_response])
|
|
114
113
|
@response.data[:channels].count.should eq(0)
|
|
115
114
|
end
|
|
116
115
|
end
|
|
117
116
|
|
|
118
|
-
describe
|
|
119
|
-
it
|
|
120
|
-
@response = RubyAsterisk::Response.new(
|
|
117
|
+
describe 'receiving a Parked Calls request' do
|
|
118
|
+
it 'should parse correctly data coming from Asterisk about calls' do
|
|
119
|
+
@response = RubyAsterisk::Response.new('ParkedCalls', [parked_calls_response])
|
|
121
120
|
@response.data[:calls].should_not be_empty
|
|
122
121
|
end
|
|
123
122
|
|
|
124
|
-
it
|
|
125
|
-
@response = RubyAsterisk::Response.new(
|
|
126
|
-
@response.data[:calls][0][
|
|
123
|
+
it 'should correctly fill the fields' do
|
|
124
|
+
@response = RubyAsterisk::Response.new('ParkedCalls', [parked_calls_response])
|
|
125
|
+
@response.data[:calls][0]['Exten'].should eq('701')
|
|
127
126
|
end
|
|
128
127
|
end
|
|
129
128
|
|
|
130
|
-
describe
|
|
131
|
-
it
|
|
132
|
-
@response = RubyAsterisk::Response.new(
|
|
129
|
+
describe 'receiving a Originate request' do
|
|
130
|
+
it 'should parse correctly data coming from Asterisk about the call' do
|
|
131
|
+
@response = RubyAsterisk::Response.new('Originate', [originate_response])
|
|
133
132
|
@response.data[:dial].should_not be_empty
|
|
134
133
|
end
|
|
135
134
|
|
|
136
|
-
it
|
|
137
|
-
@response = RubyAsterisk::Response.new(
|
|
138
|
-
@response.data[:dial][0][
|
|
135
|
+
it 'should correctly fill the fields' do
|
|
136
|
+
@response = RubyAsterisk::Response.new('Originate', [originate_response])
|
|
137
|
+
@response.data[:dial][0]['UniqueID'].should eq('1335457364.68')
|
|
139
138
|
end
|
|
140
139
|
|
|
141
|
-
it
|
|
142
|
-
@response = RubyAsterisk::Response.new(
|
|
143
|
-
@response.raw_response.should eq(originate_response)
|
|
140
|
+
it 'should have a field with original raw response' do
|
|
141
|
+
@response = RubyAsterisk::Response.new('Originate', [originate_response])
|
|
142
|
+
@response.raw_response.join.should eq(originate_response)
|
|
144
143
|
end
|
|
145
144
|
end
|
|
146
145
|
|
|
147
|
-
describe
|
|
148
|
-
it
|
|
149
|
-
@response = RubyAsterisk::Response.new(
|
|
146
|
+
describe 'receiving a MeetMeList request' do
|
|
147
|
+
it 'should parse correctly data coming from Asterisk about the conference room' do
|
|
148
|
+
@response = RubyAsterisk::Response.new('MeetMeList', [meet_me_list_response])
|
|
150
149
|
@response.data[:rooms].should_not be_empty
|
|
151
150
|
end
|
|
152
151
|
|
|
153
|
-
it
|
|
154
|
-
@response = RubyAsterisk::Response.new(
|
|
155
|
-
@response.data[:rooms][0][
|
|
152
|
+
it 'should correctly fill the fields' do
|
|
153
|
+
@response = RubyAsterisk::Response.new('MeetMeList', [meet_me_list_response])
|
|
154
|
+
@response.data[:rooms][0]['Conference'].should eq('1234')
|
|
156
155
|
end
|
|
157
156
|
end
|
|
158
157
|
|
|
159
|
-
describe
|
|
160
|
-
it
|
|
161
|
-
@response = RubyAsterisk::Response.new(
|
|
158
|
+
describe 'receiving a ExtensionState request' do
|
|
159
|
+
it 'should parse correctly data coming from Asterisk about the state of the extension' do
|
|
160
|
+
@response = RubyAsterisk::Response.new('ExtensionState', [extension_state_response])
|
|
162
161
|
@response.data[:hints].should_not be_empty
|
|
163
162
|
end
|
|
164
163
|
|
|
165
|
-
it
|
|
166
|
-
@response = RubyAsterisk::Response.new(
|
|
167
|
-
@response.data[:hints][0][
|
|
168
|
-
@response.data[:hints][0][
|
|
164
|
+
it 'should correctly fill the fields' do
|
|
165
|
+
@response = RubyAsterisk::Response.new('ExtensionState', [extension_state_response])
|
|
166
|
+
@response.data[:hints][0]['Status'].should eq('0')
|
|
167
|
+
@response.data[:hints][0]['DescriptiveStatus'].should eq('Idle')
|
|
169
168
|
end
|
|
170
169
|
end
|
|
171
170
|
end
|
|
172
171
|
|
|
173
|
-
describe
|
|
174
|
-
it
|
|
175
|
-
@response = RubyAsterisk::Response.new(
|
|
172
|
+
describe 'receiving a SIPPeers request' do
|
|
173
|
+
it 'should parse correctly data coming from Asterisk abous sip peers' do
|
|
174
|
+
@response = RubyAsterisk::Response.new('SIPpeers', [sip_peers_response])
|
|
176
175
|
@response.data[:peers].should_not be_empty
|
|
177
176
|
end
|
|
178
177
|
|
|
179
|
-
it
|
|
180
|
-
@response = RubyAsterisk::Response.new(
|
|
181
|
-
@response.data[:peers][0][
|
|
182
|
-
@response.data[:peers][0][
|
|
178
|
+
it 'should correctly fill the fields' do
|
|
179
|
+
@response = RubyAsterisk::Response.new('SIPpeers', [sip_peers_response])
|
|
180
|
+
@response.data[:peers][0]['ObjectName'].should eq('9915057')
|
|
181
|
+
@response.data[:peers][0]['IPport'].should eq('5060')
|
|
183
182
|
end
|
|
184
183
|
end
|
|
185
184
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'simplecov'
|
|
2
4
|
SimpleCov.start
|
|
3
5
|
require 'rubygems'
|
|
4
6
|
require 'bundler'
|
|
5
7
|
|
|
6
8
|
require 'ruby-asterisk'
|
|
9
|
+
|
|
10
|
+
RSpec.configure do |config|
|
|
11
|
+
config.expect_with :rspec do |c|
|
|
12
|
+
c.syntax = %i[should expect]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
config.after(:suite) do
|
|
16
|
+
puts '[CI] Done.'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'socket'
|
|
4
|
+
|
|
5
|
+
module MockAMIServer
|
|
6
|
+
def self.handle_client(client, &block)
|
|
7
|
+
client.puts 'Asterisk Call Manager/1.1'
|
|
8
|
+
|
|
9
|
+
if block
|
|
10
|
+
yield(client)
|
|
11
|
+
else
|
|
12
|
+
while (line = client.gets)
|
|
13
|
+
client.puts "Echo: #{line}"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
puts "Client error: #{e.message}"
|
|
18
|
+
ensure
|
|
19
|
+
begin
|
|
20
|
+
client.close
|
|
21
|
+
rescue StandardError
|
|
22
|
+
nil
|
|
23
|
+
end
|
|
24
|
+
puts 'Client disconnected'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.start(port = 0, &block)
|
|
28
|
+
server = TCPServer.new('localhost', port)
|
|
29
|
+
assigned_port = server.addr[1]
|
|
30
|
+
|
|
31
|
+
client_threads = []
|
|
32
|
+
server_thread = Thread.new do
|
|
33
|
+
loop do
|
|
34
|
+
client = server.accept
|
|
35
|
+
puts "Client connected: #{client.peeraddr.inspect}"
|
|
36
|
+
client_threads << Thread.new(client) { |c| handle_client(c, &block) }
|
|
37
|
+
end
|
|
38
|
+
rescue IOError, Errno::EBADF # Server closed
|
|
39
|
+
ensure
|
|
40
|
+
begin
|
|
41
|
+
server.close
|
|
42
|
+
rescue StandardError
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
client_threads.each(&:kill)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
[server_thread, assigned_port]
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'socket'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'websocket/driver'
|
|
6
|
+
|
|
7
|
+
# Minimal in-process WebSocket server used by ARI::WebSocket integration specs.
|
|
8
|
+
# Accepts connections on an ephemeral port, completes the WebSocket handshake
|
|
9
|
+
# with websocket-driver in server mode, and records what clients send.
|
|
10
|
+
class MockAriWebSocketServer
|
|
11
|
+
# websocket-driver server adapter: it only needs #write
|
|
12
|
+
class ServerAdapter
|
|
13
|
+
def initialize(io)
|
|
14
|
+
@io = io
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def write(data)
|
|
18
|
+
@io.write(data)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
ClientConnection = Struct.new(:socket, :driver)
|
|
23
|
+
|
|
24
|
+
attr_reader :port, :messages, :pings, :connections
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
@server = TCPServer.new('127.0.0.1', 0)
|
|
28
|
+
@port = @server.addr[1]
|
|
29
|
+
@messages = Queue.new # text frames received from clients
|
|
30
|
+
@pings = Queue.new # ping frames received from clients
|
|
31
|
+
@connections = Queue.new # one entry per completed handshake
|
|
32
|
+
@clients = []
|
|
33
|
+
@clients_mutex = Mutex.new
|
|
34
|
+
@accept_thread = Thread.new { accept_loop }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Send an event (Hash) to every connected client
|
|
38
|
+
def broadcast(event)
|
|
39
|
+
data = JSON.generate(event)
|
|
40
|
+
each_client { |client| client.driver.text(data) }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Close every client socket abruptly (no close frame), simulating a drop
|
|
44
|
+
def drop_clients
|
|
45
|
+
each_client { |client| client.socket.close }
|
|
46
|
+
@clients_mutex.synchronize { @clients.clear }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def stop
|
|
50
|
+
@server.close
|
|
51
|
+
@accept_thread.join(1)
|
|
52
|
+
drop_clients
|
|
53
|
+
rescue IOError
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Pop from one of the queues, failing the spec on timeout
|
|
58
|
+
def self.pop(queue, timeout = 5)
|
|
59
|
+
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout
|
|
60
|
+
loop do
|
|
61
|
+
return queue.pop(true)
|
|
62
|
+
rescue ThreadError
|
|
63
|
+
if Process.clock_gettime(Process::CLOCK_MONOTONIC) > deadline
|
|
64
|
+
raise "timed out waiting for queue after #{timeout}s"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
sleep 0.01
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def accept_loop
|
|
74
|
+
loop do
|
|
75
|
+
socket = @server.accept
|
|
76
|
+
Thread.new { handle_client(socket) }
|
|
77
|
+
end
|
|
78
|
+
rescue IOError, SystemCallError
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def handle_client(socket)
|
|
83
|
+
driver = ::WebSocket::Driver.server(ServerAdapter.new(socket))
|
|
84
|
+
client = ClientConnection.new(socket, driver)
|
|
85
|
+
@clients_mutex.synchronize { @clients << client }
|
|
86
|
+
|
|
87
|
+
setup_driver(driver, client)
|
|
88
|
+
driver.parse(socket.readpartial(4096)) until socket.closed?
|
|
89
|
+
rescue IOError, SystemCallError
|
|
90
|
+
nil
|
|
91
|
+
ensure
|
|
92
|
+
begin
|
|
93
|
+
socket.close
|
|
94
|
+
rescue StandardError
|
|
95
|
+
nil
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def setup_driver(driver, client)
|
|
100
|
+
driver.on(:connect) { driver.start if ::WebSocket::Driver.websocket?(driver.env) }
|
|
101
|
+
driver.on(:open) { @connections << client }
|
|
102
|
+
driver.on(:message) { |event| @messages << event.data }
|
|
103
|
+
driver.on(:ping) { |event| @pings << event }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def each_client
|
|
107
|
+
clients = @clients_mutex.synchronize { @clients.dup }
|
|
108
|
+
clients.each do |client|
|
|
109
|
+
yield client
|
|
110
|
+
rescue IOError, SystemCallError
|
|
111
|
+
nil
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
metadata
CHANGED
|
@@ -1,15 +1,70 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-asterisk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emiliano Della Casa
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: async
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '2.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: faraday
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: logger
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: websocket-driver
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0.8'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0.8'
|
|
13
68
|
- !ruby/object:Gem::Dependency
|
|
14
69
|
name: rake
|
|
15
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -39,7 +94,21 @@ dependencies:
|
|
|
39
94
|
- !ruby/object:Gem::Version
|
|
40
95
|
version: '0'
|
|
41
96
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
97
|
+
name: rubocop
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: rubocop-performance
|
|
43
112
|
requirement: !ruby/object:Gem::Requirement
|
|
44
113
|
requirements:
|
|
45
114
|
- - ">="
|
|
@@ -53,7 +122,7 @@ dependencies:
|
|
|
53
122
|
- !ruby/object:Gem::Version
|
|
54
123
|
version: '0'
|
|
55
124
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
125
|
+
name: simplecov
|
|
57
126
|
requirement: !ruby/object:Gem::Requirement
|
|
58
127
|
requirements:
|
|
59
128
|
- - ">="
|
|
@@ -74,29 +143,86 @@ executables: []
|
|
|
74
143
|
extensions: []
|
|
75
144
|
extra_rdoc_files: []
|
|
76
145
|
files:
|
|
146
|
+
- ".claude/skills/ruby-asterisk-agi/SKILL.md"
|
|
147
|
+
- ".claude/skills/ruby-asterisk-ami/SKILL.md"
|
|
148
|
+
- ".claude/skills/ruby-asterisk-ari-websocket/SKILL.md"
|
|
149
|
+
- ".claude/skills/ruby-asterisk-ari/SKILL.md"
|
|
150
|
+
- ".github/workflows/ci.yml"
|
|
77
151
|
- ".gitignore"
|
|
78
152
|
- ".rspec"
|
|
79
|
-
-
|
|
153
|
+
- ".rubocop.yml"
|
|
154
|
+
- CHANGELOG.md
|
|
80
155
|
- Gemfile
|
|
81
156
|
- LICENCE
|
|
82
157
|
- README.md
|
|
83
158
|
- Rakefile
|
|
84
159
|
- lib/ruby-asterisk.rb
|
|
160
|
+
- lib/ruby-asterisk/agi/protocol.rb
|
|
161
|
+
- lib/ruby-asterisk/agi/server.rb
|
|
162
|
+
- lib/ruby-asterisk/agi/session.rb
|
|
163
|
+
- lib/ruby-asterisk/ami/client.rb
|
|
164
|
+
- lib/ruby-asterisk/ami/commands/channel.rb
|
|
165
|
+
- lib/ruby-asterisk/ami/commands/conference.rb
|
|
166
|
+
- lib/ruby-asterisk/ami/commands/extension.rb
|
|
167
|
+
- lib/ruby-asterisk/ami/commands/mailbox.rb
|
|
168
|
+
- lib/ruby-asterisk/ami/commands/monitor.rb
|
|
169
|
+
- lib/ruby-asterisk/ami/commands/queue.rb
|
|
170
|
+
- lib/ruby-asterisk/ami/commands/sip.rb
|
|
171
|
+
- lib/ruby-asterisk/ami/commands/system.rb
|
|
172
|
+
- lib/ruby-asterisk/ami/event.rb
|
|
173
|
+
- lib/ruby-asterisk/ami/event_list_aggregation.rb
|
|
174
|
+
- lib/ruby-asterisk/ami/parser.rb
|
|
175
|
+
- lib/ruby-asterisk/ami/promise.rb
|
|
176
|
+
- lib/ruby-asterisk/ami/reactor.rb
|
|
177
|
+
- lib/ruby-asterisk/ari/client.rb
|
|
178
|
+
- lib/ruby-asterisk/ari/resources/base.rb
|
|
179
|
+
- lib/ruby-asterisk/ari/resources/bridge.rb
|
|
180
|
+
- lib/ruby-asterisk/ari/resources/channel.rb
|
|
181
|
+
- lib/ruby-asterisk/ari/resources/collection.rb
|
|
182
|
+
- lib/ruby-asterisk/ari/resources/endpoint.rb
|
|
183
|
+
- lib/ruby-asterisk/ari/resources/playback.rb
|
|
184
|
+
- lib/ruby-asterisk/ari/websocket.rb
|
|
185
|
+
- lib/ruby-asterisk/ari/websocket/connection.rb
|
|
186
|
+
- lib/ruby-asterisk/ari/websocket/event_handlers.rb
|
|
187
|
+
- lib/ruby-asterisk/ari/websocket/heartbeat.rb
|
|
188
|
+
- lib/ruby-asterisk/ari/websocket/reconnect.rb
|
|
189
|
+
- lib/ruby-asterisk/ari/websocket/socket_adapter.rb
|
|
190
|
+
- lib/ruby-asterisk/compat.rb
|
|
191
|
+
- lib/ruby-asterisk/error.rb
|
|
85
192
|
- lib/ruby-asterisk/parsing_constants.rb
|
|
86
193
|
- lib/ruby-asterisk/request.rb
|
|
87
194
|
- lib/ruby-asterisk/response.rb
|
|
195
|
+
- lib/ruby-asterisk/response_builder.rb
|
|
88
196
|
- lib/ruby-asterisk/response_parser.rb
|
|
89
197
|
- lib/ruby-asterisk/version.rb
|
|
90
198
|
- ruby-asterisk.gemspec
|
|
199
|
+
- spec/ruby-asterisk/agi/protocol_spec.rb
|
|
200
|
+
- spec/ruby-asterisk/agi/server_spec.rb
|
|
201
|
+
- spec/ruby-asterisk/agi/session_spec.rb
|
|
202
|
+
- spec/ruby-asterisk/ami/async_client_spec.rb
|
|
203
|
+
- spec/ruby-asterisk/ami/multi_event_spec.rb
|
|
204
|
+
- spec/ruby-asterisk/ami/parser_spec.rb
|
|
205
|
+
- spec/ruby-asterisk/ami/reactor_spec.rb
|
|
206
|
+
- spec/ruby-asterisk/ami_client_spec.rb
|
|
207
|
+
- spec/ruby-asterisk/ari/client_spec.rb
|
|
208
|
+
- spec/ruby-asterisk/ari/resources/bridge_spec.rb
|
|
209
|
+
- spec/ruby-asterisk/ari/resources/channel_spec.rb
|
|
210
|
+
- spec/ruby-asterisk/ari/resources/collection_spec.rb
|
|
211
|
+
- spec/ruby-asterisk/ari/resources/endpoint_spec.rb
|
|
212
|
+
- spec/ruby-asterisk/ari/resources/playback_spec.rb
|
|
213
|
+
- spec/ruby-asterisk/ari/websocket_integration_spec.rb
|
|
214
|
+
- spec/ruby-asterisk/ari/websocket_spec.rb
|
|
215
|
+
- spec/ruby-asterisk/immutability_spec.rb
|
|
91
216
|
- spec/ruby-asterisk/request_spec.rb
|
|
92
217
|
- spec/ruby-asterisk/response_spec.rb
|
|
93
|
-
- spec/ruby-asterisk/ruby_asterisk_spec.rb
|
|
94
218
|
- spec/spec_helper.rb
|
|
219
|
+
- spec/support/mock_ami_server.rb
|
|
220
|
+
- spec/support/mock_ari_websocket_server.rb
|
|
95
221
|
homepage: http://github.com/emilianodellacasa/ruby-asterisk
|
|
96
222
|
licenses:
|
|
97
223
|
- MIT
|
|
98
|
-
metadata:
|
|
99
|
-
|
|
224
|
+
metadata:
|
|
225
|
+
rubygems_mfa_required: 'true'
|
|
100
226
|
rdoc_options: []
|
|
101
227
|
require_paths:
|
|
102
228
|
- lib
|
|
@@ -104,20 +230,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
104
230
|
requirements:
|
|
105
231
|
- - ">="
|
|
106
232
|
- !ruby/object:Gem::Version
|
|
107
|
-
version: '
|
|
233
|
+
version: '3.1'
|
|
108
234
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
235
|
requirements:
|
|
110
236
|
- - ">="
|
|
111
237
|
- !ruby/object:Gem::Version
|
|
112
238
|
version: '0'
|
|
113
239
|
requirements: []
|
|
114
|
-
|
|
115
|
-
rubygems_version: 2.6.11
|
|
116
|
-
signing_key:
|
|
240
|
+
rubygems_version: 3.6.9
|
|
117
241
|
specification_version: 4
|
|
118
242
|
summary: Asterisk Manager Interface in Ruby
|
|
119
|
-
test_files:
|
|
120
|
-
- spec/ruby-asterisk/request_spec.rb
|
|
121
|
-
- spec/ruby-asterisk/response_spec.rb
|
|
122
|
-
- spec/ruby-asterisk/ruby_asterisk_spec.rb
|
|
123
|
-
- spec/spec_helper.rb
|
|
243
|
+
test_files: []
|
data/CHANGELOG
DELETED