rbrainz 0.4.2 → 0.5.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 (118) hide show
  1. data/CHANGES +13 -1
  2. data/LICENSE +1 -1
  3. data/README +2 -2
  4. data/Rakefile +2 -2
  5. data/TODO +9 -2
  6. data/doc/README.rdoc +5 -5
  7. data/examples/getartist.rb +3 -2
  8. data/examples/getlabel.rb +3 -2
  9. data/examples/getrelease.rb +5 -2
  10. data/examples/getreleasegroup.rb +53 -0
  11. data/examples/gettrack.rb +3 -2
  12. data/examples/getuser.rb +2 -1
  13. data/examples/rate.rb +44 -0
  14. data/examples/searchartists.rb +3 -2
  15. data/examples/searchcdstubs.rb +41 -0
  16. data/examples/searchlabels.rb +3 -2
  17. data/examples/searchreleasegroups.rb +36 -0
  18. data/examples/searchreleases.rb +6 -4
  19. data/examples/searchtracks.rb +3 -2
  20. data/examples/submit_isrcs.rb +52 -0
  21. data/examples/tag.rb +3 -2
  22. data/lib/rbrainz.rb +2 -1
  23. data/lib/rbrainz/core_ext.rb +2 -1
  24. data/lib/rbrainz/core_ext/mbid.rb +2 -1
  25. data/lib/rbrainz/core_ext/net_http_digest.rb +3 -2
  26. data/lib/rbrainz/core_ext/range.rb +3 -2
  27. data/lib/rbrainz/core_ext/range/equality.rb +2 -1
  28. data/lib/rbrainz/data/countrynames.rb +6 -3
  29. data/lib/rbrainz/data/languagenames.rb +3 -2
  30. data/lib/rbrainz/data/releasetypenames.rb +3 -2
  31. data/lib/rbrainz/data/scriptnames.rb +3 -2
  32. data/lib/rbrainz/model.rb +3 -2
  33. data/lib/rbrainz/model/alias.rb +3 -2
  34. data/lib/rbrainz/model/artist.rb +11 -3
  35. data/lib/rbrainz/model/collection.rb +3 -2
  36. data/lib/rbrainz/model/default_factory.rb +18 -6
  37. data/lib/rbrainz/model/disc.rb +3 -2
  38. data/lib/rbrainz/model/entity.rb +2 -102
  39. data/lib/rbrainz/model/incomplete_date.rb +3 -2
  40. data/lib/rbrainz/model/individual.rb +11 -2
  41. data/lib/rbrainz/model/isrc.rb +100 -0
  42. data/lib/rbrainz/model/label.rb +5 -2
  43. data/lib/rbrainz/model/mbid.rb +28 -9
  44. data/lib/rbrainz/model/rateable.rb +34 -0
  45. data/lib/rbrainz/model/rating.rb +56 -0
  46. data/lib/rbrainz/model/relateable.rb +118 -0
  47. data/lib/rbrainz/model/relation.rb +2 -1
  48. data/lib/rbrainz/model/release.rb +17 -3
  49. data/lib/rbrainz/model/release_event.rb +3 -2
  50. data/lib/rbrainz/model/release_group.rb +97 -0
  51. data/lib/rbrainz/model/scored_collection.rb +3 -2
  52. data/lib/rbrainz/model/tag.rb +5 -4
  53. data/lib/rbrainz/model/taggable.rb +27 -0
  54. data/lib/rbrainz/model/track.rb +15 -2
  55. data/lib/rbrainz/model/user.rb +3 -2
  56. data/lib/rbrainz/utils.rb +2 -1
  57. data/lib/rbrainz/utils/data.rb +3 -2
  58. data/lib/rbrainz/utils/helper.rb +8 -2
  59. data/lib/rbrainz/version.rb +3 -2
  60. data/lib/rbrainz/webservice.rb +12 -7
  61. data/lib/rbrainz/webservice/filter.rb +53 -4
  62. data/lib/rbrainz/webservice/includes.rb +72 -11
  63. data/lib/rbrainz/webservice/mbxml.rb +129 -67
  64. data/lib/rbrainz/webservice/query.rb +156 -16
  65. data/lib/rbrainz/webservice/webservice.rb +104 -116
  66. data/test/lib/mock_webservice.rb +9 -2
  67. data/test/lib/test_entity.rb +2 -97
  68. data/test/lib/test_factory.rb +9 -1
  69. data/test/lib/test_rateable.rb +31 -0
  70. data/test/lib/test_relateable.rb +103 -0
  71. data/test/lib/test_taggable.rb +36 -0
  72. data/test/lib/testing_helper.rb +17 -2
  73. data/test/test-data/invalid/artist/ratings_1.xml +6 -0
  74. data/test/test-data/invalid/artist/ratings_2.xml +6 -0
  75. data/test/test-data/valid/artist/Tchaikovsky-2.xml +6 -0
  76. data/test/test-data/valid/label/Atlantic_Records_3.xml +6 -0
  77. data/test/test-data/valid/release-group/The_Cure_1.xml +36 -0
  78. data/test/test-data/valid/release/Highway_61_Revisited_2.xml +6 -0
  79. data/test/test-data/valid/track/Silent_All_These_Years_4.xml +3 -0
  80. data/test/test-data/valid/track/Silent_All_These_Years_6.xml +8 -0
  81. data/test/test_alias.rb +2 -1
  82. data/test/test_artist.rb +24 -2
  83. data/test/test_artist_filter.rb +2 -1
  84. data/test/test_artist_includes.rb +13 -3
  85. data/test/test_collection.rb +3 -2
  86. data/test/test_default_factory.rb +8 -1
  87. data/test/test_disc.rb +2 -1
  88. data/test/test_incomplete_date.rb +2 -1
  89. data/test/test_isrc.rb +87 -0
  90. data/test/test_label.rb +8 -1
  91. data/test/test_label_filter.rb +2 -1
  92. data/test/test_label_includes.rb +10 -3
  93. data/test/test_mbid.rb +2 -1
  94. data/test/test_mbxml.rb +93 -2
  95. data/test/test_query.rb +68 -5
  96. data/test/test_range_equality.rb +2 -1
  97. data/test/test_rating.rb +46 -0
  98. data/test/test_relation.rb +2 -1
  99. data/test/test_release.rb +37 -2
  100. data/test/test_release_event.rb +2 -1
  101. data/test/test_release_filter.rb +15 -2
  102. data/test/test_release_group.rb +104 -0
  103. data/test/test_release_group_filter.rb +61 -0
  104. data/test/test_release_group_includes.rb +46 -0
  105. data/test/test_release_includes.rb +16 -3
  106. data/test/test_scored_collection.rb +3 -2
  107. data/test/test_tag.rb +2 -1
  108. data/test/test_track.rb +28 -1
  109. data/test/test_track_filter.rb +2 -1
  110. data/test/test_track_includes.rb +13 -3
  111. data/test/test_utils.rb +2 -1
  112. data/test/test_webservice.rb +11 -1
  113. metadata +38 -20
  114. data/debian/changelog +0 -11
  115. data/debian/compat +0 -1
  116. data/debian/control +0 -13
  117. data/debian/copyright +0 -25
  118. data/debian/rules +0 -48
