turntabler 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # master
2
2
 
3
+ ## 0.2.1 / 2013-02-16
4
+
5
+ * Fix exceptions on initial connection not causing reconnection process to kick in
6
+ * Fix exceptions in reconnects causing the reconnect process to halt retrying
7
+ * Fix reconnects not occurring when socket is closed without a killdashnine event from Turntable
8
+ * Fix exceptions in keepalive timer causing the EM reactor to be shut down
9
+
3
10
  ## 0.2.0 / 2013-02-16
4
11
 
5
12
  * Respect the keepalive update interval from API responses
@@ -17,7 +17,7 @@ GEM
17
17
  faye-websocket (0.4.6)
18
18
  eventmachine (>= 0.12.0)
19
19
  http_parser.rb (0.5.3)
20
- turntabler (0.2.0)
20
+ turntabler (0.2.1)
21
21
  em-http-request
22
22
  em-synchrony
23
23
  faye-websocket
@@ -77,9 +77,10 @@ module Turntabler
77
77
  # @raise [Turntabler::Error] if the command fails
78
78
  def login
79
79
  response = EventMachine::HttpRequest.new('https://turntable.fm/api/user.email_login').get(:query => {:email => email, :password => password, :client => client.id}).response
80
- data = JSON.parse(response)
81
- raise(Error, data[1]['err']) unless data[0]
82
- self.attributes = data[1]
80
+ success, data = response.empty? ? [nil, {}] : JSON.parse(response)
81
+ raise(ConnectionError, data['err']) unless success
82
+
83
+ self.attributes = data
83
84
  true
84
85
  end
85
86
 
@@ -71,14 +71,17 @@ module Turntabler
71
71
  # Setup default event handlers
72
72
  on(:heartbeat) { on_heartbeat }
73
73
  on(:session_missing) { on_session_missing }
74
+ on(:session_ended) { on_session_ended }
74
75
 
75
76
  # Connect to an initial room / server
76
- if room_name = options[:room]
77
- room(room_name).enter
78
- elsif url = options[:url]
79
- connect(url)
80
- else
81
- connect
77
+ reconnect_from(ConnectionError, APIError) do
78
+ if room_name = options[:room]
79
+ room(room_name).enter
80
+ elsif url = options[:url]
81
+ connect(url)
82
+ else
83
+ connect
84
+ end
82
85
  end
83
86
 
84
87
  instance_eval(&block) if block_given?
@@ -88,7 +91,7 @@ module Turntabler
88
91
  # this will also attempt to authenticate the user.
89
92
  #
90
93
  # @api private
91
- # @note This wil only open a new connection if the client isn't already connected to the given url
94
+ # @note This will only open a new connection if the client isn't already connected to the given url
92
95
  # @param [String] url The url to open a connection to
93
96
  # @return [true]
94
97
  # @raise [Turntabler::Error] if the connection cannot be opened
@@ -116,15 +119,20 @@ module Turntabler
116
119
  # @return [true]
117
120
  def close(allow_reconnect = false)
118
121
  if @connection
122
+ # Disable reconnects if specified
123
+ reconnect = @reconnect
124
+ @reconnect = reconnect && allow_reconnect
125
+
126
+ # Clean up timers / connections
119
127
  @keepalive_timer.cancel if @keepalive_timer
120
128
  @keepalive_timer = nil
121
129
  @connection.close
122
130
 
131
+ # Revert change to reconnect config once the final signal is received
123
132
  wait do |&resume|
124
133
  on(:session_ended, :once => true) { resume.call }
125
134
  end
126
-
127
- on_session_ended(allow_reconnect)
135
+ @reconnect = reconnect
128
136
  end
129
137
 
130
138
  true
@@ -146,7 +154,7 @@ module Turntabler
146
154
  # @return [Hash] The data returned from the Turntable service
147
155
  # @raise [Turntabler::Error] if the connection is not open or the command fails to execute
148
156
  def api(command, params = {})
149
- raise(Turntabler::Error, 'Connection is not open') unless @connection && @connection.connected?
157
+ raise(ConnectionError, 'Connection is not open') unless @connection && @connection.connected?
150
158
 
151
159
  message_id = @connection.publish(params.merge(:api => command))
152
160
 
@@ -159,7 +167,7 @@ module Turntabler
159
167
  data
160
168
  else
161
169
  error = data['error'] || data['err']
162
- raise Error, "Command \"#{command}\" failed with message: \"#{error}\""
170
+ raise APIError, "Command \"#{command}\" failed with message: \"#{error}\""
163
171
  end
164
172
  end
165
173
 
@@ -420,7 +428,7 @@ module Turntabler
420
428
  assert_valid_keys(options, :artist, :duration, :page)
421
429
  options = {:page => 1}.merge(options)
422
430
 
423
- raise(Turntabler::Error, 'User must be in a room to search for songs') unless room
431
+ raise(APIError, 'User must be in a room to search for songs') unless room
424
432
 
425
433
  if artist = options[:artist]
426
434
  query = "title: #{query}"
@@ -436,7 +444,7 @@ module Turntabler
436
444
  on(:search_failed, :once => true, :if => {'query' => query}) { resume.call }
437
445
  end
438
446
 
439
- songs || raise(Error, 'Search failed to complete')
447
+ songs || raise(APIError, 'Search failed to complete')
440
448
  end
441
449
 
442
450
  # Triggers callback handlers for the given Turntable command. This should
@@ -495,7 +503,9 @@ module Turntabler
495
503
 
