]> kaliko git repositories - python-musicpdaio.git/blobdiff - musicpdasio.py
Plain asio API
[python-musicpdaio.git] / musicpdasio.py
index df730e063342fa5bda252f2a1467f0523e8cb3ce..8bd1ba447ed96c2ed6dee96d1603437a9fec9c1b 100644 (file)
 try:
     import asyncio
 except ImportError:
+    import sys
     print('Failed to import asyncio, need python >= 3.4')
+    sys.exit(1)
 
-import sys
+import logging
+
+from os import environ
+if 'DEBUG' in environ or 'PYTHONASYNCIODEBUG' in environ:
+    logging.basicConfig(level=logging.DEBUG)
 
 HELLO_PREFIX = "OK MPD "
 ERROR_PREFIX = "ACK "
@@ -56,11 +62,9 @@ class Response:
     def __init__(self):
         self.version = None
         self.resp = ''
-        self.err = None
 
     def __repr__(self):
-        return 'err:{0}, "{1}…" ({2})'.format(
-                self.err,
+        return '"{0}…" ({1})'.format(
                 ' '.join(self.resp.split('\n')[:2]),
                 self.version)
 
@@ -80,10 +84,8 @@ class MPDProto(asyncio.Protocol):
         err = ConnectionError('Connection lost while reading line')
         self.future.set_exception(err)
 
-    #def connection_lost(self):
-    #    self.eof_received()
-
     def data_received(self, data):
+        #logging.debug(data.decode('utf-8'))
         rcv = self._hello(data.decode('utf-8'))
 
         if rcv.startswith(ERROR_PREFIX):
@@ -92,22 +94,24 @@ class MPDProto(asyncio.Protocol):
 
         self.sess.resp += rcv
         if rcv.endswith(SUCCESS+'\n'):
+            logging.debug('set future result')
             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, cred=None):
+        self.eloop = asyncio.get_event_loop()
+        self.asio = False
+        self.futures = []
         self._host = host
         self._port = port
         self._cred = cred
@@ -118,6 +122,7 @@ class MPDClient:
         }
 
     def __getattr__(self, attr):
+        #logging.debug(attr)
         command = attr
         wrapper = self._command
         if command not in self._commands:
@@ -127,17 +132,37 @@ 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 self.eloop.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):
-        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, self._cred),
-                                    host=self._host,
-                                    port=self._port))
-        MPDClient.loop.run_until_complete(future)
-        #Useless?
-        #if future.exception():
-        #    raise future.exception()
-        # return once completed.
-        return future.result().resp
+        # kick off a task to create the connection to MPD
+        coro = self._connect(MPDProto(future, payload, self._cred))
+        asyncio.async(coro)
+        self.futures.append(future)
+        if not self.asio:
+            # return once completed.
+            self.eloop.run_until_complete(future)
+        return future
+        # alternative w/ callback
+        #if not self.asio:
+        #    future.add_done_callback(lambda ftr: MPDClient.loop.stop())
+        #    self.eloop.run_forever()
+        #return future
+
+    def run(self):
+        if self.futures:
+           self.eloop.run_until_complete(asyncio.gather(*self.futures))
+           self.futures = []
+        else:
+            logging.info('No task found in queue, need to set self.asio?')