@@ -1,4 +1,5 @@
1
- # $Id: query.rb 218 2008-09-02 07:45:33Z phw $
1
+ # -*- coding: utf-8 -*-
2
+ # $Id: query.rb 270 2009-05-24 22:15:29Z phw $
2
3
  #
3
4
  # Author:: Philipp Wolfer (mailto:phw@rubyforge.org)
4
5
  # Copyright:: Copyright (c) 2007, Nigel Graham, Philipp Wolfer
@@ -179,7 +180,7 @@ module MusicBrainz
179
180
  # or a options hash as expected by ArtistIncludes.
180
181
  #
181
182
  # If no artist with that ID can be found, include contains invalid tags
182
- # or there's a server problem, and exception is raised.
183
+ # or there's a server problem, an exception is raised.
183
184
  #
184
185
  # Raises:: ConnectionError, RequestError, ResourceNotFoundError, ResponseError
185
186
  def get_artist_by_id(id, includes = nil)
@@ -187,10 +188,10 @@ module MusicBrainz
187
188
  return get_entity_by_id(Model::Artist.entity_type, id, includes)
188
189
  end
189
190
 
190
- # Returns artists matching given criteria.
191
+ # Returns artists matching the given criteria.
191
192
  #
192
193
  # The parameter _filter_ must be an instance of ArtistFilter
