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: adding features to the finger service</title>
4
<link href="../stylesheet.css" rel="stylesheet" type="text/css"/>
8
<h1 class="title">The Evolution of Finger: adding features to the finger service</h1>
9
<div class="toc"><ol><li><a href="#auto0">Introduction</a></li><li><a href="#auto1">Setting Message By Local Users</a></li><li><a href="#auto2">Use Services to Make Dependencies Sane</a></li><li><a href="#auto3">Read Status File</a></li><li><a href="#auto4">Announce on Web, Too</a></li><li><a href="#auto5">Announce on IRC, Too</a></li><li><a href="#auto6">Add XML-RPC Support</a></li></ol></div>
14
<h2>Introduction<a name="auto0"/></h2>
16
<p> This is the second 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, our finger server will continue to sprout
19
features: the ability for users to set finger announces, and using our finger
20
service to send those announcements on the web, on IRC and over XML-RPC.
21
Resources and XML-RPC are introduced in the Web Applications portion of
22
the <a href="../../../web/howto/index.html" shape="rect">Twisted Web howto</a>. More examples
23
using <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.words.protocols.irc.html" title="twisted.words.protocols.irc">twisted.words.protocols.irc</a></code> can be found
24
in <a href="../clients.html" shape="rect">Writing a TCP Client</a> and
25
the <a href="../../../words/examples/index.html" shape="rect">Twisted Words examples</a>.</p>
27
<h2>Setting Message By Local Users<a name="auto1"/></h2>
29
<p>Now that port 1079 is free, maybe we can use it with a different
30
server, one which will let people set their messages. It does
31
no access control, so anyone who can login to the machine can
32
set any message. We assume this is the desired behavior in
33
our case. Testing it can be done by simply:
36
<pre class="shell" xml:space="preserve">
37
% nc localhost 1079 # or telnet localhost 1079
39
Giving a tutorial now, sorry!
43
<div class="py-listing"><pre><p class="py-linenumber"> 1
98
</p><span class="py-src-comment"># But let's try and fix setting away messages, shall we?</span>
99
<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>
100
<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>
101
<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>
103
<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>):
104
<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>):
105
<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>)
107
<span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>):
108
<span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span>
109
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>)
111
<span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</span>):
112
<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">message</span> + <span class="py-src-string">'\r\n'</span>)
113
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
114
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</span>)
116
<span class="py-src-keyword">class</span> <span class="py-src-identifier">FingerFactory</span>(<span class="py-src-parameter">protocol</span>.<span class="py-src-parameter">ServerFactory</span>):
117
<span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerProtocol</span>
119
<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">kwargs</span>):
120
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = <span class="py-src-variable">kwargs</span>
122
<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>):
123
<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>))
125
<span class="py-src-keyword">class</span> <span class="py-src-identifier">FingerSetterProtocol</span>(<span class="py-src-parameter">basic</span>.<span class="py-src-parameter">LineReceiver</span>):
126
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
127
<span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span> = []
129
<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">line</span>):
130
<span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span>.<span class="py-src-variable">append</span>(<span class="py-src-variable">line</span>)
132
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionLost</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">reason</span>):
133
<span class="py-src-variable">user</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span>[<span class="py-src-number">0</span>]
134
<span class="py-src-variable">status</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span>[<span class="py-src-number">1</span>]
135
<span class="py-src-variable">self</span>.<span class="py-src-variable">factory</span>.<span class="py-src-variable">setUser</span>(<span class="py-src-variable">user</span>, <span class="py-src-variable">status</span>)
137
<span class="py-src-keyword">class</span> <span class="py-src-identifier">FingerSetterFactory</span>(<span class="py-src-parameter">protocol</span>.<span class="py-src-parameter">ServerFactory</span>):
138
<span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerSetterProtocol</span>
140
<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">fingerFactory</span>):
141
<span class="py-src-variable">self</span>.<span class="py-src-variable">fingerFactory</span> = <span class="py-src-variable">fingerFactory</span>
143
<span class="py-src-keyword">def</span> <span class="py-src-identifier">setUser</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">user</span>, <span class="py-src-parameter">status</span>):
144
<span class="py-src-variable">self</span>.<span class="py-src-variable">fingerFactory</span>.<span class="py-src-variable">users</span>[<span class="py-src-variable">user</span>] = <span class="py-src-variable">status</span>
146
<span class="py-src-variable">ff</span> = <span class="py-src-variable">FingerFactory</span>(<span class="py-src-variable">moshez</span>=<span class="py-src-string">'Happy and well'</span>)
147
<span class="py-src-variable">fsf</span> = <span class="py-src-variable">FingerSetterFactory</span>(<span class="py-src-variable">ff</span>)
149
<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>)
150
<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>)
151
<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">ff</span>).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
152
<span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">1079</span>,<span class="py-src-variable">fsf</span>).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
153
</pre><div class="caption">Source listing - <a href="listings/finger/finger12.tac"><span class="filename">listings/finger/finger12.tac</span></a></div></div>
155
<p>This program has two protocol-factory-TCPServer pairs, which are both child
156
services of the application. Specifically, the
157
<code base="API" class="twisted.application.service.Service">setServiceParent</code>
158
method is used to define the two TCPServer services as children of
159
<code>application</code>, which implements
160
<code base="API" class="twisted.application.servce">IServiceCollection</code>.
161
Both services are thus started with the application.</p>
163
<h2>Use Services to Make Dependencies Sane<a name="auto2"/></h2>
165
<p>The previous version had the setter poke at the innards of the
166
finger factory. This strategy is usually not a good idea: this version makes
167
both factories symmetric by making them both look at a single
168
object. Services are useful for when an object is needed which is
169
not related to a specific network server. Here, we define a common service
170
class with methods that will create factories on the fly. The service
171
also contains methods the factories will depend on.</p>
173
<p>The factory-creation methods, <code>getFingerFactory</code> and
174
<code>getFingerSetterFactory</code>, follow this pattern:</p>
178
<li>Instantiate a generic server factory,
179
<code>twisted.internet.protocol.ServerFactory</code>.</li>
181
<li>Set the protocol class, just like our factory class would have.</li>
183
<li>Copy a service method to the factory as a function attribute. The
184
function won't have access to the factory's <code>self</code>, but that's OK
185
because as a bound method it has access to the service's <code>self</code>,
186
which is what it needs. For <code>getUser</code>, a custom method defined in
187
the service gets copied. For <code>setUser</code>, a standard method of the
188
<code>users</code> dictionary is copied.</li>
192
<p>Thus, we stopped subclassing: the service simply puts useful methods and
193
attributes inside the factories. We are getting better at protocol design:
194
none of our protocol classes had to be changed, and neither will have to
195
change until the end of the tutorial.</p>
198
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.application.service.service.html" title="twisted.application.service.service">service</a></code> , this new
199
finger service implements the
200
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.application.service.IService.html" title="twisted.application.service.IService">IService</a></code> interface
201
and can be started and stopped in a standardized manner. We'll make use of
202
this in the next example.</p>
204
<div class="py-listing"><pre><p class="py-linenumber"> 1
263
</p><span class="py-src-comment"># Fix asymmetry</span>
264
<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>
265
<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>
266
<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>
268
<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>):
269
<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>):
270
<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>)
272
<span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>):
273
<span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span>
274
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>)
276
<span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</span>):
277
<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">message</span> + <span class="py-src-string">'\r\n'</span>)
278
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
279
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</span>)
281
<span class="py-src-keyword">class</span> <span class="py-src-identifier">FingerSetterProtocol</span>(<span class="py-src-parameter">basic</span>.<span class="py-src-parameter">LineReceiver</span>):
282
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
283
<span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span> = []
285
<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">line</span>):
286
<span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span>.<span class="py-src-variable">append</span>(<span class="py-src-variable">line</span>)
288
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionLost</span>(<span class="py-src-parameter">self</span>,<span class="py-src-parameter">reason</span>):
289
<span class="py-src-variable">user</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span>[<span class="py-src-number">0</span>]
290
<span class="py-src-variable">status</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span>[<span class="py-src-number">1</span>]
291
<span class="py-src-variable">self</span>.<span class="py-src-variable">factory</span>.<span class="py-src-variable">setUser</span>(<span class="py-src-variable">user</span>, <span class="py-src-variable">status</span>)
293
<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>):
294
<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">kwargs</span>):
295
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = <span class="py-src-variable">kwargs</span>
297
<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>):
298
<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>))
300
<span class="py-src-keyword">def</span> <span class="py-src-identifier">setUser</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">user</span>, <span class="py-src-parameter">status</span>):
301
<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>
303
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
304
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
305
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerProtocol</span>
306
<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>
307
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
309
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerSetterFactory</span>(<span class="py-src-parameter">self</span>):
310
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
311
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerSetterProtocol</span>
312
<span class="py-src-variable">f</span>.<span class="py-src-variable">setUser</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">setUser</span>
313
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
315
<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>)
316
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-variable">moshez</span>=<span class="py-src-string">'Happy and well'</span>)
317
<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>)
318
<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>()
319
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
320
<span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">1079</span>,<span class="py-src-variable">f</span>.<span class="py-src-variable">getFingerSetterFactory</span>()
321
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
322
</pre><div class="caption">Source listing - <a href="listings/finger/finger13.tac"><span class="filename">listings/finger/finger13.tac</span></a></div></div>
326
<h2>Read Status File<a name="auto3"/></h2>
328
<p>This version shows how, instead of just letting users set their
329
messages, we can read those from a centrally managed file. We cache
330
results, and every 30 seconds we refresh it. Services are useful
331
for such scheduled tasks.</p>
333
<div class="listing"><pre>
334
moshez: happy and well
336
</pre><div class="caption">sample /etc/users file - <a href="listings/finger/etc.users"><span class="filename">listings/finger/etc.users</span></a></div></div>
338
<div class="py-listing"><pre><p class="py-linenumber"> 1
393
</p><span class="py-src-comment"># Read from file</span>
394
<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>
395
<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>
396
<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>
398
<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>):
399
<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>):
400
<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>)
402
<span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>):
403
<span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span>
404
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>)
406
<span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</span>):
407
<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">message</span> + <span class="py-src-string">'\r\n'</span>)
408
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
409
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</span>)
411
<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>):
412
<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>):
413
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = {}
414
<span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span> = <span class="py-src-variable">filename</span>
415
<span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
417
<span class="py-src-keyword">def</span> <span class="py-src-identifier">_read</span>(<span class="py-src-parameter">self</span>):
418
<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>):
419
<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>)
420
<span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">strip</span>()
421
<span class="py-src-variable">status</span> = <span class="py-src-variable">status</span>.<span class="py-src-variable">strip</span>()
422
<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>
423
<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>)
425
<span class="py-src-keyword">def</span> <span class="py-src-identifier">startService</span>(<span class="py-src-parameter">self</span>):
426
<span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
427
<span class="py-src-variable">service</span>.<span class="py-src-variable">Service</span>.<span class="py-src-variable">startService</span>(<span class="py-src-variable">self</span>)
429
<span class="py-src-keyword">def</span> <span class="py-src-identifier">stopService</span>(<span class="py-src-parameter">self</span>):
430
<span class="py-src-variable">service</span>.<span class="py-src-variable">Service</span>.<span class="py-src-variable">stopService</span>(<span class="py-src-variable">self</span>)
431
<span class="py-src-variable">self</span>.<span class="py-src-variable">call</span>.<span class="py-src-variable">cancel</span>()
433
<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>):
434
<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>))
436
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
437
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
438
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerProtocol</span>
439
<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>
440
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
442
<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>)
443
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
444
<span class="py-src-variable">finger</span> = <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>())
446
<span class="py-src-variable">finger</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>))
447
<span class="py-src-variable">f</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">service</span>.<span class="py-src-variable">IServiceCollection</span>(<span class="py-src-variable">application</span>))
448
</pre><div class="caption">Source listing - <a href="listings/finger/finger14.tac"><span class="filename">listings/finger/finger14.tac</span></a></div></div>
450
<p>Since this verison is reading data from a file (and refreshing the data
451
every 30 seconds), there is no <code>FingerSetterFactory</code> and thus
452
nothing listening on port 1079.</p>
454
<p>Here we override the standard
455
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.application.service.Service.startService.html" title="twisted.application.service.Service.startService">startService</a></code>
457
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.application.service.Service.stopService.html" title="twisted.application.service.Service.stopService">stopService</a></code>
458
hooks in the Finger service, which is set up as a child service of
459
the application in the last line of the code. <code>startService</code> calls
460
<code>_read</code>, the function responsible for reading the data;
461
<code>reactor.callLater</code> is then used to schedule it to run again after
462
thirty seconds every time it is called. <code>reactor.callLater</code> returns
463
an object that lets us cancel the scheduled run in <code>stopService</code>
464
using its <code>cancel</code> method.</p>
466
<h2>Announce on Web, Too<a name="auto4"/></h2>
468
<p>The same kind of service can also produce things useful for
469
other protocols. For example, in twisted.web, the factory
470
itself (<code base="API" class="twisted.web.server">Site</code>) is almost
471
never subclassed — instead, it is given a resource, which represents the tree
472
of resources available via URLs. That hierarchy is navigated by
473
<code base="API" class="twisted.web.server">Site</code>
474
and overriding it dynamically is possible with
475
<code base="API" class="twisted.web.resource.Resource">getChild</code>.</p>
477
<p>To integrate this into the Finger application (just because we can), we set
478
up a new TCPServer that calls the <code base="API" class="twisted.web.server">Site</code> factory and retrieves resources via a
479
new function of <code>FingerService</code> named <code>getResource</code>.
480
This function specifically returns a <code base="API" class="twisted.web.resource">Resource</code> object with an overridden <code base="API" class="twisted.web.resource.Resource">getChild</code> method.</p>
482
<div class="py-listing"><pre><p class="py-linenumber"> 1
558
</p><span class="py-src-comment"># Read from file, announce on the web!</span>
559
<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>
560
<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>
561
<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>
562
<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>
563
<span class="py-src-keyword">import</span> <span class="py-src-variable">cgi</span>
565
<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>):
566
<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>):
567
<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>)
569
<span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>):
570
<span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span>
571
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>)
573
<span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</span>):
574
<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">message</span> + <span class="py-src-string">'\r\n'</span>)
575
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
576
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</span>)
578
<span class="py-src-keyword">class</span> <span class="py-src-identifier">FingerResource</span>(<span class="py-src-parameter">resource</span>.<span class="py-src-parameter">Resource</span>):
580
<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">users</span>):
581
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = <span class="py-src-variable">users</span>
582
<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>)
584
<span class="py-src-comment"># we treat the path as the username</span>
585
<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">username</span>, <span class="py-src-parameter">request</span>):
586
<span class="py-src-string">"""
587
'username' is a string.
588
'request' is a 'twisted.web.server.Request'.
589
"""</span>
590
<span class="py-src-variable">messagevalue</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">username</span>)
591
<span class="py-src-variable">username</span> = <span class="py-src-variable">cgi</span>.<span class="py-src-variable">escape</span>(<span class="py-src-variable">username</span>)
592
<span class="py-src-keyword">if</span> <span class="py-src-variable">messagevalue</span> <span class="py-src-keyword">is</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">None</span>:
593
<span class="py-src-variable">messagevalue</span> = <span class="py-src-variable">cgi</span>.<span class="py-src-variable">escape</span>(<span class="py-src-variable">messagevalue</span>)
594
<span class="py-src-variable">text</span> = <span class="py-src-string">'<h1>%s</h1><p>%s</p>'</span> % (<span class="py-src-variable">username</span>,<span class="py-src-variable">messagevalue</span>)
595
<span class="py-src-keyword">else</span>:
596
<span class="py-src-variable">text</span> = <span class="py-src-string">'<h1>%s</h1><p>No such user</p>'</span> % <span class="py-src-variable">username</span>
597
<span class="py-src-keyword">return</span> <span class="py-src-variable">static</span>.<span class="py-src-variable">Data</span>(<span class="py-src-variable">text</span>, <span class="py-src-string">'text/html'</span>)
599
<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>):
600
<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>):
601
<span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span> = <span class="py-src-variable">filename</span>
602
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = {}
603
<span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
605
<span class="py-src-keyword">def</span> <span class="py-src-identifier">_read</span>(<span class="py-src-parameter">self</span>):
606
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>.<span class="py-src-variable">clear</span>()
607
<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>):
608
<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>)
609
<span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">strip</span>()
610
<span class="py-src-variable">status</span> = <span class="py-src-variable">status</span>.<span class="py-src-variable">strip</span>()
611
<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>
612
<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>)
614
<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>):
615
<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>))
617
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
618
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
619
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerProtocol</span>
620
<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>
621
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
623
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getResource</span>(<span class="py-src-parameter">self</span>):
624
<span class="py-src-variable">r</span> = <span class="py-src-variable">FingerResource</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>)
625
<span class="py-src-keyword">return</span> <span class="py-src-variable">r</span>
627
<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>)
628
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
629
<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>)
630
<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>()
631
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
632
<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>())
633
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
634
</pre><div class="caption">Source listing - <a href="listings/finger/finger15.tac"><span class="filename">listings/finger/finger15.tac</span></a></div></div>
637
<h2>Announce on IRC, Too<a name="auto5"/></h2>
639
<p>This is the first time there is client code. IRC clients often
640
act a lot like servers: responding to events from the network.
641
The reconnecting client factory will make sure that severed links
642
will get re-established, with intelligent tweaked exponential
643
back-off algorithms. The IRC client itself is simple: the only
644
real hack is getting the nickname from the factory in connectionMade.</p>
646
<div class="py-listing"><pre><p class="py-linenumber"> 1
737
</p><span class="py-src-comment"># Read from file, announce on the web, irc</span>
738
<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>
739
<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>
740
<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>
741
<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>
742
<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>
744
<span class="py-src-keyword">import</span> <span class="py-src-variable">cgi</span>
746
<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>):
747
<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>):
748
<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>)
750
<span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>):
751
<span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span>
752
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>)
754
<span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</span>):
755
<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">message</span> + <span class="py-src-string">'\r\n'</span>)
756
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
757
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</span>)
760
<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>):
761
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
762
<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>
763
<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>)
765
<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>):
766
<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>]
767
<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>():
768
<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>)
770
<span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>):
771
<span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span>
772
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>)
774
<span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</span>):
775
<span class="py-src-variable">irc</span>.<span class="py-src-variable">IRCClient</span>.<span class="py-src-variable">msg</span>(<span class="py-src-variable">self</span>, <span class="py-src-variable">user</span>, <span class="py-src-variable">msg</span>+<span class="py-src-string">': '</span>+<span class="py-src-variable">message</span>)
776
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</span>)
778
<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>):
779
<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>):
780
<span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span> = <span class="py-src-variable">filename</span>
781
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = {}
782
<span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
784
<span class="py-src-keyword">def</span> <span class="py-src-identifier">_read</span>(<span class="py-src-parameter">self</span>):
785
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>.<span class="py-src-variable">clear</span>()
786
<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>):
787
<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>)
788
<span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">strip</span>()
789
<span class="py-src-variable">status</span> = <span class="py-src-variable">status</span>.<span class="py-src-variable">strip</span>()
790
<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>
791
<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>)
793
<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>):
794
<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>))
796
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
797
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
798
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerProtocol</span>
799
<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>
800
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
802
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getResource</span>(<span class="py-src-parameter">self</span>):
803
<span class="py-src-variable">r</span> = <span class="py-src-variable">resource</span>.<span class="py-src-variable">Resource</span>()
804
<span class="py-src-variable">r</span>.<span class="py-src-variable">getChild</span> = (<span class="py-src-keyword">lambda</span> <span class="py-src-variable">path</span>, <span class="py-src-variable">request</span>:
805
<span class="py-src-variable">static</span>.<span class="py-src-variable">Data</span>(<span class="py-src-string">'<h1>%s</h1><p>%s</p>'</span> %
806
<span class="py-src-variable">tuple</span>(<span class="py-src-variable">map</span>(<span class="py-src-variable">cgi</span>.<span class="py-src-variable">escape</span>,
807
[<span class="py-src-variable">path</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">path</span>,
808
<span class="py-src-string">"No such user <p/> usage: site/user"</span>)])),
809
<span class="py-src-string">'text/html'</span>))
810
<span class="py-src-keyword">return</span> <span class="py-src-variable">r</span>
812
<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>):
813
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ReconnectingClientFactory</span>()
814
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">IRCReplyBot</span>
815
<span class="py-src-variable">f</span>.<span class="py-src-variable">nickname</span> = <span class="py-src-variable">nickname</span>
816
<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>
817
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
819
<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>)
820
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
821
<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>)
822
<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>()
823
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
824
<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>())
825
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
826
<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>)
827
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
828
</pre><div class="caption">Source listing - <a href="listings/finger/finger16.tac"><span class="filename">listings/finger/finger16.tac</span></a></div></div>
830
<p><code>FingerService</code> now has another new function,
831
<code>getIRCbot</code>, which returns the
832
<code>ReconnectingClientFactory</code>. This factory in turn will instantiate
833
the <code>IRCReplyBot</code> protocol. The IRCBot is configured in the last
834
line to connect to <code>irc.freenode.org</code> with a nickname of
835
<code>fingerbot</code>.</p>
837
<p>By overriding <code>irc.IRCClient.connectionMade</code>,
838
<code>IRCReplyBot</code> can access the <code>nickname</code> attribute of the
839
factory that instantiated it.</p>
841
<h2>Add XML-RPC Support<a name="auto6"/></h2>
843
<p>In Twisted, XML-RPC support is handled just as though it was
844
another resource. That resource will still support GET calls normally
845
through render(), but that is usually left unimplemented. Note
846
that it is possible to return deferreds from XML-RPC methods.
847
The client, of course, will not get the answer until the deferred
850
<div class="py-listing"><pre><p class="py-linenumber"> 1
941
</p><span class="py-src-comment"># Read from file, announce on the web, irc, xml-rpc</span>
942
<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>
943
<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>
944
<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>
945
<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>
946
<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>
947
<span class="py-src-keyword">import</span> <span class="py-src-variable">cgi</span>
949
<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>):
950
<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>):
951
<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>)
953
<span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>):
954
<span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span>
955
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>)
957
<span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</span>):
958
<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">message</span> + <span class="py-src-string">'\r\n'</span>)
959
<span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
960
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</span>)
962
<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>):
963
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
964
<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>
965
<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>)
967
<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>):
968
<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>]
969
<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>():
970
<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>)
972
<span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>):
973
<span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span>
974
<span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>)
976
<span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</span>):
977
<span class="py-src-variable">irc</span>.<span class="py-src-variable">IRCClient</span>.<span class="py-src-variable">msg</span>(<span class="py-src-variable">self</span>, <span class="py-src-variable">user</span>, <span class="py-src-variable">msg</span>+<span class="py-src-string">': '</span>+<span class="py-src-variable">message</span>)
978
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</span>)
980
<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>):
981
<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>):
982
<span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span> = <span class="py-src-variable">filename</span>
983
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = {}
984
<span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
986
<span class="py-src-keyword">def</span> <span class="py-src-identifier">_read</span>(<span class="py-src-parameter">self</span>):
987
<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>.<span class="py-src-variable">clear</span>()
988
<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>):
989
<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>)
990
<span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">strip</span>()
991
<span class="py-src-variable">status</span> = <span class="py-src-variable">status</span>.<span class="py-src-variable">strip</span>()
992
<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>
993
<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>)
995
<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>):
996
<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>))
998
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
999
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
1000
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerProtocol</span>
1001
<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>
1002
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
1004
<span class="py-src-keyword">def</span> <span class="py-src-identifier">getResource</span>(<span class="py-src-parameter">self</span>):
1005
<span class="py-src-variable">r</span> = <span class="py-src-variable">resource</span>.<span class="py-src-variable">Resource</span>()
1006
<span class="py-src-variable">r</span>.<span class="py-src-variable">getChild</span> = (<span class="py-src-keyword">lambda</span> <span class="py-src-variable">path</span>, <span class="py-src-variable">request</span>:
1007
<span class="py-src-variable">static</span>.<span class="py-src-variable">Data</span>(<span class="py-src-string">'<h1>%s</h1><p>%s</p>'</span> %
1008
<span class="py-src-variable">tuple</span>(<span class="py-src-variable">map</span>(<span class="py-src-variable">cgi</span>.<span class="py-src-variable">escape</span>,
1009
[<span class="py-src-variable">path</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">path</span>, <span class="py-src-string">"No such user"</span>)])),
1010
<span class="py-src-string">'text/html'</span>))
1011
<span class="py-src-variable">x</span> = <span class="py-src-variable">xmlrpc</span>.<span class="py-src-variable">XMLRPC</span>()
1012
<span class="py-src-variable">x</span>.<span class="py-src-variable">xmlrpc_getUser</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
1013
<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>)
1014
<span class="py-src-keyword">return</span> <span class="py-src-variable">r</span>
1016
<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>):
1017
<span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ReconnectingClientFactory</span>()
1018
<span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">IRCReplyBot</span>
1019
<span class="py-src-variable">f</span>.<span class="py-src-variable">nickname</span> = <span class="py-src-variable">nickname</span>
1020
<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>
1021
<span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
1023
<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>)
1024
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
1025
<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>)
1026
<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>()
1027
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
1028
<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>())
1029
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
1030
<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>)
1031
).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
1032
</pre><div class="caption">Source listing - <a href="listings/finger/finger17.tac"><span class="filename">listings/finger/finger17.tac</span></a></div></div>
1034
<p>Instead of a web browser, we can test the XMLRPC finger using a simple
1035
client based on Python's built-in <code>xmlrpclib</code>, which will access
1036
the resource we've made available at <code>localhost/RPC2</code>.</p>
1038
<div class="py-listing"><pre><p class="py-linenumber">1
1043
</p><span class="py-src-comment"># testing xmlrpc finger</span>
1045
<span class="py-src-keyword">import</span> <span class="py-src-variable">xmlrpclib</span>
1046
<span class="py-src-variable">server</span> = <span class="py-src-variable">xmlrpclib</span>.<span class="py-src-variable">Server</span>(<span class="py-src-string">'http://127.0.0.1:8000/RPC2'</span>)
1047
<span class="py-src-keyword">print</span> <span class="py-src-variable">server</span>.<span class="py-src-variable">getUser</span>(<span class="py-src-string">'moshez'</span>)
1048
</pre><div class="caption">Source listing - <a href="listings/finger/fingerXRclient.py"><span class="filename">listings/finger/fingerXRclient.py</span></a></div></div>
1052
<p><a href="../index.html">Index</a></p>
1053
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'