Skip to content

Commit

Permalink
Updated error handling, including retry if Stop fails with error 718 …
Browse files Browse the repository at this point in the history
…(invalid instance ID)
  • Loading branch information
provegard committed Jul 31, 2011
1 parent 9e81742 commit e4eab2e
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 19 deletions.
25 changes: 23 additions & 2 deletions airpnp/bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
# POSSIBILITY OF SUCH DAMAGE.

import aplog as log
from device import CommandError
from device_discovery import DeviceDiscoveryService
from AirPlayService import AirPlayService, AirPlayOperations
from util import hms_to_sec, sec_to_hms
Expand Down Expand Up @@ -92,7 +93,8 @@ def client(self):

@client.setter
def client(self, value):
if not value is None and not self._client is None:
if not value is None and not self._client is None \
and value.host != self._client.host:
log.msg(1, "Rejecting client %r since device is busy (current "
"client = %r)" % (value, self._client))
raise ValueError("Device is busy")
Expand Down Expand Up @@ -177,14 +179,33 @@ def play(self, location, position):
def stop(self, info):
if self._uri is not None:
self.msg(1, 'Stopping playback')
self._avtransport.Stop(InstanceID=self._instance_id)
if not self._try_stop(1):
self.msg(1, "Failed to stop playback, device may still be "
"in a playing state")

# clear the URI to indicate that we don't play anymore
self._uri = None

# clear the client, so that we can accept another
self.client = None

def _try_stop(self, retries):
try:
self._avtransport.Stop(InstanceID=self._instance_id)
return True
except CommandError, e:
soap_err = e.get_soap_error()
if soap_err.code == '718':
self.msg(2, "Got 718 (invalid instance ID) for stop request, "
"tries left = %d" % (retries, ))
if retries:
return self._try_stop(retries - 1)
else:
# ignore
return False
else:
raise e

def reverse(self, info):
pass

Expand Down
11 changes: 9 additions & 2 deletions airpnp/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,13 @@ def add_xml_attrs(obj, element, namespace, attrs):


class CommandError(Exception):
pass

def __init__(self, reason, soap_error):
Exception.__init__(self, reason)
self._err = soap_error

def get_soap_error(self):
return self._err


class Device(object):
Expand Down Expand Up @@ -232,7 +238,8 @@ def __call__(self, service, **kwargs):
response = self._soap_sender(self._device, service.controlURL, msg)
if isinstance(response, SoapError):
raise CommandError('Command error: %s/%s' % (response.code,
response.desc))
response.desc),
response)
# populate the output dictionary
ret = {}
for arg in outargs:
Expand Down
18 changes: 3 additions & 15 deletions airpnp/device_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,27 +223,15 @@ def _send_soap_message(self, device, url, msg):
log.msg(3, 'Got response from device %s:\n%s' % (device,
answer.tostring()))
if isinstance(answer, SoapError):
# log only, don't raise - assume caller handles the error
log.msg(1, 'Error response for %s command to device %s: %s/%s' %
(msg.get_name(), device, answer.code, answer.desc))

# hide the device for a short while, hoping that the error is
# only temporary
reactor.callLater(0, self._flip, device, reactor)
return answer
except:
error = sys.exc_info()[0]
log.err(error, 'Failed to send command "%s" to device %s' %
log.err(None, 'Failed to send command "%s" to device %s' %
(msg.get_name(), device))

# treat the device as lost
reactor.callLater(0, self._device_expired, device.UDN)

raise error

def _flip(self, device, reactor):
"""Simulate a temporary device removal."""
self.on_device_removed(device)
reactor.callLater(1, self.on_device_found, device)
raise

def _device_error(self, event):
"""Handle error that occurred when building a device."""
Expand Down

0 comments on commit e4eab2e

Please sign in to comment.