193
- # or a options hash as expected by ArtistFilter.
194
+ # or an option hash as expected by ArtistFilter.
194
195
  #
195
196
  # Raises:: ConnectionError, RequestError, ResponseError
196
197
  def get_artists(filter)
@@ -198,13 +199,38 @@ module MusicBrainz
198
199
  return get_entities(Model::Artist.entity_type, filter)
199
200
  end
200
201
 
201
- # Returns an release.
202
+ # Returns a release group.
203
+ #
204
+ # The parameter _includes_ must be an instance of ReleaseGroupIncludes
205
+ # or a options hash as expected by ReleaseGroupIncludes.
206
+ #
207
+ # If no release group with that ID can be found, include contains invalid
208
+ # tags or there's a server problem, an exception is raised.
209
+ #
210
+ # Raises:: ConnectionError, RequestError, ResourceNotFoundError, ResponseError
211
+ def get_release_group_by_id(id, includes = nil)
212
+ includes = ReleaseGroupIncludes.new(includes) unless includes.nil? || includes.is_a?(ReleaseGroupIncludes)
213
+ return get_entity_by_id(Model::ReleaseGroup.entity_type, id, includes)
214
+ end
215
+
216
+ # Returns release groups matching the given criteria.
217
+ #
218
+ # The parameter _filter_ must be an instance of ReleaseGroupFilter
219
+ # or an option hash as expected by ReleaseGroupFilter.
220
+ #
221
+ # Raises:: ConnectionError, RequestError, ResponseError
222
+ def get_release_groups(filter)
223
+ filter = ReleaseGroupFilter.new(filter) unless filter.nil? || filter.is_a?(ReleaseGroupFilter)
224
+ return get_entities(Model::ReleaseGroup.entity_type, filter)
225
+ end
226
+
227
+ # Returns a release.
202
228
  #
203
229
  # The parameter _includes_ must be an instance of ReleaseIncludes
204
230
  # or a options hash as expected by ReleaseIncludes.
205
231
  #
206
232
  # If no release with that ID can be found, include contains invalid tags
207
- # or there's a server problem, and exception is raised.
233
+ # or there's a server problem, an exception is raised.
208
234
  #
209
235
  # Raises:: ConnectionError, RequestError, ResourceNotFoundError, ResponseError
210
236
  def get_release_by_id(id, includes = nil)
@@ -212,10 +238,10 @@ module MusicBrainz
212
238
  return get_entity_by_id(Model::Release.entity_type, id, includes)
213
239
  end
214
240
 
215
- # Returns releases matching given criteria.
241
+ # Returns releases matching the given criteria.
216
242
  #
217
243
  # The parameter _filter_ must be an instance of ReleaseFilter
218
- # or a options hash as expected by ReleaseFilter.
244
+ # or an option hash as expected by ReleaseFilter.
219
245
  #
220
246
  # Raises:: ConnectionError, RequestError, ResponseError
221
247
  def get_releases(filter)
@@ -223,13 +249,13 @@ module MusicBrainz
223
249
  return get_entities(Model::Release.entity_type, filter)
224
250
  end
225
251
 
226
- # Returns an track.
252
+ # Returns a track.
227
253
  #
228
254
  # The parameter _includes_ must be an instance of TrackIncludes
229
255
  # or a options hash as expected by TrackIncludes.
230
256
  #
231
257
  # If no track with that ID can be found, include contains invalid tags
232
- # or there's a server problem, and exception is raised.
258
+ # or there's a server problem, an exception is raised.
233
259
  #
234
260
  # Raises:: ConnectionError, RequestError, ResourceNotFoundError, ResponseError
235
261
  def get_track_by_id(id, includes = nil)
@@ -237,10 +263,10 @@ module MusicBrainz
237
263
  return get_entity_by_id(Model::Track.entity_type, id, includes)
238
264
  end
239
265
 
240
- # Returns tracks matching given criteria.
266
+ # Returns tracks matching the given criteria.
241
267
  #
