1
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
<title>Twisted Documentation: The Evolution of Finger: cleaning up the finger code</title>
4
<link href="../stylesheet.css" rel="stylesheet" type="text/css"/>
8
<h1 class="title">The Evolution of Finger: cleaning up the finger code</h1>
9
<div class="toc"><ol><li><a href="#auto0">Introduction</a></li><li><a href="#auto1">Write Readable Code</a></li></ol></div>
14
<h2>Introduction<a name="auto0"/></h2>
16
<p> This is the third part of the Twisted tutorial <a href="index.html" shape="rect">Twisted from Scratch, or The Evolution of Finger</a>.</p>
18
<p>In this section of the tutorial, we'll clean up our code so that it is
19
closer to a readable and extendable style.</p>
21
<h2>Write Readable Code<a name="auto1"/></h2>
23
<p>The last version of the application had a lot of hacks. We avoided
24
sub-classing, didn't support things like user listings over the web,
25
and removed all blank lines -- all in the interest of code
26
which is shorter. Here we take a step back, subclass what is more
27
naturally a subclass, make things which should take multiple lines
28
take them, etc. This shows a much better style of developing Twisted
29
applications, though the hacks in the previous stages are sometimes
30
used in throw-away prototypes.</p>
32
<div class="py-listing"><pre><p class="py-linenumber"> 1
169
</p><span class="py-src-comment"># Do everything properly</span>
170
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">internet</span>, <span class="py-src-variable">service</span>
171
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">protocol</span>, <span class="py-src-variable">reactor</span>, <span class="py-src-variable">defer</span>
172
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">words</span>.<span class="py-src-variable">protocols</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">irc</span>
173
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">protocols</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">basic</span>
174
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">resource</span>, <span class="py-src-variable">server</span>, <span class="py-src-variable">static</span>, <span class="py-src-variable">xmlrpc</span>
175
<span class="py-src-keyword">import</span> <span class="py-src-variable">cgi</span>
177
<span class="py-src-keyword">def</span> <span class="py-src-identifier">catchError</span>(<span class="py-src-parameter">err</span>):
178
<span class="py-src-keyword">return</span> <span class="py-src-string">"Internal error in server"</span>
180
<span class="py-src-keyword">class</span> <span class="py-src-identifier">FingerProtocol</span>(<span class="py-src-parameter">basic</span>.<span class="py-src-parameter">LineReceiver</span>):
182
<span class="py-src-keyword">def</span> <span class="py-src-identifier">lineReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">user</span>):
183
<span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">factory</span>.<span class="py-src-variable">getUser</span>(<span class="py-src-variable">user</span>)
184
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">catchError</span>)
185
<span class="py-src-keyword">def</span> <span class="py-src-identifier">writeValue</span>(<span class="py-src-parameter">value</span>):
186
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">value</span>+<span class="py-src-string">'\r\n'</span>)
187
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
188
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeValue</span>)
191
<span class="py-src-keyword">class</span> <span class="py-src-identifier">IRCReplyBot</span>(<span class="py-src-parameter">irc</span>.<span class="py-src-parameter">IRCClient</span>):
193
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
194
<span class="py-src-variable">self</span>.<span class="py-src-variable">nickname</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">factory</span>.<span class="py-src-variable">nickname</span>
195
<span class="py-src-variable">irc</span>.<span class="py-src-variable">IRCClient</span>.<span class="py-src-variable">connectionMade</span>(<span class="py-src-variable">self</span>)
197
<span class="py-src-keyword">def</span> <span class="py-src-identifier">privmsg</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">user</span>, <span class="py-src-parameter">channel</span>, <span class="py-src-parameter">msg</span>):
198
<span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">split</span>(<span class="py-src-string">'!'</span>)[<span class="py-src-number">0</span>]
199
<span class="py-src-keyword">if</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">nickname</span>.<span class="py-src-variable">lower</span>() == <span class="py-src-variable">channel</span>.<span class="py-src-variable">lower</span>():
200
<span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">factory</span>.<span class="py-src-variable">getUser</span>(<span class="py-src-variable">msg</span>)
201
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">catchError</span>)
202
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">m</span>: <span class="py-src-string">"Status of %s: %s"</span> % (<span class="py-src-variable">msg</span>, <span class="py-src-variable">m</span>))
203
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">m</span>: <span class="py-src-variable">self</span>.<span class="py-src-variable">msg</span>(<span class="py-src-variable">user</span>, <span class="py-src-variable">m</span>))
206
<span class="py-src-keyword">class</span> <span class="py-src-identifier">UserStatusTree</span>(<span class="py-src-parameter">resource</span>.<span class="py-src-parameter">Resource</span>):
207
<span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">service</span>):
208
<span class="py-src-variable">resource</span>.<span class="py-src-variable">Resource</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>)
209
<span class="py-src-variable">self</span>.<span class="py-src-variable">service</span> = <span class="py-src-variable">service</span>
211
<span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
212
<span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">service</span>.<span class="py-src-variable">getUsers</span>()
213
<span class="py-src-keyword">def</span> <span class="py-src-identifier">formatUsers</span>(<span class="py-src-parameter">users</span>):
214
<span class="py-src-variable">l</span> = [<span class="py-src-string">'<li><a href="%s">%s</a></li>'</span> % (<span class="py-src-variable">user</span>, <span class="py-src-variable">user</span>)
215
<span class="py-src-keyword">for</span> <span class="py-src-variable">user</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">users</span>]
216
<span class="py-src-keyword">return</span> <span class="py-src-string">'<ul>'</span>+<span class="py-src-string">''</span>.<span class="py-src-variable">join</span>(<span class="py-src-variable">l</span>)+<span class="py-src-string">'</ul>'</span>
217
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">formatUsers</span>)
218
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>)
219
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>())
220
<span class="py-src-keyword">return</span> <span class="py-src-variable">server</span>.<span class="py-src-variable">NOT_DONE_YET</span>
222
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getChild</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">path</span>, <span class="py-src-parameter">request</span>):
223
<span class="py-src-keyword">if</span> <span class="py-src-variable">path</span>==<span class="py-src-string">""</span>:
224
<span class="py-src-keyword">return</span> <span class="py-src-variable">UserStatusTree</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">service</span>)
225
<span class="py-src-keyword">else</span>:
226
<span class="py-src-keyword">return</span> <span class="py-src-variable">UserStatus</span>(<span class="py-src-variable">path</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">service</span>)
228
<span class="py-src-keyword">class</span> <span class="py-src-identifier">UserStatus</span>(<span class="py-src-parameter">resource</span>.<span class="py-src-parameter">Resource</span>):
230
<span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">user</span>, <span class="py-src-parameter">service</span>):
231
<span class="py-src-variable">resource</span>.<span class="py-src-variable">Resource</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>)
232
<span class="py-src-variable">self</span>.<span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>
233
<span class="py-src-variable">self</span>.<span class="py-src-variable">service</span> = <span class="py-src-variable">service</span>
235
<span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
236
<span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">service</span>.<span class="py-src-variable">getUser</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">user</span>)
237
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">cgi</span>.<span class="py-src-variable">escape</span>)
238
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">m</span>:
239
<span class="py-src-string">'<h1>%s</h1>'</span>%<span class="py-src-variable">self</span>.<span class="py-src-variable">user</span>+<span class="py-src-string">'<p>%s</p>'</span>%<span class="py-src-variable">m</span>)
240
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">request</span>.<span class="py-src-variable">write</span>)
241
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-variable">request</span>.<span class="py-src-variable">finish</span>())
242
<span class="py-src-keyword">return</span> <span class="py-src-variable">server</span>.<span class="py-src-variable">NOT_DONE_YET</span>
245
<span class="py-src-keyword">class</span> <span class="py-src-identifier">UserStatusXR</span>(<span class="py-src-parameter">xmlrpc</span>.<span class="py-src-parameter">XMLRPC</span>):
247
<span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">service</span>):
248
<span class="py-src-variable">xmlrpc</span>.<span class="py-src-variable">XMLRPC</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>)
249
<span class="py-src-variable">self</span>.<span class="py-src-variable">service</span> = <span class="py-src-variable">service</span>
251
<span class="py-src-keyword">def</span> <span class="py-src-identifier">xmlrpc_getUser</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">user</span>):
252
<span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">service</span>.<span class="py-src-variable">getUser</span>(<span class="py-src-variable">user</span>)
255
<span class="py-src-keyword">class</span> <span class="py-src-identifier">FingerService</span>(<span class="py-src-parameter">service</span>.<span class="py-src-parameter">Service</span>):
257
<span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">filename</span>):
258
<span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span> = <span class="py-src-variable">filename</span>
259
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = {}
260
<span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
262
<span class="py-src-keyword">def</span> <span class="py-src-identifier">_read</span>(<span class="py-src-parameter">self</span>):
263
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>.<span class="py-src-variable">clear</span>()
264
<span class="py-src-keyword">for</span> <span class="py-src-variable">line</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">file</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span>):
265
<span class="py-src-variable">user</span>, <span class="py-src-variable">status</span> = <span class="py-src-variable">line</span>.<span class="py-src-variable">split</span>(<span class="py-src-string">':'</span>, <span class="py-src-number">1</span>)
266
<span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">strip</span>()
267
<span class="py-src-variable">status</span> = <span class="py-src-variable">status</span>.<span class="py-src-variable">strip</span>()
268
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>[<span class="py-src-variable">user</span>] = <span class="py-src-variable">status</span>
269
<span class="py-src-variable">self</span>.<span class="py-src-variable">call</span> = <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-number">30</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>)
271
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getUser</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">user</span>):
272
<span class="py-src-keyword">return</span> <span class="py-src-variable">defer</span>.<span class="py-src-variable">succeed</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>.<span class="py-src-variable">get</span>(<span class="py-src-variable">user</span>, <span class="py-src-string">"No such user"</span>))
274
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getUsers</span>(<span class="py-src-parameter">self</span>):
275
<span class="py-src-keyword">return</span> <span class="py-src-variable">defer</span>.<span class="py-src-variable">succeed</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>.<span class="py-src-variable">keys</span>())
277
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
278
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
279
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerProtocol</span>
280
<span class="py-src-variable">f</span>.<span class="py-src-variable">getUser</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
281
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
283
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getResource</span>(<span class="py-src-parameter">self</span>):
284
<span class="py-src-variable">r</span> = <span class="py-src-variable">UserStatusTree</span>(<span class="py-src-variable">self</span>)
285
<span class="py-src-variable">x</span> = <span class="py-src-variable">UserStatusXR</span>(<span class="py-src-variable">self</span>)
286
<span class="py-src-variable">r</span>.<span class="py-src-variable">putChild</span>(<span class="py-src-string">'RPC2'</span>, <span class="py-src-variable">x</span>)
287
<span class="py-src-keyword">return</span> <span class="py-src-variable">r</span>
289
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getIRCBot</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">nickname</span>):
290
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ReconnectingClientFactory</span>()
291
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">IRCReplyBot</span>
292
<span class="py-src-variable">f</span>.<span class="py-src-variable">nickname</span> = <span class="py-src-variable">nickname</span>
293
<span class="py-src-variable">f</span>.<span class="py-src-variable">getUser</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
294
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
297
<span class="py-src-variable">application</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">Application</span>(<span class="py-src-string">'finger'</span>, <span class="py-src-variable">uid</span>=<span class="py-src-number">1</span>, <span class="py-src-variable">gid</span>=<span class="py-src-number">1</span>)
298
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
299
<span class="py-src-variable">serviceCollection</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>)
300
<span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">79</span>, <span class="py-src-variable">f</span>.<span class="py-src-variable">getFingerFactory</span>()
301
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
302
<span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">8000</span>, <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">f</span>.<span class="py-src-variable">getResource</span>())
303
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
304
<span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPClient</span>(<span class="py-src-string">'irc.freenode.org'</span>, <span class="py-src-number">6667</span>, <span class="py-src-variable">f</span>.<span class="py-src-variable">getIRCBot</span>(<span class="py-src-string">'fingerbot'</span>)
305
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
306
</pre><div class="caption">Source listing - <a href="listings/finger/finger18.tac"><span class="filename">listings/finger/finger18.tac</span></a></div></div>
310
<p><a href="../index.html">Index</a></p>
311
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'