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.
Files changed (77) hide show
  1. checksums.yaml +5 -5
  2. data/.claude/skills/ruby-asterisk-agi/SKILL.md +317 -0
  3. data/.claude/skills/ruby-asterisk-ami/SKILL.md +187 -0
  4. data/.claude/skills/ruby-asterisk-ari/SKILL.md +174 -0
  5. data/.claude/skills/ruby-asterisk-ari-websocket/SKILL.md +148 -0
  6. data/.github/workflows/ci.yml +79 -0
  7. data/.gitignore +48 -4
  8. data/.rubocop.yml +84 -0
  9. data/CHANGELOG.md +52 -0
  10. data/Gemfile +3 -1
  11. data/README.md +410 -108
  12. data/Rakefile +3 -5
  13. data/lib/ruby-asterisk/agi/protocol.rb +160 -0
  14. data/lib/ruby-asterisk/agi/server.rb +108 -0
  15. data/lib/ruby-asterisk/agi/session.rb +187 -0
  16. data/lib/ruby-asterisk/ami/client.rb +135 -0
  17. data/lib/ruby-asterisk/ami/commands/channel.rb +55 -0
  18. data/lib/ruby-asterisk/ami/commands/conference.rb +37 -0
  19. data/lib/ruby-asterisk/ami/commands/extension.rb +17 -0
  20. data/lib/ruby-asterisk/ami/commands/mailbox.rb +21 -0
  21. data/lib/ruby-asterisk/ami/commands/monitor.rb +33 -0
  22. data/lib/ruby-asterisk/ami/commands/queue.rb +39 -0
  23. data/lib/ruby-asterisk/ami/commands/sip.rb +25 -0
  24. data/lib/ruby-asterisk/ami/commands/system.rb +50 -0
  25. data/lib/ruby-asterisk/ami/event.rb +22 -0
  26. data/lib/ruby-asterisk/ami/event_list_aggregation.rb +82 -0
  27. data/lib/ruby-asterisk/ami/parser.rb +60 -0
  28. data/lib/ruby-asterisk/ami/promise.rb +108 -0
  29. data/lib/ruby-asterisk/ami/reactor.rb +162 -0
  30. data/lib/ruby-asterisk/ari/client.rb +94 -0
  31. data/lib/ruby-asterisk/ari/resources/base.rb +23 -0
  32. data/lib/ruby-asterisk/ari/resources/bridge.rb +22 -0
  33. data/lib/ruby-asterisk/ari/resources/channel.rb +26 -0
  34. data/lib/ruby-asterisk/ari/resources/collection.rb +27 -0
  35. data/lib/ruby-asterisk/ari/resources/endpoint.rb +22 -0
  36. data/lib/ruby-asterisk/ari/resources/playback.rb +18 -0
  37. data/lib/ruby-asterisk/ari/websocket/connection.rb +143 -0
  38. data/lib/ruby-asterisk/ari/websocket/event_handlers.rb +80 -0
  39. data/lib/ruby-asterisk/ari/websocket/heartbeat.rb +65 -0
  40. data/lib/ruby-asterisk/ari/websocket/reconnect.rb +54 -0
  41. data/lib/ruby-asterisk/ari/websocket/socket_adapter.rb +23 -0
  42. data/lib/ruby-asterisk/ari/websocket.rb +155 -0
  43. data/lib/ruby-asterisk/compat.rb +7 -0
  44. data/lib/ruby-asterisk/error.rb +10 -0
  45. data/lib/ruby-asterisk/parsing_constants.rb +71 -69
  46. data/lib/ruby-asterisk/request.rb +33 -14
  47. data/lib/ruby-asterisk/response.rb +43 -16
  48. data/lib/ruby-asterisk/response_builder.rb +18 -0
  49. data/lib/ruby-asterisk/response_parser.rb +10 -9
  50. data/lib/ruby-asterisk/version.rb +4 -2
  51. data/lib/ruby-asterisk.rb +5 -222
  52. data/ruby-asterisk.gemspec +23 -17
  53. data/spec/ruby-asterisk/agi/protocol_spec.rb +239 -0
  54. data/spec/ruby-asterisk/agi/server_spec.rb +199 -0
  55. data/spec/ruby-asterisk/agi/session_spec.rb +293 -0
  56. data/spec/ruby-asterisk/ami/async_client_spec.rb +256 -0
  57. data/spec/ruby-asterisk/ami/multi_event_spec.rb +57 -0
  58. data/spec/ruby-asterisk/ami/parser_spec.rb +190 -0
  59. data/spec/ruby-asterisk/ami/reactor_spec.rb +290 -0
  60. data/spec/ruby-asterisk/ami_client_spec.rb +68 -0
  61. data/spec/ruby-asterisk/ari/client_spec.rb +168 -0
  62. data/spec/ruby-asterisk/ari/resources/bridge_spec.rb +42 -0
  63. data/spec/ruby-asterisk/ari/resources/channel_spec.rb +57 -0
  64. data/spec/ruby-asterisk/ari/resources/collection_spec.rb +66 -0
  65. data/spec/ruby-asterisk/ari/resources/endpoint_spec.rb +30 -0
  66. data/spec/ruby-asterisk/ari/resources/playback_spec.rb +33 -0
  67. data/spec/ruby-asterisk/ari/websocket_integration_spec.rb +86 -0
  68. data/spec/ruby-asterisk/ari/websocket_spec.rb +374 -0
  69. data/spec/ruby-asterisk/immutability_spec.rb +148 -0
  70. data/spec/ruby-asterisk/request_spec.rb +29 -9
  71. data/spec/ruby-asterisk/response_spec.rb +46 -47
  72. data/spec/spec_helper.rb +12 -0
  73. data/spec/support/mock_ami_server.rb +50 -0
  74. data/spec/support/mock_ari_websocket_server.rb +114 -0
  75. metadata +138 -18
  76. data/CHANGELOG +0 -3
  77. data/spec/ruby-asterisk/ruby_asterisk_spec.rb +0 -192