242
268
  # The parameter _filter_ must be an instance of TrackFilter
243
- # or a options hash as expected by TrackFilter.
269
+ # or an option hash as expected by TrackFilter.
244
270
  #
245
271
  # Raises:: ConnectionError, RequestError, ResponseError
246
272
  def get_tracks(filter)
@@ -295,7 +321,7 @@ module MusicBrainz
295
321
  # Submit track to PUID mappings.
296
322
  #
297
323
  # The <em>tracks2puids</em> parameter has to be a Hash or Array
298
- # with track ID/PUID pairs. The track IDs are either instances of MBID,
324
+ # with track ID/PUID pairs. The track IDs are either instances of Model::MBID,
299
325
  # absolute URIs or the 36 character ASCII representation. PUIDs are
300
326
  # 36 characters ASCII strings.
301
327
  #
@@ -333,9 +359,59 @@ module MusicBrainz
333
359
  @webservice.post(:track, :params=>params)
334
360
  end
335
361
 
336
- # Submit tags for an entity. _mbid_ must be an instance of MBID identifying
362
+ # Submit track to ISRC mappings.
363
+ #
364
+ # The <em>tracks2isrcs</em> parameter has to be a Hash or Array
365
+ # with track ID/ISRC pairs. The track IDs are either instances of Model::MBID,
366
+ # absolute URIs or the 36 character ASCII representation. ISRCs are either
367
+ # instances of Model::ISRC or 12 character ASCII strings.
368
+ #
369
+ # Example:
370
+ # ws = Webservice::Webservice.new(
371
+ # :host => 'test.musicbrainz.org',
372
+ # :username => 'outsidecontext',
373
+ # :password => 'secret'
374
+ # )
375
+ #
376
+ # query = Webservice::Query.new(ws, :client_id=>'My Tagging App 1.0')
377
+ #
378
+ # query.submit_isrcs([
379
+ # ['7f574ec1-344c-4ae1-970d-3c757f9a717e', 'DED830049301'],
380
+ # ['1393122c-364c-4fb6-9a4b-17eddce90152', 'DED830049302'],
381
+ # ['2634965c-5299-4958-b0dc-47b166bb6898', 'DED830049303'],
382
+ # ['dad6b8a4-0412-4a80-9123-3e0ebddaf82d', 'DED830049304'],
383
+ # ['e1f7e805-33f3-4663-b294-3805b82405f9', 'DED830049305'],
384
+ # ['d9f932ad-de0d-44ca-bf35-ae8184f63909', 'DED830049306'],
385
+ # ['c983b62d-f528-433f-a402-a6317ce3d2d8', 'DED830049307'],
386
+ # ['9d50b06a-4136-427f-8d11-b2efb0141da6', 'DED830049308'],
387
+ # ['f2af3e3f-3f9f-4f8d-8b60-1d1b709aaf69', 'DED830049309'],
388
+ # ['059384bc-fb45-445e-ab77-950d6ccf587a', 'DED830049310'],
389
+ # ['2f4d7b47-a4ba-495a-b447-60b8287ed9c9', 'DED830049311'],
390
+ # ])
391
+ #
392
+ # Note that this method only works if a valid user name and
393
+ # password have been set. If username and/or password are incorrect,
394
+ # an AuthenticationError is raised. See the example in Query on
395
+ # how to supply authentication data.
396
+ #
397
+ # See:: http://musicbrainz.org/doc/ISRC
398
+ # Raises:: ConnectionError, RequestError, AuthenticationError, InvalidISRCError
399
+ def submit_isrcs(tracks2isrcs)
400
+ raise RequestError, 'Please supply a client ID' unless @client_id
401
+ params = [['client', @client_id.to_s]] # Encoded as utf-8
402
+
403
+ tracks2isrcs.each do |track_id, isrc|
404
+ track_id = Model::MBID.parse(track_id, :track).uuid
405
+ isrc = Model::ISRC.parse(isrc)
406
+ params << ['isrc', track_id + ' ' + isrc.to_str ]
407
+ end
408
+
409
+ @webservice.post(:track, :params=>params)
410
+ end
411
+
412
+ # Submit tags for an entity. _mbid_ must be an instance of Model::MBID identifying
337
413
  # the entity the tag should applied to and _tags_ is either and array or
