pvl.irk: crude support for reading lines from Irk
authorTero Marttila <terom@paivola.fi>
Sun, 13 Jan 2013 00:23:34 +0200
changeset 111 4b96c153c113
parent 110 af87b706e4a3
child 112 8127c0f4223d
pvl.irk: crude support for reading lines from Irk
pvl/irk.py
--- a/pvl/irk.py	Sat Jan 12 23:22:23 2013 +0200
+++ b/pvl/irk.py	Sun Jan 13 00:23:34 2013 +0200
@@ -7,7 +7,10 @@
 import logging; log = logging.getLogger('pvl.irk')
 
 # proto
-import socket, json
+import json
+
+# XXX: socket
+import socket, select
 
 def parser (parser, connect='tcp://localhost/', target=None) :
     """
@@ -97,7 +100,7 @@
         """
 
         if not url :
-            return cls(sys.stdout)
+            return cls(sys.stdout, recv=False)
 
         family, socktype = cls.SCHEME[url.scheme]
         
@@ -106,18 +109,32 @@
         else :
             # inet
             sock = connect(url.hostname, url.port or cls.PORT, family=family, socktype=socktype)
-        
-        return cls(sock.makefile('w'))
 
-    def __init__ (self, file) :
+        # XXX: just to make things a bit more exciting... and we really don't want to be blocking on our output..
+        sock.setblocking(False)
+        
+        return cls(sock.makefile('w'), recv=sock)
+
+    def __init__ (self, file, recv=None) :
         """
-            Use given file-like object for output.
+            Use given file-like object (write, flush, fileno) for output.
         """
 
         self.file = file
 
+        # XXX
+        self.recv = recv
+        self._buf = ''
+
         log.debug("%s", file)
 
+    def fileno (self) :
+        """
+            Return fd. Useful for detecting error conditions (connection lost).
+        """
+
+        return self.recv.fileno()
+
     def send (self, **opts) :
         """
             Raises IOError on write errors.
@@ -130,6 +147,62 @@
         self.file.write('\n')
         self.file.flush()
 
+    def read (self, size=512) :
+        """
+            Recieve data back from irkerd.
+            
+            Raise EOFError.
+
+            XXX: this is seriously crazy on a buffered file-like object..?
+        """
+        
+        # poll
+        read, _, _ = select.select((self.recv, ), (), (), 0.0)
+        
+        if read :
+            read = self.recv.recv(size)
+
+            if read :
+                return read
+            else :
+                raise EOFError()
+        else :
+            return None # block
+    
+    def readline (self) :
+        """
+            Yield line of input, or None.
+
+            Raise EOFError.
+        """
+
+        while '\n' not in self._buf :
+            read = self.read()
+
+            if not read :
+                return None # block
+            
+            self._buf += read
+
+        line, self._buf = self._buf.split('\n')
+
+        return line
+    
+    def readlines (self) :
+        """
+            Yield lines of input, until blocking.
+        """
+
+        while True :
+            line = self.readline()
+
+            if line :
+                yield line
+            else :
+                return
+    
+    __iter__ = readlines
+
 class IrkerTarget (object) :
     """
         A channel on an Irk connection.