496
504
  # Periodically update the user's status to remain available
497
505
  @keepalive_timer.cancel if @keepalive_timer
498
- @keepalive_timer = EM::Synchrony.add_periodic_timer(interval) { user.update(:status => user.status) }
506
+ @keepalive_timer = EM::Synchrony.add_periodic_timer(interval) do
507
+ Turntabler.run { user.update(:status => user.status) }
508
+ end
499
509
  end
500
510
  end
501
511
 
@@ -518,20 +528,38 @@ module Turntabler
518
528
 
519
529
  # Callback when the session has ended. This will automatically reconnect if
520
530
  # allowed to do so.
521
- def on_session_ended(allow_reconnect)
531
+ def on_session_ended
522
532
  url = @connection.url
523
533
  room = @room
524
534
  @connection = nil
525
535
  @room = nil
526
536
 
527
537
  # Automatically reconnect to the room / server if allowed
528
- if @reconnect && allow_reconnect
529
- EM::Synchrony.add_timer(@reconnect_wait) do
538
+ if @reconnect
539
+ reconnect_from(Exception) do
530
540
  room ? room.enter : connect(url)
531
541
  trigger(:reconnected)
532
542
  end
533
543
  end
534
544
  end
545
+
546
+ # Runs a given block and retries that block after a certain period of time
547
+ # if any of the specified exceptions are raised. Note that there is no
548
+ # limit on the number of attempts to retry.
549
+ def reconnect_from(*exceptions)
550
+ begin
551
+ yield
552
+ rescue *exceptions => ex
553
+ if @reconnect
554
+ logger.debug "Connection failed: #{ex.message}"
555
+ EM::Synchrony.sleep(@reconnect_wait)
556
+ logger.debug 'Attempting to reconnect'
557
+ retry
558
+ else
559
+ raise
560
+ end
561
+ end
562
+ end
535
563
 
536
564
  # Pauses the current fiber until it is resumed with response data. This
537
565
  # can only get resumed explicitly by the provided block.
@@ -1,5 +1,13 @@
1
1
  module Turntabler
2
- # Represents an error that occurred while interacting with the Turntable API
2
+ # Represents an error within the library
3
3
  class Error < StandardError
4
4
  end
5
+
6
+ # Represents an error that occurred while connecting to the Turntable API
7
+ class ConnectionError < Error
8
+ end
9
+
10
+ # Represents an error that occurred while interacting with the Turntable API
11
+ class APIError < Error
12
+ end
5
13
  end
@@ -1,6 +1,7 @@
1
1
  require 'pp'
2
2
  require 'turntabler/assertions'
3
3
  require 'turntabler/digest_helpers'
4
+ require 'turntabler/error'
4
5
 
5
6
  module Turntabler
6
7
  # Represents an object that's been created using content from Turntable. This
@@ -185,7 +186,7 @@ module Turntabler
185
186
 
186
187
  # Gets the current room the user is in
187
188
  def room
188
- client.room || raise(Turntabler::Error, 'User is not currently in a room')
189
+ client.room || raise(APIError, 'User is not currently in a room')
189
190
  end
190
191
 
191
192
  # Determines whether the user is currently in a room
@@ -128,7 +128,10 @@ module Turntabler
128
128
  def host
129
129
  begin
130
130
  response = EventMachine::HttpRequest.new("http://turntable.fm/api/room.which_chatserver?roomid=#{id}").get.response
131
- self.attributes = JSON.parse(response)[1]
131
+ success, data = response.empty? ? [nil, {}] : JSON.parse(response)
132
+ raise(ConnectionError, data['err']) unless success
133
+
134
+ self.attributes = data
132
135
  end unless @host
133
136
  @host
134
137
  end
@@ -1,4 +1,3 @@
1
- require 'turntabler/error'
2
1
  require 'turntabler/resource'
3
2
  require 'turntabler/user'
4
3
  require 'turntabler/vote'
@@ -232,7 +231,7 @@ module Turntabler
232
231
  # Asserts that this is the song currently being played in the room the user
233
232
  # is in. Raises Turntabler::Error if this is not the case.
234
233
  def assert_current_song
235
- raise(Turntabler::Error, "Song \"#{id}\" is not currently playing") unless room.current_song == self
234
+ raise(APIError, "Song \"#{id}\" is not currently playing") unless room.current_song == self
236
235
  end
237
236
 
238
237
  # Gets the index of this song within the given playlist. Raises Turntabler::Error
@@ -240,7 +239,7 @@ module Turntabler
240
239
  def index(playlist_id)
241
240
  playlist = client.user.playlist(playlist_id)
242
241
  index = playlist.songs.index(self)
243
- raise(Turntabler::Error, "Song \"#{id}\" is not in playlist \"#{playlist.id}\"") unless index
242
+ raise(APIError, "Song \"#{id}\" is not in playlist \"#{playlist.id}\"") unless index
244
243
  return playlist, index
245
244
  end
246
245
  end
@@ -3,7 +3,7 @@ module Turntabler
3
3
  module Version
4
4
  MAJOR = 0
5
5
  MINOR = 2
6
- PATCH = 0
6
+ PATCH = 1
7
7
  STRING = [MAJOR, MINOR, PATCH].join(".")
8
8
  end
9
9
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: turntabler
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.0
5
+ version: 0.2.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Aaron Pfeifer
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2013-02-16 00:00:00 Z
13
+ date: 2013-02-17 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: em-synchrony