338
- # Collection of Tag objects or a string with comma separated tags.
414
+ # Collection of Model::Tag objects or a string with comma separated tags.
339
415
  #
340
416
  # Note that this method only works if a valid user name and password have
341
417
  # been set. The tags will be applied for the authenticated user. If
@@ -395,6 +471,70 @@ module MusicBrainz
395
471
  return get_entities(:tag, "entity=#{mbid.entity}&id=#{mbid.uuid}").to_collection
396
472
  end
397
473
 
474
+ # Submit the user's rating for an entity. _mbid_ must be an instance of
475
+ # Model::MBID identifying the entity which should be rated and _rating_ is
476
+ # either a Model::Rating object or an integer value between 0 and 5.
477
+ #
478
+ # Note that this method only works if a valid user name and password have
479
+ # been set. The tags will be applied for the authenticated user. If
480
+ # username and/or password are incorrect, an AuthenticationError is raised.
481
+ # See the example in Query on how to supply authentication data.
482
+ #
483
+ # Example:
484
+ # ws = Webservice::Webservice.new(
485
+ # :host => 'test.musicbrainz.org',
486
+ # :username => 'outsidecontext',
487
+ # :password => 'secret'
488
+ # )
489
+ #
490
+ # query = Webservice::Query.new(ws)
491
+ #
492
+ # mbid = Model::MBID.new('http://musicbrainz.org/artist/10bf95b6-30e3-44f1-817f-45762cdc0de0')
493
+ # query.submit_user_rating(mbid, 5)
494
+ #
495
+ # See:: Model::Rating
496
+ # Raises:: ConnectionError, RequestError, AuthenticationError
497
+ def submit_user_rating(mbid, rating)
498
+ mbid = Model::MBID.parse(mbid)
499
+ params = {:entity=>mbid.entity, :id=>mbid.uuid, :rating=>rating.to_i}
500
+ @webservice.post(:rating, :params=>params)
501
+ end
502
+
503
+ # Returns the Model::Rating a user has applied to the entity
504
+ # identified by _mbid_.
505
+ #
506
+ # Note that this method only works if a valid user name and password have
507
+ # been set. Only the tags the authenticated user applied to the entity will
508
+ # be returned. If username and/or password are incorrect, an
509
+ # AuthenticationError is raised. See the example in Query on how to supply
510
+ # authentication data.
511
+ #
512
+ # Example:
513
+ # ws = Webservice::Webservice.new(
514
+ # :host => 'test.musicbrainz.org',
515
+ # :username => 'outsidecontext',
516
+ # :password => 'secret'
517
+ # )
518
+ #
519
+ # query = Webservice::Query.new(ws)
520
+ #
521
+ # mbid = Model::MBID.new('http://musicbrainz.org/artist/10bf95b6-30e3-44f1-817f-45762cdc0de0')
522
+ # rating = query.get_user_rating(mbid)
523
+ #
524
+ # See:: Model::Rating
525
+ # Raises:: ConnectionError, RequestError, ResponseError, AuthenticationError
526
+ def get_user_rating(mbid)
527
+ mbid = Model::MBID.parse(mbid)
528
+ stream = @webservice.get(:rating, :filter => "entity=#{mbid.entity}&id=#{mbid.uuid}")
529
+ begin
530
+ rating = MBXML.new(stream, @factory).get_entity(:user_rating)
531
+ rescue MBXML::ParseError => e
532
+ raise ResponseError, e.to_s
533
+ end
534
+ rating = Model::Rating.new unless rating
535
+ return rating
536
+ end
537
+
398
538
  private # ----------------------------------------------------------------
399
539
 
400
540
  # Helper method which will return any entity by ID.
@@ -430,4 +570,4 @@ module MusicBrainz
430
570
  end
431
571
 
432
572
  end
433
- end
573
+ end
@@ -1,4 +1,4 @@
1
- # $Id: webservice.rb 209 2008-06-22 21:53:55Z phw $
1
+ # $Id: webservice.rb 277 2009-05-25 19:33:26Z phw $
2
2
  #
3
3
  # Author:: Philipp Wolfer (mailto:phw@rubyforge.org)
