"Fossies" - the Fresh Open Source Software Archive

Member "polysh-polysh-0.13/polysh/buffered_dispatcher.py" (11 May 2020, 3160 Bytes) of package /linux/privat/polysh-polysh-0.13.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "buffered_dispatcher.py" see the Fossies "Dox" file reference documentation.

    1 """Polysh - Buffered Dispatcher Class
    2 
    3 Copyright (c) 2006 Guillaume Chazarain <guichaz@gmail.com>
    4 Copyright (c) 2018 InnoGames GmbH
    5 """
    6 # This program is free software: you can redistribute it and/or modify
    7 # it under the terms of the GNU General Public License as published by
    8 # the Free Software Foundation, either version 2 of the License, or
    9 # (at your option) any later version.
   10 #
   11 # This program is distributed in the hope that it will be useful,
   12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 # GNU General Public License for more details.
   15 #
   16 # You should have received a copy of the GNU General Public License
   17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
   18 
   19 import asyncore
   20 import errno
   21 
   22 from polysh.console import console_output
   23 
   24 
   25 class BufferedDispatcher(asyncore.file_dispatcher):
   26     """A dispatcher with a write buffer to allow asynchronous writers, and a
   27     read buffer to permit line oriented manipulations"""
   28 
   29     # 1 MiB should be enough for everybody
   30     MAX_BUFFER_SIZE = 1 * 1024 * 1024
   31 
   32     def __init__(self, fd: int) -> None:
   33         asyncore.file_dispatcher.__init__(self, fd)
   34         self.fd = fd
   35         self.read_buffer = b''
   36         self.write_buffer = b''
   37 
   38     def handle_read(self) -> None:
   39         self._handle_read_chunk()
   40 
   41     def _handle_read_chunk(self) -> bytes:
   42         """Some data can be read"""
   43         new_data = b''
   44         buffer_length = len(self.read_buffer)
   45         try:
   46             while buffer_length < self.MAX_BUFFER_SIZE:
   47                 try:
   48                     piece = self.recv(4096)
   49                 except OSError as e:
   50                     if e.errno == errno.EAGAIN:
   51                         # End of the available data
   52                         break
   53                     elif e.errno == errno.EIO and new_data:
   54                         # Hopefully we could read an error message before the
   55                         # actual termination
   56                         break
   57                     else:
   58                         raise
   59 
   60                 if not piece:
   61                     # A closed connection is indicated by signaling a read
   62                     # condition, and having recv() return 0.
   63                     break
   64 
   65                 new_data += piece
   66                 buffer_length += len(piece)
   67 
   68         finally:
   69             new_data = new_data.replace(b'\r', b'\n')
   70             self.read_buffer += new_data
   71         return new_data
   72 
   73     def readable(self) -> bool:
   74         """No need to ask data if our buffer is already full"""
   75         return len(self.read_buffer) < self.MAX_BUFFER_SIZE
   76 
   77     def writable(self) -> bool:
   78         """Do we have something to write?"""
   79         return self.write_buffer != b''
   80 
   81     def dispatch_write(self, buf: bytes) -> bool:
   82         """Augment the buffer with stuff to write when possible"""
   83         self.write_buffer += buf
   84         if len(self.write_buffer) > self.MAX_BUFFER_SIZE:
   85             console_output('Buffer too big ({:d}) for {}\n'.format(
   86                 len(self.write_buffer), str(self)).encode())
   87             raise asyncore.ExitNow(1)
   88         return True