25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
6.2KB

  1. import _pyio as _original_pyio
  2. import errno
  3. import os as _original_os
  4. import socket as _original_socket
  5. from io import (
  6. BufferedRandom as _OriginalBufferedRandom,
  7. BufferedReader as _OriginalBufferedReader,
  8. BufferedWriter as _OriginalBufferedWriter,
  9. DEFAULT_BUFFER_SIZE,
  10. TextIOWrapper as _OriginalTextIOWrapper,
  11. IOBase as _OriginalIOBase,
  12. )
  13. from types import FunctionType
  14. from eventlet.greenio.base import (
  15. _operation_on_closed_file,
  16. greenpipe_doc,
  17. set_nonblocking,
  18. SOCKET_BLOCKING,
  19. )
  20. from eventlet.hubs import notify_close, notify_opened, IOClosed, trampoline
  21. from eventlet.support import get_errno
  22. import six
  23. __all__ = ['_fileobject', 'GreenPipe']
  24. # TODO get rid of this, it only seems like the original _fileobject
  25. _fileobject = _original_socket.SocketIO
  26. # Large part of the following code is copied from the original
  27. # eventlet.greenio module
  28. class GreenFileIO(_OriginalIOBase):
  29. def __init__(self, name, mode='r', closefd=True, opener=None):
  30. if isinstance(name, int):
  31. fileno = name
  32. self._name = "<fd:%d>" % fileno
  33. else:
  34. assert isinstance(name, six.string_types)
  35. with open(name, mode) as fd:
  36. self._name = fd.name
  37. fileno = _original_os.dup(fd.fileno())
  38. notify_opened(fileno)
  39. self._fileno = fileno
  40. self._mode = mode
  41. self._closed = False
  42. set_nonblocking(self)
  43. self._seekable = None
  44. @property
  45. def closed(self):
  46. return self._closed
  47. def seekable(self):
  48. if self._seekable is None:
  49. try:
  50. _original_os.lseek(self._fileno, 0, _original_os.SEEK_CUR)
  51. except IOError as e:
  52. if get_errno(e) == errno.ESPIPE:
  53. self._seekable = False
  54. else:
  55. raise
  56. else:
  57. self._seekable = True
  58. return self._seekable
  59. def readable(self):
  60. return 'r' in self._mode or '+' in self._mode
  61. def writable(self):
  62. return 'w' in self._mode or '+' in self._mode
  63. def fileno(self):
  64. return self._fileno
  65. def read(self, size=-1):
  66. if size == -1:
  67. return self.readall()
  68. while True:
  69. try:
  70. return _original_os.read(self._fileno, size)
  71. except OSError as e:
  72. if get_errno(e) not in SOCKET_BLOCKING:
  73. raise IOError(*e.args)
  74. self._trampoline(self, read=True)
  75. def readall(self):
  76. buf = []
  77. while True:
  78. try:
  79. chunk = _original_os.read(self._fileno, DEFAULT_BUFFER_SIZE)
  80. if chunk == b'':
  81. return b''.join(buf)
  82. buf.append(chunk)
  83. except OSError as e:
  84. if get_errno(e) not in SOCKET_BLOCKING:
  85. raise IOError(*e.args)
  86. self._trampoline(self, read=True)
  87. def readinto(self, b):
  88. up_to = len(b)
  89. data = self.read(up_to)
  90. bytes_read = len(data)
  91. b[:bytes_read] = data
  92. return bytes_read
  93. def isatty(self):
  94. try:
  95. return _original_os.isatty(self.fileno())
  96. except OSError as e:
  97. raise IOError(*e.args)
  98. def _trampoline(self, fd, read=False, write=False, timeout=None, timeout_exc=None):
  99. if self._closed:
  100. # Don't trampoline if we're already closed.
  101. raise IOClosed()
  102. try:
  103. return trampoline(fd, read=read, write=write, timeout=timeout,
  104. timeout_exc=timeout_exc,
  105. mark_as_closed=self._mark_as_closed)
  106. except IOClosed:
  107. # Our fileno has been obsoleted. Defang ourselves to
  108. # prevent spurious closes.
  109. self._mark_as_closed()
  110. raise
  111. def _mark_as_closed(self):
  112. """ Mark this socket as being closed """
  113. self._closed = True
  114. def write(self, data):
  115. view = memoryview(data)
  116. datalen = len(data)
  117. offset = 0
  118. while offset < datalen:
  119. try:
  120. written = _original_os.write(self._fileno, view[offset:])
  121. except OSError as e:
  122. if get_errno(e) not in SOCKET_BLOCKING:
  123. raise IOError(*e.args)
  124. trampoline(self, write=True)
  125. else:
  126. offset += written
  127. return offset
  128. def close(self):
  129. if not self._closed:
  130. self._closed = True
  131. _original_os.close(self._fileno)
  132. notify_close(self._fileno)
  133. for method in [
  134. 'fileno', 'flush', 'isatty', 'next', 'read', 'readinto',
  135. 'readline', 'readlines', 'seek', 'tell', 'truncate',
  136. 'write', 'xreadlines', '__iter__', '__next__', 'writelines']:
  137. setattr(self, method, _operation_on_closed_file)
  138. def truncate(self, size=-1):
  139. if size == -1:
  140. size = self.tell()
  141. try:
  142. rv = _original_os.ftruncate(self._fileno, size)
  143. except OSError as e:
  144. raise IOError(*e.args)
  145. else:
  146. self.seek(size) # move position&clear buffer
  147. return rv
  148. def seek(self, offset, whence=_original_os.SEEK_SET):
  149. try:
  150. return _original_os.lseek(self._fileno, offset, whence)
  151. except OSError as e:
  152. raise IOError(*e.args)
  153. def __enter__(self):
  154. return self
  155. def __exit__(self, *args):
  156. self.close()
  157. _open_environment = dict(globals())
  158. _open_environment.update(dict(
  159. BufferedRandom=_OriginalBufferedRandom,
  160. BufferedWriter=_OriginalBufferedWriter,
  161. BufferedReader=_OriginalBufferedReader,
  162. TextIOWrapper=_OriginalTextIOWrapper,
  163. FileIO=GreenFileIO,
  164. os=_original_os,
  165. ))
  166. _open = FunctionType(
  167. six.get_function_code(_original_pyio.open),
  168. _open_environment,
  169. )
  170. def GreenPipe(name, mode="r", buffering=-1, encoding=None, errors=None,
  171. newline=None, closefd=True, opener=None):
  172. try:
  173. fileno = name.fileno()
  174. except AttributeError:
  175. pass
  176. else:
  177. fileno = _original_os.dup(fileno)
  178. name.close()
  179. name = fileno
  180. return _open(name, mode, buffering, encoding, errors, newline, closefd, opener)
  181. GreenPipe.__doc__ = greenpipe_doc