4
4
  # Copyright:: Copyright (c) 2007, Nigel Graham, Philipp Wolfer
@@ -72,7 +72,7 @@ module MusicBrainz
72
72
  # [:username] The username to authenticate with.
73
73
  # [:password] The password to authenticate with.
74
74
  # [:user_agent] Value sent in the User-Agent HTTP header. Defaults to "rbrainz/#{RBRAINZ_VERSION}"
75
- # [:proxy] URL for the proxy server to connect through
75
+ # [:proxy] URI for the proxy server to connect through
76
76
  def initialize(options={ :host=>nil, :port=>nil, :path_prefix=>'/ws', :username=>nil, :password=>nil, :user_agent=>"rbrainz/#{RBRAINZ_VERSION}", :proxy=>nil })
77
77
  Utils.check_options options, :host, :port, :path_prefix, :username, :password, :user_agent, :proxy
78
78
  @host = options[:host] ? options[:host] : 'musicbrainz.org'
@@ -83,14 +83,7 @@ module MusicBrainz
83
83
  @user_agent = options[:user_agent] ? options[:user_agent] : "rbrainz/#{RBRAINZ_VERSION}"
84
84
  @open_timeout = nil
85
85
  @read_timeout = nil
86
- @proxy = {}
87
- unless options[:proxy].nil?
88
- uri = URI.parse( options[:proxy] )
89
- @proxy[:host], @proxy[:port] = uri.host, uri.port
90
- if uri.userinfo
91
- @proxy[:username], @proxy[:password] = uri.userinfo.split(/:/)
92
- end
93
- end
86
+ set_proxy_options(options)
94
87
  end
95
88
 
96
89
  # Query the Webservice with HTTP GET.
@@ -108,55 +101,9 @@ module MusicBrainz
108
101
  # See:: IWebservice#get
109
102
  def get(entity_type, options={ :id=>nil, :include=>nil, :filter=>nil, :version=>1 })
110
103
  Utils.check_options options, :id, :include, :filter, :version
111
- url = URI.parse(create_uri(entity_type, options))
112
- request = Net::HTTP::Get.new(url.request_uri)
113
- request['User-Agent'] = @user_agent
114
- connection = Net::HTTP.new(url.host, url.port, @proxy[:host], @proxy[:port])
115
-
116
- # Set timeouts
117
- connection.open_timeout = @open_timeout if @open_timeout
118
- connection.read_timeout = @read_timeout if @read_timeout
119
-
120
- # Make the request
121
- begin
122
- response = connection.start do |http|
123
- response = http.request(request)
124
- if response.is_a?(Net::HTTPProxyAuthenticationRequired) && @proxy[:username] && @proxy[:password]
125
- request = Net::HTTP::Post.new(url.request_uri)
126
- request['User-Agent'] = @user_agent
127
- request.proxy_select_auth(@proxy[:username], @proxy[:password], response)
128
- request.set_form_data(options[:params])
129
- response = http.request(request)
130
- end
131
-
132
- if response.is_a?(Net::HTTPUnauthorized) && @username && @password
133
- request = Net::HTTP::Get.new(url.request_uri)
134
- request['User-Agent'] = @user_agent
135
- request.select_auth @username, @password, response
136
- response = http.request(request)
137
- end
138
- response
139
- end
140
- rescue Timeout::Error, Errno::ETIMEDOUT
141
- raise ConnectionError.new('%s timed out' % url.to_s)
142
- rescue SocketError => e
143
- raise ConnectionError.new('%s (%s)' % [url.to_s, e.to_s])
144
- end
145
-
146
- # Handle response errors.
147
- if response.is_a? Net::HTTPBadRequest # 400
148
- raise RequestError.new(url.to_s)
149
- elsif response.is_a? Net::HTTPUnauthorized # 401
150
- raise AuthenticationError.new(url.to_s)
151
- elsif response.is_a? Net::HTTPNotFound # 404
152
- raise ResourceNotFoundError.new(url.to_s)
153
- elsif response.is_a? Net::HTTPForbidden
154
- raise AuthenticationError.new(url.to_s)
155
- elsif not response.is_a? Net::HTTPSuccess
156
- raise ConnectionError.new(response.class.name)
157
- end
158
-
159
- return ::StringIO.new(response.body)
104
+ uri = create_uri(entity_type, options)
105
+ response = open_connection_and_make_request(uri, :get)
106
+ return response
160
107
  end
