]> kaliko git repositories - python-musicpdaio.git/blobdiff - musicpdasio.py
Handles connection problems
[python-musicpdaio.git] / musicpdasio.py
index b52a3e3de301a32bb423b40e9790673769a39656..665674d32df7456a96a867babfab10c776e8f124 100644 (file)
@@ -21,7 +21,7 @@ try:
 except ImportError:
     print('Failed to import asyncio, need python >= 3.4')
 
-import sys
+import logging
 
 HELLO_PREFIX = "OK MPD "
 ERROR_PREFIX = "ACK "
@@ -65,7 +65,8 @@ class Response:
                 self.version)
 
 class MPDProto(asyncio.Protocol):
-    def __init__(self, future, payload):
+    def __init__(self, future, payload, cred):
+        self.transport = None
         self.future = future
         self.payload = payload
         self.sess = Response()
@@ -74,39 +75,44 @@ class MPDProto(asyncio.Protocol):
         self.transport = transport
         self.transport.write(bytes('{}\n'.format(self.payload), 'utf-8'))
 
-    def data_received(self, data):
-        rcv = data.decode('utf-8')
-        if '\n' not in rcv:
-            self.sess.err = ConnectionError('Connection lost while reading line')
-            self.future.set_result(self.sess)
-            raise ConnectionError('Connection lost while reading line')
-
-        rcv = rcv.strip('\n')
-
-        if rcv.startswith(HELLO_PREFIX):
-            self.sess.version = rcv[len(HELLO_PREFIX):]
-            return
+    def eof_received(self):
         self.transport.close()
+        err = ConnectionError('Connection lost while reading line')
+        self.future.set_exception(err)
+
+    def data_received(self, data):
+        #logging.debug(data.decode('utf-8'))
+        rcv = self._hello(data.decode('utf-8'))
 
-        # set the result on the Future so that the coroutine can
-        # resume
         if rcv.startswith(ERROR_PREFIX):
-            self.sess.err = rcv[len(ERROR_PREFIX):].strip()
-            self.future.set_result(self.sess)
-            return
-        else:
-            self.sess.resp = rcv
+            err = rcv[len(ERROR_PREFIX):].strip()
+            self.future.set_exception(CommandError(err))
+
+        self.sess.resp += rcv
+        if rcv.endswith(SUCCESS+'\n'):
+            self.transport.close()
             self.future.set_result(self.sess)
 
+    def _hello(self, rcv):
+        """Consume HELLO_PREFIX"""
+        if rcv.startswith(HELLO_PREFIX):
+            logging.debug('consumed hello prefix')
+            self.sess.version = rcv.split('\n')[0][len(HELLO_PREFIX):]
+            #print('consumed hello prefix: %s' % self.sess.version)
+            return rcv[rcv.find('\n')+1:]
+        return rcv
+
 class MPDClient:
     loop = asyncio.get_event_loop()
 
-    def __init__(self, host='localhost', port=6600):
+    def __init__(self, host='localhost', port=6600, cred=None):
         self._host = host
         self._port = port
+        self._cred = cred
         self._commands = {
                 'currentsong',
                 'stats',
+                'playlistinfo',
         }
 
     def __getattr__(self, attr):
@@ -119,16 +125,23 @@ class MPDClient:
                                      (self.__class__.__name__, attr))
         return lambda *args: wrapper(command, args)
 
+    @asyncio.coroutine
+    def _connect(self, proto):
+        # coroutine allowing Exception handling
+        # src: http://comments.gmane.org/gmane.comp.python.tulip/1401
+        try:
+            yield from MPDClient.loop.create_connection(lambda: proto,
+                    host=self._host,
+                    port=self._port)
+        except Exception as err:
+            proto.future.set_exception(ConnectionError(err))
+
     def _command(self, command, args):
-        # TODO: deal with encoding
-        payload = '{} {}'.format(command ,''.join(args))
+        payload = '{} {}'.format(command, ''.join(args))
         future = asyncio.Future()
-        # kick off a task to create the connection to MPD.
-        asyncio.async(MPDClient.loop.create_connection(
-                                    lambda: MPDProto(future, payload),
-                                    host=self._host,
-                                    port=self._port))
+        # kick off a task to create the connection to MPD
+        coro = self._connect(MPDProto(future, payload, self._cred))
+        asyncio.async(coro)
         MPDClient.loop.run_until_complete(future)
-        # return the future once completed.
-        return future.result()
-
+        # return once completed.
+        return future.result().resp