-
Notifications
You must be signed in to change notification settings - Fork 288
/
get-poetry-1.py
161 lines (109 loc) · 3.71 KB
/
get-poetry-1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# This is the Twisted Get Poetry Now! client, version 5.1
import optparse, random, sys
from twisted.internet import defer
from twisted.internet.protocol import Protocol, ClientFactory
def parse_args():
usage = """usage: %prog [options] [hostname]:port ...
This is the Get Poetry Now! client, Twisted version 5.1
Run it like this:
python get-poetry-1.py port1 port2 port3 ...
If you are in the base directory of the twisted-intro package,
you could run it like this:
python twisted-client-5/get-poetry-1.py 10001 10002 10003
to grab poetry from servers on ports 10001, 10002, and 10003.
Of course, there need to be servers listening on those ports
for that to work.
"""
parser = optparse.OptionParser(usage)
_, addresses = parser.parse_args()
if not addresses:
print(parser.format_help())
parser.exit()
def parse_address(addr):
if ':' not in addr:
host = '127.0.0.1'
port = addr
else:
host, port = addr.split(':', 1)
if not port.isdigit():
parser.error('Ports must be integers.')
return host, int(port)
return list(map(parse_address, addresses))
class PoetryProtocol(Protocol):
poem = b''
def dataReceived(self, data):
self.poem += data
def connectionLost(self, reason):
self.poemReceived(self.poem)
def poemReceived(self, poem):
self.factory.poem_finished(poem)
class PoetryClientFactory(ClientFactory):
protocol = PoetryProtocol
def __init__(self, deferred):
self.deferred = deferred
def poem_finished(self, poem):
if self.deferred is not None:
d, self.deferred = self.deferred, None
d.callback(poem)
def clientConnectionFailed(self, connector, reason):
if self.deferred is not None:
d, self.deferred = self.deferred, None
d.errback(reason)
def get_poetry(host, port):
"""
Download a poem from the given host and port. This function
returns a Deferred which will be fired with the complete text of
the poem or a Failure if the poem could not be downloaded.
"""
d = defer.Deferred()
from twisted.internet import reactor
factory = PoetryClientFactory(d)
reactor.connectTCP(host, port, factory)
return d
class GibberishError(Exception): pass
class CannotCummingsify(Exception): pass
def cummingsify(poem):
"""
Randomly do one of the following:
1. Return a cummingsified version of the poem.
2. Raise a GibberishError.
3. Raise a CannotCummingsify error with the original poem
as the first argument.
"""
def success():
return poem.lower()
def gibberish():
raise GibberishError()
def bug():
raise CannotCummingsify(poem)
poem = poem.decode('utf8')
return random.choice([success, gibberish, bug])()
def poetry_main():
addresses = parse_args()
from twisted.internet import reactor
poems = []
errors = []
def cummingsify_failed(err):
if err.check(CannotCummingsify):
print('Cummingsify failed!')
return err.value.args[0]
return err
def got_poem(poem):
print(poem)
poems.append(poem)
def poem_failed(err):
print('The poem download failed.', file=sys.stderr)
errors.append(err)
def poem_done(_):
if len(poems) + len(errors) == len(addresses):
reactor.stop()
for address in addresses:
host, port = address
d = get_poetry(host, port)
d.addCallback(cummingsify)
d.addErrback(cummingsify_failed)
d.addCallbacks(got_poem, poem_failed)
d.addBoth(poem_done)
reactor.run()
if __name__ == '__main__':
poetry_main()