161
108
 
162
109
  # Send data to the web service via HTTP-POST.
@@ -177,68 +124,35 @@ module MusicBrainz
177
124
  # See:: IWebservice#post
178
125
  def post(entity_type, options={ :id=>nil, :params=>[], :version=>1 })
179
126
  Utils.check_options options, :id, :params, :version
180
- url = URI.parse(create_uri(entity_type, options))
181
- request = Net::HTTP::Post.new(url.request_uri)
182
- request['User-Agent'] = @user_agent
183
- request.set_form_data(options[:params])
184
- connection = Net::HTTP.new(url.host, url.port, @proxy[:host], @proxy[:port])
185
-
186
- # Set timeouts
187
- connection.open_timeout = @open_timeout if @open_timeout
188
- connection.read_timeout = @read_timeout if @read_timeout
189
-
190
- # Make the request
191
- begin
192
- response = connection.start do |http|
193
- response = http.request(request)
194
-
195
- if response.is_a?(Net::HTTPProxyAuthenticationRequired) && @proxy[:username] && @proxy[:password]
196
- request = Net::HTTP::Post.new(url.request_uri)
197
- request['User-Agent'] = @user_agent
198
- request.proxy_select_auth(@proxy[:username], @proxy[:password], response)
199
- request.set_form_data(options[:params])
200
- response = http.request(request)
201
- end
202
- if response.is_a?(Net::HTTPUnauthorized) && @username && @password
203
- request = Net::HTTP::Post.new(url.request_uri)
204
- request['User-Agent'] = @user_agent
205
- request.select_auth( @username, @password, response)
206
- request.set_form_data(options[:params])
207
- response = http.request(request)
208
- end
209
- response
210
- end
211
- rescue Timeout::Error, Errno::ETIMEDOUT
212
- raise ConnectionError.new('%s timed out' % url.to_s)
213
- rescue SocketError => e
214
- raise ConnectionError.new('%s (%s)' % [url.to_s, e.to_s])
215
- end
216
-
217
- # Handle response errors.
218
- if response.is_a? Net::HTTPBadRequest # 400
219
- raise RequestError.new(url.to_s)
220
- elsif response.is_a? Net::HTTPUnauthorized # 401
221
- raise AuthenticationError.new(url.to_s)
222
- elsif response.is_a? Net::HTTPNotFound # 404
223
- raise ResourceNotFoundError.new(url.to_s)
224
- elsif response.is_a? Net::HTTPForbidden
225
- raise AuthenticationError.new(url.to_s)
226
- elsif not response.is_a? Net::HTTPSuccess
227
- raise ConnectionError.new(response.class.name)
228
- end
229
-
230
- return ::StringIO.new(response.body)
127
+ uri = create_uri(entity_type, options)
128
+ response = open_connection_and_make_request(uri, :post, options[:params])
129
+ return response
231
130
  end
232
131
 
233
132
  private # ----------------------------------------------------------------
234
133
 
134
+ def set_proxy_options(options)
135
+ @proxy = {}
136
+ unless options[:proxy].nil?
137
+ uri = URI.parse( options[:proxy] )
138
+ @proxy[:host], @proxy[:port] = uri.host, uri.port
139
+ if uri.userinfo
140
+ @proxy[:username], @proxy[:password] = uri.userinfo.split(/:/)
141
+ end
142
+ end
143
+ end
144
+
235
145
  # Builds a request URI for querying the webservice.
236
- def create_uri(entity_type, options = {:id=>nil, :include=>nil, :filter=>nil, :version=>1, :type=>nil})
146
+ def create_uri(entity_type, options = {:id=>nil, :include=>nil, :filter=>nil, :version=>1, :type=>'xml'})
237
147
  # Make sure the version is set
238
148
  options[:version] = 1 if options[:version].nil?
239
149
  options[:type] = 'xml' if options[:type].nil?
240
-
241
- # Build the URI
150
+ uri = build_uri_without_querystring(entity_type, options)
151
+ uri = append_querystring_to_uri(uri, options)
152
+ return URI.parse(uri)
153
+ end
154
+
155
+ def build_uri_without_querystring(entity_type, options)
242
156
  if options[:id]