@@ -1,17 +1,37 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
2
3
  require 'spec_helper'
3
4
  describe RubyAsterisk::Request do
4
-
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" })
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 "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
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
- # encoding: utf-8
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 ".new" do
100
-
101
- describe "receiving a Core Show Channels request" do
102
- it "should parse correctly data coming from Asterisk about channels" do
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 "should correctly fill the fields" do
108
- @response = RubyAsterisk::Response.new("CoreShowChannels",core_show_channels_response)
109
- @response.data[:channels][0]["CallerIDnum"].should eq("123456")
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 "should have no channels if answer is empty" do
113
- @response = RubyAsterisk::Response.new("CoreShowChannels",empty_core_show_channels_response)
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 "receiving a Parked Calls request" do
119
- it "should parse correctly data coming from Asterisk about calls" do
120
- @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
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 "should correctly fill the fields" do
125
- @response = RubyAsterisk::Response.new("ParkedCalls",parked_calls_response)
126
- @response.data[:calls][0]["Exten"].should eq("701")
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 "receiving a Originate request" do
131
- it "should parse correctly data coming from Asterisk about the call" do
132
- @response = RubyAsterisk::Response.new("Originate",originate_response)
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 "should correctly fill the fields" do
137
- @response = RubyAsterisk::Response.new("Originate",originate_response)
138
- @response.data[:dial][0]["UniqueID"].should eq("1335457364.68")
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 "should have a field with original raw response" do
142
- @response = RubyAsterisk::Response.new("Originate",originate_response)
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 "receiving a MeetMeList request" do
148
- it "should parse correctly data coming from Asterisk about the conference room" do
149
- @response = RubyAsterisk::Response.new("MeetMeList",meet_me_list_response)
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 "should correctly fill the fields" do
154
- @response = RubyAsterisk::Response.new("MeetMeList",meet_me_list_response)
155
- @response.data[:rooms][0]["Conference"].should eq("1234")
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 "receiving a ExtensionState request" do
160
- it "should parse correctly data coming from Asterisk about the state of the extension" do
161
- @response = RubyAsterisk::Response.new("ExtensionState",extension_state_response)
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 "should correctly fill the fields" do
166
- @response = RubyAsterisk::Response.new("ExtensionState",extension_state_response)
167
- @response.data[:hints][0]["Status"].should eq("0")
168
- @response.data[:hints][0]["DescriptiveStatus"].should eq("Idle")
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 "receiving a SIPPeers request" do
174
- it "should parse correctly data coming from Asterisk abous sip peers" do
175
- @response = RubyAsterisk::Response.new("SIPpeers",sip_peers_response)
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 "should correctly fill the fields" do
180
- @response = RubyAsterisk::Response.new("SIPpeers",sip_peers_response)
181
- @response.data[:peers][0]["ObjectName"].should eq("9915057")
182
- @response.data[:peers][0]["IPport"].should eq("5060")
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.2.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: 2019-07-25 00:00:00.000000000 Z
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: simplecov
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: quality
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
- - CHANGELOG
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
- post_install_message:
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: '0'
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
- rubyforge_project: ruby-asterisk
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
@@ -1,3 +0,0 @@
1
- ## v0.0.1
2
-
3
- * Initial release