root / trunk / twisted / internet / _win32stdio.py

Revision 16524, 2.9 kB (checked in by glyph, 3 years ago)

Further enhance win32 portability of subprocess support.

Author: glyph

Reviewer: jerub

Fixes #1553 -- finally.

twisted.internet.stdio previously did not support Windows properly: it did not
provide IConsumer, IHalfCloseableXXX or IProducer. This merge fixes those
problems, making it much easier to spawn subprocesses which themselves use
Twisted. Much better test coverage of stdio for all platforms is also
included.

Line 
1 # -*- test-case-name: twisted.test.test_process.ProcessTestCase.testStdio -*-
2
3 import win32api
4 import os, msvcrt
5
6 from zope.interface import implements
7
8 from twisted.internet.interfaces import IHalfCloseableProtocol, ITransport, IAddress
9 from twisted.internet.interfaces import IConsumer, IPushProducer
10
11 from twisted.internet import _pollingfile, main
12
13 class Win32PipeAddress(object):
14     implements(IAddress)
15
16 class StandardIO(_pollingfile._PollingTimer):
17
18     implements(ITransport,
19                IConsumer,
20                IPushProducer)
21
22     disconnecting = False
23     disconnected = False
24
25     def __init__(self, proto):
26         """
27         Start talking to standard IO with the given protocol.
28
29         Also, put it stdin/stdout/stderr into binary mode.
30         """
31         from twisted.internet import reactor
32
33         for stdfd in range(0, 1, 2):
34             msvcrt.setmode(stdfd, os.O_BINARY)
35
36         _pollingfile._PollingTimer.__init__(self, reactor)
37         self.proto = proto
38
39         hstdin = win32api.GetStdHandle(win32api.STD_INPUT_HANDLE)
40         hstdout = win32api.GetStdHandle(win32api.STD_OUTPUT_HANDLE)
41
42         self.stdin = _pollingfile._PollableReadPipe(
43             hstdin, self.dataReceived, self.readConnectionLost)
44
45         self.stdout = _pollingfile._PollableWritePipe(
46             hstdout, self.writeConnectionLost)
47
48         self._addPollableResource(self.stdin)
49         self._addPollableResource(self.stdout)
50
51         self.proto.makeConnection(self)
52
53     def dataReceived(self, data):
54         self.proto.dataReceived(data)
55
56     def readConnectionLost(self):
57         if IHalfCloseableProtocol.providedBy(self.proto):
58             self.proto.readConnectionLost()
59         self.checkConnLost()
60
61     def writeConnectionLost(self):
62         if IHalfCloseableProtocol.providedBy(self.proto):
63             self.proto.writeConnectionLost()
64         self.checkConnLost()
65
66     connsLost = 0
67
68     def checkConnLost(self):
69         self.connsLost += 1
70         if self.connsLost >= 2:
71             self.disconnecting = True
72             self.disconnected = True
73             self.proto.connectionLost(main.CONNECTION_DONE)
74
75     # ITransport
76
77     def write(self, data):
78         self.stdout.write(data)
79
80     def writeSequence(self, seq):
81         self.stdout.write(''.join(seq))
82
83     def loseConnection(self):
84         self.disconnecting = True
85         self.stdin.close()
86         self.stdout.close()
87
88     def getPeer(self):
89         return Win32PipeAddress()
90
91     def getHost(self):
92         return Win32PipeAddress()
93
94     # IConsumer
95
96     def registerProducer(self, producer, streaming):
97         return self.stdout.registerProducer(producer, streaming)
98
99     def unregisterProducer(self):
100         return self.stdout.unregisterProducer()
101
102     # def write() above
103
104     # IProducer
105
106     def stopProducing(self):
107         self.stdin.stopProducing()
108
109     # IPushProducer
110
111     def pauseProducing(self):
112         self.stdin.pauseProducing()
113
114     def resumeProducing(self):
115         self.stdin.resumeProducing()
116
Note: See TracBrowser for help on using the browser.