rmpd 1.1.15 → 1.1.16
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 +4 -4
- data/.gitignore +1 -0
- data/console.rb +1 -1
- data/lib/rmpd.rb +2 -0
- data/lib/rmpd/command.rb +70 -44
- data/lib/rmpd/commands/admin.rb +1 -1
- data/lib/rmpd/commands/miscellaneous.rb +7 -2
- data/lib/rmpd/connection.rb +49 -66
- data/lib/rmpd/version.rb +1 -1
- data/spec/models/commands_spec.rb +21 -10
- data/spec/models/connection_spec.rb +3 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ed7a0812069ac86c9233bca9760bcceb0acc079
|
4
|
+
data.tar.gz: 48355f71e90c5cdadd1130d5dab71ec705274783
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 368aabafe5d5d3aa6c115ea01594ebcac6e3e17580379aa6cd2c0f09f5a76725d438483f2f17d13dd40049722e11b7bf113d839fbd16e7d197b7df2d9591fb6d
|
7
|
+
data.tar.gz: f31ddb04deb6543737e1d4681fbb698f34ceb1f9b7ee5bfbe31cbdaffb64dfd02f630e3091c14a95893192a22f284ad2e1dd1feb385f2407f8c80ef9f181e371
|
data/.gitignore
CHANGED
data/console.rb
CHANGED
data/lib/rmpd.rb
CHANGED
@@ -17,6 +17,8 @@ module Rmpd
|
|
17
17
|
|
18
18
|
class MpdConnRefusedError < MpdError ; end
|
19
19
|
|
20
|
+
class MpdDisconnectedError < MpdError; end
|
21
|
+
|
20
22
|
class MpdAckError < MpdError
|
21
23
|
def initialize(regex_match)
|
22
24
|
@error, @command_list_num, @current_command, @message = regex_match.values_at(1..-1)
|
data/lib/rmpd/command.rb
CHANGED
@@ -41,31 +41,26 @@ module Rmpd
|
|
41
41
|
module IdleStrategy
|
42
42
|
|
43
43
|
def execute(connection, *args, &block)
|
44
|
-
connection.
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
connection.synchronize do
|
45
|
+
connection.send_command(@name, *args)
|
46
|
+
if block_given?
|
47
|
+
yield connection.socket rescue nil
|
48
|
+
connection.send_command("noidle")
|
49
|
+
end
|
50
|
+
Response.factory(@name).parse(connection.read_response)
|
48
51
|
end
|
49
|
-
Response.factory(@name).parse(connection.read_response)
|
50
|
-
rescue EOFError
|
51
|
-
puts "IdleStrategy EOFError received, retrying" if $DEBUG
|
52
|
-
connection.close
|
53
|
-
retry
|
54
52
|
end
|
55
|
-
|
56
53
|
end
|
57
54
|
|
58
55
|
module NoidleStrategy
|
59
56
|
|
60
57
|
def execute(connection, *args)
|
61
|
-
connection.
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
connection.close
|
68
|
-
retry
|
58
|
+
connection.synchronize do
|
59
|
+
connection.send_command(@name, *args)
|
60
|
+
# The MPD server will never respond to a noidle command.
|
61
|
+
# http://www.mail-archive.com/musicpd-dev-team@lists.sourceforge.net/msg02246.html
|
62
|
+
nil
|
63
|
+
end
|
69
64
|
end
|
70
65
|
|
71
66
|
end
|
@@ -73,52 +68,83 @@ module Rmpd
|
|
73
68
|
module CommandStrategy
|
74
69
|
|
75
70
|
def execute(connection, *args)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
71
|
+
tries = 0
|
72
|
+
begin
|
73
|
+
connection.synchronize do
|
74
|
+
connection.send_command(@name, *args)
|
75
|
+
Response.factory(@name).parse(connection.read_response)
|
76
|
+
end
|
77
|
+
rescue MpdDisconnectedError => e
|
78
|
+
tries += 1
|
79
|
+
if tries < 5
|
80
|
+
puts "CommandStrategy MpdDisconnectedError received, retrying" if $DEBUG
|
81
|
+
connection.connect
|
82
|
+
retry
|
83
|
+
else
|
84
|
+
puts "CommandStrategy retries exceeded" if $DEBUG
|
85
|
+
raise e
|
86
|
+
end
|
87
|
+
end
|
82
88
|
end
|
83
|
-
|
84
89
|
end
|
85
90
|
|
86
91
|
module CommandListStrategy
|
87
92
|
|
88
93
|
def execute(connection, *args, &block)
|
94
|
+
tries = 0
|
89
95
|
list = List.new
|
90
96
|
yield list
|
91
97
|
|
92
|
-
|
93
|
-
|
94
|
-
|
98
|
+
begin
|
99
|
+
connection.synchronize do
|
100
|
+
connection.send_command("command_list_begin")
|
101
|
+
list.map do |command_w_args|
|
102
|
+
connection.send_command(*command_w_args)
|
103
|
+
end
|
104
|
+
connection.send_command("command_list_end")
|
105
|
+
Response.factory(@name).parse(connection.read_response)
|
106
|
+
end
|
107
|
+
rescue MpdDisconnectedError => e
|
108
|
+
tries += 1
|
109
|
+
if tries < 5
|
110
|
+
puts "CommandListStrategy MpdDisconnectedError received, retrying" if $DEBUG
|
111
|
+
connect
|
112
|
+
retry
|
113
|
+
else
|
114
|
+
puts "CommandListStrategy retries exceeded" if $DEBUG
|
115
|
+
raise e
|
116
|
+
end
|
95
117
|
end
|
96
|
-
connection.send_command("command_list_end")
|
97
|
-
Response.factory(@name).parse(connection.read_response)
|
98
|
-
rescue EOFError
|
99
|
-
puts "CommandListStrategy EOFError received, retrying" if $DEBUG
|
100
|
-
connection.close
|
101
|
-
retry
|
102
118
|
end
|
103
|
-
|
104
119
|
end
|
105
120
|
|
106
121
|
module CommandListOkStrategy
|
107
122
|
|
108
123
|
def execute(connection, *args, &block)
|
124
|
+
tries = 0
|
109
125
|
@list = List.new
|
110
126
|
yield @list
|
111
127
|
|
112
|
-
|
113
|
-
|
114
|
-
|
128
|
+
begin
|
129
|
+
connection.synchronize do
|
130
|
+
connection.send_command("command_list_ok_begin")
|
131
|
+
@list.map do |command_w_args|
|
132
|
+
connection.send_command(*command_w_args)
|
133
|
+
end
|
134
|
+
connection.send_command("command_list_end")
|
135
|
+
handle_command_list_ok_response(connection.read_response)
|
136
|
+
end
|
137
|
+
rescue MpdDisconnectedError => e
|
138
|
+
tries += 1
|
139
|
+
if tries < 5
|
140
|
+
puts "CommandListOkStrategy MpdDisconnectedError received, retrying" if $DEBUG
|
141
|
+
connect
|
142
|
+
retry
|
143
|
+
else
|
144
|
+
puts "CommandListOkStrategy retries exceeded" if $DEBUG
|
145
|
+
raise e
|
146
|
+
end
|
115
147
|
end
|
116
|
-
connection.send_command("command_list_end")
|
117
|
-
handle_command_list_ok_response(connection.read_response)
|
118
|
-
rescue EOFError
|
119
|
-
puts "CommandListOkStrategy EOFError received, retrying" if $DEBUG
|
120
|
-
connection.close
|
121
|
-
retry
|
122
148
|
end
|
123
149
|
|
124
150
|
|
data/lib/rmpd/commands/admin.rb
CHANGED
@@ -13,8 +13,13 @@ module Rmpd
|
|
13
13
|
simple_command :status
|
14
14
|
|
15
15
|
def close
|
16
|
-
|
17
|
-
|
16
|
+
@socket_mu.lock
|
17
|
+
begin
|
18
|
+
send_command("close")
|
19
|
+
@socket.close
|
20
|
+
ensure
|
21
|
+
@socket_mu.unlock
|
22
|
+
end
|
18
23
|
end
|
19
24
|
|
20
25
|
simple_command :command_list
|
data/lib/rmpd/connection.rb
CHANGED
@@ -20,44 +20,71 @@ module Rmpd
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def close
|
23
|
-
@socket_mu.
|
24
|
-
|
25
|
-
|
23
|
+
@socket_mu.synchronize {@socket.close}
|
24
|
+
end
|
25
|
+
|
26
|
+
def synchronize(&block)
|
27
|
+
@socket_mu.synchronize(&block)
|
26
28
|
end
|
27
29
|
|
28
30
|
def connect
|
29
31
|
@socket_mu.lock
|
30
|
-
|
32
|
+
begin
|
33
|
+
return unless @socket.nil? || @socket.closed?
|
34
|
+
|
35
|
+
if %r{^/} === @config.hostname
|
36
|
+
connect_unix_socket
|
37
|
+
else
|
38
|
+
connect_inet_socket
|
39
|
+
end
|
40
|
+
|
41
|
+
read_response # protocol version, ignore for now
|
42
|
+
if @config.password
|
43
|
+
send_command("password", @config.password)
|
44
|
+
Response.factory("password").parse(read_response)
|
45
|
+
end
|
46
|
+
ensure
|
31
47
|
@socket_mu.unlock
|
32
|
-
return
|
33
48
|
end
|
34
|
-
|
49
|
+
end
|
35
50
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
51
|
+
def read_response
|
52
|
+
response = []
|
53
|
+
|
54
|
+
while (line = @socket.readline.force_encoding("UTF-8"))
|
55
|
+
response << line.strip
|
56
|
+
break if END_RE === line
|
40
57
|
end
|
41
58
|
|
42
|
-
|
43
|
-
password(@config.password) if @config.password
|
59
|
+
response
|
44
60
|
end
|
45
61
|
|
62
|
+
def send_command(command, *args)
|
63
|
+
@socket.puts("#{command} #{quote(args).join(" ")}".strip)
|
64
|
+
rescue Errno::EPIPE, EOFError => e
|
65
|
+
@socket.close
|
66
|
+
raise MpdDisconnectedError.new(e)
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
def mpd
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
private
|
78
|
+
|
46
79
|
def connect_unix_socket
|
47
|
-
@
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
@socket = nil
|
52
|
-
raise MpdConnRefusedError.new(error)
|
53
|
-
ensure
|
54
|
-
@socket_mu.unlock
|
55
|
-
end
|
80
|
+
@socket = UNIXSocket.new(@config.hostname)
|
81
|
+
rescue StandardError => error
|
82
|
+
@socket = nil
|
83
|
+
raise MpdConnRefusedError.new(error)
|
56
84
|
end
|
57
85
|
|
58
86
|
def connect_inet_socket
|
59
87
|
Socket::getaddrinfo(@config.hostname, @config.port, nil, SOCK_STREAM).each do |info|
|
60
|
-
@socket_mu.lock
|
61
88
|
begin
|
62
89
|
sockaddr = Socket.pack_sockaddr_in(info[1], info[3])
|
63
90
|
@socket = Socket.new(info[4], info[5], 0)
|
@@ -67,52 +94,8 @@ module Rmpd
|
|
67
94
|
raise MpdConnRefusedError.new(error)
|
68
95
|
else
|
69
96
|
break
|
70
|
-
ensure
|
71
|
-
@socket_mu.unlock
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def send_command(command, *args)
|
77
|
-
tries = 0
|
78
|
-
|
79
|
-
begin
|
80
|
-
connect
|
81
|
-
send_command_without_reconnect(command, *args)
|
82
|
-
rescue Errno::EPIPE, EOFError
|
83
|
-
if (tries += 1) < MAX_RETRIES
|
84
|
-
retry
|
85
|
-
else
|
86
|
-
raise MpdError.new("Retry count exceeded")
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def send_command_without_reconnect(command, *args)
|
92
|
-
@socket_mu.lock
|
93
|
-
@socket.puts("#{command} #{quote(args).join(" ")}".strip)
|
94
|
-
rescue => e
|
95
|
-
@socket.close
|
96
|
-
raise e
|
97
|
-
ensure
|
98
|
-
@socket_mu.unlock
|
99
|
-
end
|
100
|
-
|
101
|
-
def read_response
|
102
|
-
response = []
|
103
|
-
|
104
|
-
@socket_mu.synchronize do
|
105
|
-
while (line = @socket.readline.force_encoding("UTF-8"))
|
106
|
-
response << line.strip
|
107
|
-
break if END_RE === line
|
108
97
|
end
|
109
98
|
end
|
110
|
-
|
111
|
-
response
|
112
|
-
end
|
113
|
-
|
114
|
-
def mpd
|
115
|
-
self
|
116
99
|
end
|
117
100
|
|
118
101
|
def quote(args)
|
data/lib/rmpd/version.rb
CHANGED
@@ -30,23 +30,28 @@ describe Rmpd::Commands do
|
|
30
30
|
@socket.stub!(:readline).and_return(*(connect_response + ok))
|
31
31
|
@socket.should_receive(:close).exactly(5).times
|
32
32
|
lambda do
|
33
|
+
@conn.connect
|
33
34
|
@conn.ping
|
34
|
-
end.should raise_error(Rmpd::
|
35
|
+
end.should raise_error(Rmpd::MpdDisconnectedError)
|
35
36
|
end
|
36
37
|
|
37
38
|
it "should abort after a limited number of tries against a closed connection" do
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
pending do
|
40
|
+
@socket.stub!(:puts).and_raise(EOFError)
|
41
|
+
@socket.stub!(:readline).and_return(*(connect_response + ok))
|
42
|
+
@socket.should_receive(:close).exactly(5).times
|
43
|
+
lambda do
|
44
|
+
@conn.connect
|
45
|
+
@conn.ping
|
46
|
+
end.should raise_error(MpdError, "Retry count exceeded")
|
47
|
+
end
|
44
48
|
end
|
45
49
|
|
46
50
|
describe "close" do
|
47
51
|
it "should close the socket" do
|
48
52
|
@socket.stub!(:readline).and_return(*connect_response)
|
49
53
|
@socket.should_receive(:close).once
|
54
|
+
@conn.connect
|
50
55
|
@conn.ping
|
51
56
|
@conn.close
|
52
57
|
end
|
@@ -57,6 +62,7 @@ describe Rmpd::Commands do
|
|
57
62
|
set_password
|
58
63
|
@socket.stub!(:readline).and_return(*connect_and_auth_responses)
|
59
64
|
$stderr.should_receive(:puts).with(/deprecated/i)
|
65
|
+
@conn.connect
|
60
66
|
@conn.volume(0)
|
61
67
|
end
|
62
68
|
end
|
@@ -78,7 +84,7 @@ describe Rmpd::Commands do
|
|
78
84
|
@song_id = 1
|
79
85
|
@cmd = "playlistinfo \"#{@song_id}\""
|
80
86
|
@responses = connect_and_auth_responses + ["file: blah\n", "boobies: yay!\n"] + ok
|
81
|
-
@command = Proc.new {@conn.playlistinfo(@song_id)}
|
87
|
+
@command = Proc.new {@conn.connect; @conn.playlistinfo(@song_id)}
|
82
88
|
end
|
83
89
|
|
84
90
|
it_should_behave_like "a command with a song pos"
|
@@ -90,7 +96,7 @@ describe Rmpd::Commands do
|
|
90
96
|
@song_id = 12
|
91
97
|
@cmd = "play \"#{@song_id}\""
|
92
98
|
@responses = connect_and_auth_responses + ok
|
93
|
-
@command = Proc.new {@conn.play(@song_id)}
|
99
|
+
@command = Proc.new {@conn.connect; @conn.play(@song_id)}
|
94
100
|
end
|
95
101
|
|
96
102
|
it_should_behave_like "a command with a song pos"
|
@@ -102,7 +108,7 @@ describe Rmpd::Commands do
|
|
102
108
|
@song_id = 23
|
103
109
|
@cmd = "delete \"#{@song_id}\""
|
104
110
|
@responses = connect_and_auth_responses + ok
|
105
|
-
@command = Proc.new {@conn.delete(@song_id)}
|
111
|
+
@command = Proc.new {@conn.connect; @conn.delete(@song_id)}
|
106
112
|
end
|
107
113
|
|
108
114
|
it_should_behave_like "a command with a song pos"
|
@@ -115,6 +121,7 @@ describe Rmpd::Commands do
|
|
115
121
|
@socket.stub!(:puts).and_return(@socket.puts)
|
116
122
|
@socket.stub!(:eof?).and_return(false)
|
117
123
|
|
124
|
+
@conn.connect
|
118
125
|
@conn.command_list do |c|
|
119
126
|
c.status
|
120
127
|
c.stats
|
@@ -127,6 +134,7 @@ describe Rmpd::Commands do
|
|
127
134
|
@socket.stub!(:puts).and_return(@socket.puts)
|
128
135
|
@socket.stub!(:eof?).and_return(false)
|
129
136
|
|
137
|
+
@conn.connect
|
130
138
|
@conn.command_list do |c|
|
131
139
|
c.addid("foo")
|
132
140
|
end
|
@@ -139,6 +147,7 @@ describe Rmpd::Commands do
|
|
139
147
|
@responses = connect_response
|
140
148
|
@socket.stub!(:readline).and_return(*@responses)
|
141
149
|
|
150
|
+
@conn.connect
|
142
151
|
@conn.noidle.should be_nil
|
143
152
|
end
|
144
153
|
|
@@ -146,6 +155,7 @@ describe Rmpd::Commands do
|
|
146
155
|
@responses = connect_response + status_response + ok
|
147
156
|
@socket.stub!(:readline).and_return(*@responses)
|
148
157
|
|
158
|
+
@conn.connect
|
149
159
|
response = @conn.status
|
150
160
|
|
151
161
|
response.should have(2).items, response.pretty_inspect
|
@@ -161,6 +171,7 @@ describe Rmpd::Commands do
|
|
161
171
|
@socket.stub!(:puts).and_return(@socket.puts)
|
162
172
|
@socket.stub!(:eof?).and_return(false)
|
163
173
|
|
174
|
+
@conn.connect
|
164
175
|
results = @conn.command_list_ok do |c|
|
165
176
|
c.list("album")
|
166
177
|
c.list("artist")
|
@@ -18,6 +18,7 @@ describe Connection do
|
|
18
18
|
it "should connect successfully" do
|
19
19
|
responses = connect_response + ok
|
20
20
|
@socket.should_receive(:readline).and_return(*responses)
|
21
|
+
@conn.connect
|
21
22
|
@conn.ping
|
22
23
|
end
|
23
24
|
|
@@ -25,6 +26,7 @@ describe Connection do
|
|
25
26
|
responses = connect_and_auth_responses + ok
|
26
27
|
set_password
|
27
28
|
@socket.should_receive(:readline).and_return(*responses)
|
29
|
+
@conn.connect
|
28
30
|
@conn.ping
|
29
31
|
end
|
30
32
|
|
@@ -40,6 +42,7 @@ describe Connection do
|
|
40
42
|
it "should handle connection failures gracefully" do
|
41
43
|
@socket.stub!(:connect).and_raise(Errno::ECONNREFUSED.new("test"))
|
42
44
|
lambda do
|
45
|
+
@conn.connect
|
43
46
|
@conn.ping
|
44
47
|
end.should raise_error(Rmpd::MpdError)
|
45
48
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rmpd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Wollesen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-09-
|
11
|
+
date: 2016-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|