turntabler 0.2.0 → 0.2.1

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.
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