You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

_posixstdio.py 4.6KB

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. # -*- test-case-name: twisted.test.test_stdio -*-
  2. """Standard input/out/err support.
  3. Future Plans::
  4. support for stderr, perhaps
  5. Rewrite to use the reactor instead of an ad-hoc mechanism for connecting
  6. protocols to transport.
  7. Maintainer: James Y Knight
  8. """
  9. from zope.interface import implementer
  10. from twisted.internet import process, error, interfaces
  11. from twisted.python import log, failure
  12. @implementer(interfaces.IAddress)
  13. class PipeAddress(object):
  14. pass
  15. @implementer(interfaces.ITransport, interfaces.IProducer,
  16. interfaces.IConsumer, interfaces.IHalfCloseableDescriptor)
  17. class StandardIO(object):
  18. _reader = None
  19. _writer = None
  20. disconnected = False
  21. disconnecting = False
  22. def __init__(self, proto, stdin=0, stdout=1, reactor=None):
  23. if reactor is None:
  24. from twisted.internet import reactor
  25. self.protocol = proto
  26. self._writer = process.ProcessWriter(reactor, self, 'write', stdout)
  27. self._reader = process.ProcessReader(reactor, self, 'read', stdin)
  28. self._reader.startReading()
  29. self.protocol.makeConnection(self)
  30. # ITransport
  31. # XXX Actually, see #3597.
  32. def loseWriteConnection(self):
  33. if self._writer is not None:
  34. self._writer.loseConnection()
  35. def write(self, data):
  36. if self._writer is not None:
  37. self._writer.write(data)
  38. def writeSequence(self, data):
  39. if self._writer is not None:
  40. self._writer.writeSequence(data)
  41. def loseConnection(self):
  42. self.disconnecting = True
  43. if self._writer is not None:
  44. self._writer.loseConnection()
  45. if self._reader is not None:
  46. # Don't loseConnection, because we don't want to SIGPIPE it.
  47. self._reader.stopReading()
  48. def getPeer(self):
  49. return PipeAddress()
  50. def getHost(self):
  51. return PipeAddress()
  52. # Callbacks from process.ProcessReader/ProcessWriter
  53. def childDataReceived(self, fd, data):
  54. self.protocol.dataReceived(data)
  55. def childConnectionLost(self, fd, reason):
  56. if self.disconnected:
  57. return
  58. if reason.value.__class__ == error.ConnectionDone:
  59. # Normal close
  60. if fd == 'read':
  61. self._readConnectionLost(reason)
  62. else:
  63. self._writeConnectionLost(reason)
  64. else:
  65. self.connectionLost(reason)
  66. def connectionLost(self, reason):
  67. self.disconnected = True
  68. # Make sure to cleanup the other half
  69. _reader = self._reader
  70. _writer = self._writer
  71. protocol = self.protocol
  72. self._reader = self._writer = None
  73. self.protocol = None
  74. if _writer is not None and not _writer.disconnected:
  75. _writer.connectionLost(reason)
  76. if _reader is not None and not _reader.disconnected:
  77. _reader.connectionLost(reason)
  78. try:
  79. protocol.connectionLost(reason)
  80. except:
  81. log.err()
  82. def _writeConnectionLost(self, reason):
  83. self._writer=None
  84. if self.disconnecting:
  85. self.connectionLost(reason)
  86. return
  87. p = interfaces.IHalfCloseableProtocol(self.protocol, None)
  88. if p:
  89. try:
  90. p.writeConnectionLost()
  91. except:
  92. log.err()
  93. self.connectionLost(failure.Failure())
  94. def _readConnectionLost(self, reason):
  95. self._reader=None
  96. p = interfaces.IHalfCloseableProtocol(self.protocol, None)
  97. if p:
  98. try:
  99. p.readConnectionLost()
  100. except:
  101. log.err()
  102. self.connectionLost(failure.Failure())
  103. else:
  104. self.connectionLost(reason)
  105. # IConsumer
  106. def registerProducer(self, producer, streaming):
  107. if self._writer is None:
  108. producer.stopProducing()
  109. else:
  110. self._writer.registerProducer(producer, streaming)
  111. def unregisterProducer(self):
  112. if self._writer is not None:
  113. self._writer.unregisterProducer()
  114. # IProducer
  115. def stopProducing(self):
  116. self.loseConnection()
  117. def pauseProducing(self):
  118. if self._reader is not None:
  119. self._reader.pauseProducing()
  120. def resumeProducing(self):
  121. if self._reader is not None:
  122. self._reader.resumeProducing()
  123. def stopReading(self):
  124. """Compatibility only, don't use. Call pauseProducing."""
  125. self.pauseProducing()
  126. def startReading(self):
  127. """Compatibility only, don't use. Call resumeProducing."""
  128. self.resumeProducing()