243
157
  # Make sure the id is a MBID object
244
158
  id = options[:id]
@@ -252,14 +166,88 @@ module MusicBrainz
252
166
  uri = 'http://%s:%d%s/%d/%s/' %
253
167
  [@host, @port, @path_prefix, options[:version], entity_type]
254
168
  end
255
-
256
- # Append the querystring
169
+ return uri
170
+ end
171
+
172
+ def append_querystring_to_uri(uri, options)
257
173
  querystring = []
258
174
  querystring << 'type=' + CGI.escape(options[:type]) unless options[:type].nil?
259
175
  querystring << options[:include].to_s unless options[:include].nil?
260
176
  querystring << options[:filter].to_s unless options[:filter].nil?
261
177
  uri += '?' + querystring.join('&') unless querystring.empty?
262
- return uri
178
+ end
179
+
180
+ def open_connection_and_make_request(uri, request_type, form_data=nil)
181
+ connection = create_connection(uri)
182
+ response = make_request(connection, uri, request_type, form_data)
183
+ handle_response_errors(uri, response)
184
+ return ::StringIO.new(response.body)
185
+ end
186
+
187
+ def create_connection(uri)
188
+ connection = Net::HTTP.new(uri.host, uri.port, @proxy[:host], @proxy[:port])
189
+ set_connection_timeouts(connection)
190
+ return connection
191
+ end
192
+
193
+ def make_request(connection, uri, request_type, form_data=nil)
194
+ response = nil
195
+ begin
196
+ connection.start do |http|
197
+ request = create_request(uri, request_type, form_data)
198
+ response = http.request(request)
199
+ if response.is_a?(Net::HTTPProxyAuthenticationRequired) && @proxy[:username] && @proxy[:password]
200
+ request = create_request(uri, request_type, form_data)
201
+ request.proxy_select_auth(@proxy[:username], @proxy[:password], response)
202
+ response = http.request(request)
203
+ end
204
+
205
+ if response.is_a?(Net::HTTPUnauthorized) && @username && @password
206
+ request = create_request(uri, request_type, form_data)
207
+ request.select_auth @username, @password, response
208
+ response = http.request(request)
209
+ end
210
+ response
211
+ end
212
+ rescue Timeout::Error, Errno::ETIMEDOUT
213
+ raise ConnectionError.new('%s timed out' % uri.to_s)
214
+ rescue SocketError => e
215
+ raise ConnectionError.new('%s (%s)' % [uri.to_s, e.to_s])
216
+ rescue ::Exception => e
217
+ raise ConnectionError.new(e.to_s)
218
+ end
219
+ return response
220
+ end
221
+
222
+ def set_connection_timeouts(connection)
223
+ connection.open_timeout = @open_timeout if @open_timeout
224
+ connection.read_timeout = @read_timeout if @read_timeout
225
+ end
226
+
227
+ def create_request(uri, request_type, form_data=nil)
228
+ if request_type == :post
229
+ request = Net::HTTP::Post.new(uri.request_uri)
230
+ else
231
+ request = Net::HTTP::Get.new(uri.request_uri)
232
+ end
233
+ request['User-Agent'] = @user_agent
234
+ request.set_form_data(form_data) unless form_data.nil?
235
+ return request
236
+ end
237
+
238
+ # Handles response errors and raises appropriate exceptions
239
+ def handle_response_errors(uri, response)
240
+ if response.is_a? Net::HTTPBadRequest # 400
241
+ raise RequestError.new(uri.to_s)
242
+ elsif response.is_a? Net::HTTPUnauthorized # 401
243
+ raise AuthenticationError.new(uri.to_s)
244
+ elsif response.is_a? Net::HTTPNotFound # 404
245
+ raise ResourceNotFoundError.new(uri.to_s)
246
+ elsif response.is_a? Net::HTTPForbidden
247
+ raise AuthenticationError.new(uri.to_s)
248
+ elsif not response.is_a? Net::HTTPSuccess
249
+ raise ConnectionError.new(response.class.name)
250
+ end
263
251
  end
264
252
 
265
253
  end