root / trunk / twisted / internet / _posixstdio.py

Revision 25881, 4.9 kB (checked in by exarkun, 6 months ago)

Merge conch-losewriteconnection-3220

Author: JimD, exarkun
Reviewer: therve
Fixes: #3220

Replace the use of the deprecated StandardIO.closeStdin with use of the
equivalent StandardIO.loseWriteConnection. This eliminates a deprecation
warning when a Conch SSH session ends.

Line 
1 # -*- test-case-name: twisted.test.test_stdio -*-
2
3 """Standard input/out/err support.
4
5 Future Plans::
6
7     support for stderr, perhaps
8     Rewrite to use the reactor instead of an ad-hoc mechanism for connecting
9         protocols to transport.
10
11 Maintainer: James Y Knight
12 """
13
14 import warnings
15 from zope.interface import implements
16
17 from twisted.internet import process, error, interfaces
18 from twisted.python import log, failure
19
20
21 class PipeAddress(object):
22     implements(interfaces.IAddress)
23
24
25 class StandardIO(object):
26     implements(interfaces.ITransport, interfaces.IProducer, interfaces.IConsumer, interfaces.IHalfCloseableDescriptor)
27     _reader = None
28     _writer = None
29     disconnected = False
30     disconnecting = False
31
32     def __init__(self, proto, stdin=0, stdout=1):
33         from twisted.internet import reactor
34         self.protocol = proto
35
36         self._reader=process.ProcessReader(reactor, self, 'read', stdin)
37         self._reader.startReading()
38         self._writer=process.ProcessWriter(reactor, self, 'write', stdout)
39         self._writer.startReading()
40         self.protocol.makeConnection(self)
41
42     # ITransport
43
44     # XXX Actually, see #3597.
45     def loseWriteConnection(self):
46         if self._writer is not None:
47             self._writer.loseConnection()
48
49     def write(self, data):
50         if self._writer is not None:
51             self._writer.write(data)
52
53     def writeSequence(self, data):
54         if self._writer is not None:
55             self._writer.writeSequence(data)
56
57     def loseConnection(self):
58         self.disconnecting = True
59
60         if self._writer is not None:
61             self._writer.loseConnection()
62         if self._reader is not None:
63             # Don't loseConnection, because we don't want to SIGPIPE it.
64             self._reader.stopReading()
65
66     def getPeer(self):
67         return PipeAddress()
68
69     def getHost(self):
70         return PipeAddress()
71
72
73     # Callbacks from process.ProcessReader/ProcessWriter
74     def childDataReceived(self, fd, data):
75         self.protocol.dataReceived(data)
76
77     def childConnectionLost(self, fd, reason):
78         if self.disconnected:
79             return
80
81         if reason.value.__class__ == error.ConnectionDone:
82             # Normal close
83             if fd == 'read':
84                 self._readConnectionLost(reason)
85             else:
86                 self._writeConnectionLost(reason)
87         else:
88             self.connectionLost(reason)
89
90     def connectionLost(self, reason):
91         self.disconnected = True
92
93         # Make sure to cleanup the other half
94         _reader = self._reader
95         _writer = self._writer
96         protocol = self.protocol
97         self._reader = self._writer = None
98         self.protocol = None
99
100         if _writer is not None and not _writer.disconnected:
101             _writer.connectionLost(reason)
102
103         if _reader is not None and not _reader.disconnected:
104             _reader.connectionLost(reason)
105
106         try:
107             protocol.connectionLost(reason)
108         except:
109             log.err()
110
111     def _writeConnectionLost(self, reason):
112         self._writer=None
113         if self.disconnecting:
114             self.connectionLost(reason)
115             return
116
117         p = interfaces.IHalfCloseableProtocol(self.protocol, None)
118         if p:
119             try:
120                 p.writeConnectionLost()
121             except:
122                 log.err()
123                 self.connectionLost(failure.Failure())
124
125     def _readConnectionLost(self, reason):
126         self._reader=None
127         p = interfaces.IHalfCloseableProtocol(self.protocol, None)
128         if p:
129             try:
130                 p.readConnectionLost()
131             except:
132                 log.err()
133                 self.connectionLost(failure.Failure())
134         else:
135             self.connectionLost(reason)
136
137     # IConsumer
138     def registerProducer(self, producer, streaming):
139         if self._writer is None:
140             producer.stopProducing()
141         else:
142             self._writer.registerProducer(producer, streaming)
143
144     def unregisterProducer(self):
145         if self._writer is not None:
146             self._writer.unregisterProducer()
147
148     # IProducer
149     def stopProducing(self):
150         self.loseConnection()
151
152     def pauseProducing(self):
153         if self._reader is not None:
154             self._reader.pauseProducing()
155
156     def resumeProducing(self):
157         if self._reader is not None:
158             self._reader.resumeProducing()
159
160     # Stupid compatibility:
161     def closeStdin(self):
162         """Compatibility only, don't use. Same as loseWriteConnection."""
163         warnings.warn("This function is deprecated, use loseWriteConnection instead.",
164                       category=DeprecationWarning, stacklevel=2)
165         self.loseWriteConnection()
166
167     def stopReading(self):
168         """Compatibility only, don't use. Call pauseProducing."""
169         self.pauseProducing()
170
171     def startReading(self):
172         """Compatibility only, don't use. Call resumeProducing."""
173         self.resumeProducing()
Note: See TracBrowser for help on using the browser.