Sophie

Sophie

distrib > Mandriva > 2008.1 > x86_64 > media > main-release > by-pkgid > db93d7191b12a3d5ce887da46fc79bf1 > files > 258

python-twisted-core-doc-2.5.0-3mdv2008.1.x86_64.rpm

<?xml version="1.0"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>Twisted Documentation: The Evolution of Finger: adding features to the finger service</title><link href="../../howto/stylesheet.css" type="text/css" rel="stylesheet" /></head><body bgcolor="white"><h1 class="title">The Evolution of Finger: adding features to the finger service</h1><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><div class="content"><span></span><h2>Introduction<a name="auto0"></a></h2><p> This is the second part of the Twisted tutorial <a href="index.html">Twisted from Scratch, or The Evolution of Finger</a>.</p><p>In this section of the tutorial, our finger server will continue to sprout
features: the ability for users to set finger announces, and using our finger
service to send those announcements on the web, on IRC and over XML-RPC.</p><h2>Setting Message By Local Users<a name="auto1"></a></h2><p>Now that port 1079 is free, maybe we can run on it a different
server, one which will let people set their messages. It does
no access control, so anyone who can login to the machine can
set any message. We assume this is the desired behavior in
our case. Testing it can be done by simply:
</p><pre class="shell">
% nc localhost 1079   # or telnet localhost 1079
moshez
Giving a tutorial now, sorry!
^D
</pre><div class="py-listing"><pre>
<span class="py-src-comment"># But let's try and fix setting away messages, shall we?
</span><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>
<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>
<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>
<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>):
    <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>):
        <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>
        ).<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-string">&quot;Internal error in server&quot;</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">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">m</span>+<span class="py-src-string">&quot;\r\n&quot;</span>),
                       <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()))

<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>):
    <span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerProtocol</span>
    <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>): <span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = <span class="py-src-variable">kwargs</span>
    <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>):
        <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">&quot;No such user&quot;</span>))

<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>):
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>): <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span> = []
    <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>): <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>)
    <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>):
        <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">self</span>.<span class="py-src-variable">lines</span>[:<span class="py-src-number">2</span>])
        <span class="py-src-comment"># first line: user    second line: status
</span>
<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>):
    <span class="py-src-variable">protocol</span> = <span class="py-src-variable">FingerSetterProtocol</span>
    <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">ff</span>): <span class="py-src-variable">self</span>.<span class="py-src-variable">setUser</span> = <span class="py-src-variable">ff</span>.<span class="py-src-variable">users</span>.<span class="py-src-variable">__setitem__</span>

<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>)
<span class="py-src-variable">fsf</span> = <span class="py-src-variable">FingerSetterFactory</span>(<span class="py-src-variable">ff</span>)

<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>)
<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>)
<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>)
<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>)
</pre><div class="caption">Source listing - <a href="listings/finger/finger12.py"><span class="filename">listings/finger/finger12.py</span></a></div></div><h2>Use Services to Make Dependencies Sane<a name="auto2"></a></h2><p>The previous version had the setter poke at the innards of the
finger factory. It's usually not a good idea: this version makes
both factories symmetric by making them both look at a single
object. Services are useful for when an object is needed which is
not related to a specific network server. Here, we moved all responsibility
for manufacturing factories into the service. Note that we stopped
subclassing: the service simply puts useful methods and attributes
inside the factories. We are getting better at protocol design:
none of our protocol classes had to be changed, and neither will
have to change until the end of the tutorial.</p><div class="py-listing"><pre>
<span class="py-src-comment"># Fix asymmetry
</span><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>
<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>
<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>
<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>):
    <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>):
        <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>
        ).<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-string">&quot;Internal error in server&quot;</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">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">m</span>+<span class="py-src-string">&quot;\r\n&quot;</span>),
                       <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()))

<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>):
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>): <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span> = []
    <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>): <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>)
    <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>): <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">self</span>.<span class="py-src-variable">lines</span>[:<span class="py-src-number">2</span>])
    <span class="py-src-comment"># first line: user   second line: status
</span>
<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>):
    <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">args</span>, **<span class="py-src-parameter">kwargs</span>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">parent</span>.<span class="py-src-variable">__init__</span>(<span class="py-src-variable">self</span>, *<span class="py-src-variable">args</span>)
        <span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = <span class="py-src-variable">kwargs</span>
    <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>):
        <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">&quot;No such user&quot;</span>))
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
        <span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span>, <span class="py-src-variable">f</span>.<span class="py-src-variable">getUser</span> = <span class="py-src-variable">FingerProtocol</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
        <span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerSetterFactory</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
        <span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span>, <span class="py-src-variable">f</span>.<span class="py-src-variable">setUser</span> = <span class="py-src-variable">FingerSetterProtocol</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>.<span class="py-src-variable">__setitem__</span>
        <span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>

<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>)
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'finger'</span>, <span class="py-src-variable">moshez</span>=<span class="py-src-string">'Happy and well'</span>)
<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>)
<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>()
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
<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>()
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
</pre><div class="caption">Source listing - <a href="listings/finger/finger13.py"><span class="filename">listings/finger/finger13.py</span></a></div></div><h2>Read Status File<a name="auto3"></a></h2><p>This version shows how, instead of just letting users set their
messages, we can read those from a centrally managed file. We cache
results, and every 30 seconds we refresh it. Services are useful
for such scheduled tasks.</p><div class="listing"><pre>
moshez: happy and well
shawn: alive 
</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><div class="py-listing"><pre>
<span class="py-src-comment"># Read from file
</span><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>
<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>
<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>

<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>):
    <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>):
        <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>
        ).<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-string">&quot;Internal error in server&quot;</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">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">m</span>+<span class="py-src-string">&quot;\r\n&quot;</span>),
                       <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()))

<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>):
    <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>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = {}
        <span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span> = <span class="py-src-variable">filename</span>
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">_read</span>(<span class="py-src-parameter">self</span>):
        <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>):
            <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>)
            <span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">strip</span>()
            <span class="py-src-variable">status</span> = <span class="py-src-variable">status</span>.<span class="py-src-variable">strip</span>()
            <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>
        <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>)
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">startService</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
        <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>)
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">stopService</span>(<span class="py-src-parameter">self</span>):
        <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>)
        <span class="py-src-variable">self</span>.<span class="py-src-variable">call</span>.<span class="py-src-variable">cancel</span>()
    <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>):
        <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">&quot;No such user&quot;</span>))
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
        <span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span>, <span class="py-src-variable">f</span>.<span class="py-src-variable">getUser</span> = <span class="py-src-variable">FingerProtocol</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
        <span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>

<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>)
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
<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>())

<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>))
<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>))
</pre><div class="caption">Source listing - <a href="listings/finger/finger14.py"><span class="filename">listings/finger/finger14.py</span></a></div></div><h2>Announce on Web, Too<a name="auto4"></a></h2><p>The same kind of service can also produce things useful for
other protocols. For example, in twisted.web, the factory
itself (the site) is almost never subclassed -- instead,
it is given a resource, which represents the tree of resources
available via URLs. That hierarchy is navigated by site,
and overriding it dynamically is possible with getChild.</p><div class="py-listing"><pre>
<span class="py-src-comment"># Read from file, announce on the web!
</span><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>
<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>
<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>
<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-keyword">import</span> <span class="py-src-variable">cgi</span>

<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>):
    <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>):
        <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>
        ).<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-string">&quot;Internal error in server&quot;</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">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">m</span>+<span class="py-src-string">&quot;\r\n&quot;</span>),
                       <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()))

<span class="py-src-keyword">class</span> <span class="py-src-identifier">MotdResource</span>(<span class="py-src-parameter">resource</span>.<span class="py-src-parameter">Resource</span>):

    <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>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = <span class="py-src-variable">users</span>
        <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>)

    <span class="py-src-comment"># we treat the path as the username
</span>    <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>):
        <span class="py-src-variable">motd</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>)
        <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>)
        <span class="py-src-keyword">if</span> <span class="py-src-variable">motd</span> <span class="py-src-keyword">is</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">None</span>:
            <span class="py-src-variable">motd</span> = <span class="py-src-variable">cgi</span>.<span class="py-src-variable">escape</span>(<span class="py-src-variable">motd</span>)
            <span class="py-src-variable">text</span> = <span class="py-src-string">'&lt;h1&gt;%s&lt;/h1&gt;&lt;p&gt;%s&lt;/p&gt;'</span> % (<span class="py-src-variable">username</span>,<span class="py-src-variable">motd</span>)
        <span class="py-src-keyword">else</span>:
            <span class="py-src-variable">text</span> = <span class="py-src-string">'&lt;h1&gt;%s&lt;/h1&gt;&lt;p&gt;No such user&lt;/p&gt;'</span> % <span class="py-src-variable">username</span>
        <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>)

<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>):
    <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>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span> = <span class="py-src-variable">filename</span>
        <span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">_read</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = {}
        <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>):
            <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>)
            <span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">strip</span>()
            <span class="py-src-variable">status</span> = <span class="py-src-variable">status</span>.<span class="py-src-variable">strip</span>()
            <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>
        <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>)
    <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>):
        <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">&quot;No such user&quot;</span>))
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
        <span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span>, <span class="py-src-variable">f</span>.<span class="py-src-variable">getUser</span> = <span class="py-src-variable">FingerProtocol</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
        <span class="py-src-variable">f</span>.<span class="py-src-variable">startService</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">startService</span>
        <span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>

    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getResource</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">r</span> = <span class="py-src-variable">MotdResource</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">users</span>)
        <span class="py-src-keyword">return</span> <span class="py-src-variable">r</span>

<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>)
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
<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>)
<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>()
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
<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>())
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
</pre><div class="caption">Source listing - <a href="listings/finger/finger15.py"><span class="filename">listings/finger/finger15.py</span></a></div></div><h2>Announce on IRC, Too<a name="auto5"></a></h2><p>This is the first time there is client code. IRC clients often
act a lot like servers: responding to events from the network.
The reconnecting client factory will make sure that severed links
will get re-established, with intelligent tweaked exponential
back-off algorithms. The IRC client itself is simple: the only
real hack is getting the nickname from the factory in connectionMade.</p><div class="py-listing"><pre>
<span class="py-src-comment"># Read from file, announce on the web, irc
</span><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>
<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>
<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>
<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>
<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-keyword">import</span> <span class="py-src-variable">cgi</span>
<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>):
    <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>):
        <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>
        ).<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-string">&quot;Internal error in server&quot;</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">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">m</span>+<span class="py-src-string">&quot;\r\n&quot;</span>),
                       <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()))
<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>):
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>): <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span> = []
    <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>): <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>)
    <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>): <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">self</span>.<span class="py-src-variable">lines</span>[:<span class="py-src-number">2</span>])
<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>):
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
        <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>
        <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>)
    <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>):
        <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>]
        <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>():
            <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>
            ).<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-string">&quot;Internal error in server&quot;</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">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">m</span>))

<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>):
    <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>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span> = <span class="py-src-variable">filename</span>
        <span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">_read</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = {}
        <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>):
            <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>)
            <span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">strip</span>()
            <span class="py-src-variable">status</span> = <span class="py-src-variable">status</span>.<span class="py-src-variable">strip</span>()
            <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>
        <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>)
    <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>):
        <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">&quot;No such user&quot;</span>))
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
        <span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span>, <span class="py-src-variable">f</span>.<span class="py-src-variable">getUser</span> = <span class="py-src-variable">FingerProtocol</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
        <span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getResource</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">r</span> = <span class="py-src-variable">resource</span>.<span class="py-src-variable">Resource</span>()
        <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>:
                      <span class="py-src-variable">static</span>.<span class="py-src-variable">Data</span>(<span class="py-src-string">'&lt;h1&gt;%s&lt;/h1&gt;&lt;p&gt;%s&lt;/p&gt;'</span> %
                      <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>,
                      [<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">&quot;No such user &lt;p/&gt; usage: site/user&quot;</span>)])),
                      <span class="py-src-string">'text/html'</span>))
        <span class="py-src-keyword">return</span> <span class="py-src-variable">r</span>

    <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>):
        <span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ReconnectingClientFactory</span>()
        <span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span>,<span class="py-src-variable">f</span>.<span class="py-src-variable">nickname</span>,<span class="py-src-variable">f</span>.<span class="py-src-variable">getUser</span> = <span class="py-src-variable">IRCReplyBot</span>,<span class="py-src-variable">nickname</span>,<span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
        <span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>

<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>)
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
<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>)
<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>()
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
<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>())
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
<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>)
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
</pre><div class="caption">Source listing - <a href="listings/finger/finger16.py"><span class="filename">listings/finger/finger16.py</span></a></div></div><h2>Add XML-RPC Support<a name="auto6"></a></h2><p>In Twisted, XML-RPC support is handled just as though it was
another resource. That resource will still support GET calls normally
through render(), but that is usually left unimplemented. Note
that it is possible to return deferreds from XML-RPC methods.
The client, of course, will not get the answer until the deferred
is triggered.</p><div class="py-listing"><pre>
<span class="py-src-comment"># Read from file, announce on the web, irc, xml-rpc
</span><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>
<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>
<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>
<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>
<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>
<span class="py-src-keyword">import</span> <span class="py-src-variable">cgi</span>
<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>):
    <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>):
        <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>
        ).<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-string">&quot;Internal error in server&quot;</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">transport</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">m</span>+<span class="py-src-string">&quot;\r\n&quot;</span>),
                       <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()))
<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>):
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>): <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span> = []
    <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>): <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>)
    <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>): <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">self</span>.<span class="py-src-variable">lines</span>[:<span class="py-src-number">2</span>])
<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>):
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionMade</span>(<span class="py-src-parameter">self</span>):
        <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>
        <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>)
    <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>):
        <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>]
        <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>():
            <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>
            ).<span class="py-src-variable">addErrback</span>(<span class="py-src-keyword">lambda</span> <span class="py-src-variable">_</span>: <span class="py-src-string">&quot;Internal error in server&quot;</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">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">m</span>))

<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>):
    <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>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">filename</span> = <span class="py-src-variable">filename</span>
        <span class="py-src-variable">self</span>.<span class="py-src-variable">_read</span>()
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">_read</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">self</span>.<span class="py-src-variable">users</span> = {}
        <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>):
            <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>)
            <span class="py-src-variable">user</span> = <span class="py-src-variable">user</span>.<span class="py-src-variable">strip</span>()
            <span class="py-src-variable">status</span> = <span class="py-src-variable">status</span>.<span class="py-src-variable">strip</span>()
            <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>
        <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>)
    <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>):
        <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">&quot;No such user&quot;</span>))
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getFingerFactory</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ServerFactory</span>()
        <span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span>, <span class="py-src-variable">f</span>.<span class="py-src-variable">getUser</span> = <span class="py-src-variable">FingerProtocol</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
        <span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>
    <span class="py-src-keyword">def</span> <span class="py-src-identifier">getResource</span>(<span class="py-src-parameter">self</span>):
        <span class="py-src-variable">r</span> = <span class="py-src-variable">resource</span>.<span class="py-src-variable">Resource</span>()
        <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>:
                      <span class="py-src-variable">static</span>.<span class="py-src-variable">Data</span>(<span class="py-src-string">'&lt;h1&gt;%s&lt;/h1&gt;&lt;p&gt;%s&lt;/p&gt;'</span> %
                      <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>,
                      [<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">&quot;No such user&quot;</span>)])),
                      <span class="py-src-string">'text/html'</span>))
        <span class="py-src-variable">x</span> = <span class="py-src-variable">xmlrpc</span>.<span class="py-src-variable">XMLRPC</span>()
        <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>
        <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>)
        <span class="py-src-keyword">return</span> <span class="py-src-variable">r</span>
    <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>):
        <span class="py-src-variable">f</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ReconnectingClientFactory</span>()
        <span class="py-src-variable">f</span>.<span class="py-src-variable">protocol</span>,<span class="py-src-variable">f</span>.<span class="py-src-variable">nickname</span>,<span class="py-src-variable">f</span>.<span class="py-src-variable">getUser</span> = <span class="py-src-variable">IRCReplyBot</span>,<span class="py-src-variable">nickname</span>,<span class="py-src-variable">self</span>.<span class="py-src-variable">getUser</span>
        <span class="py-src-keyword">return</span> <span class="py-src-variable">f</span>

<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>)
<span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
<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>)
<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>()
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
<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>())
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
<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>)
                   ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
</pre><div class="caption">Source listing - <a href="listings/finger/finger17.py"><span class="filename">listings/finger/finger17.py</span></a></div></div><p>A simple client to test the XMLRPC finger:</p><div class="py-listing"><pre>
<span class="py-src-comment"># testing xmlrpc finger
</span>
<span class="py-src-keyword">import</span> <span class="py-src-variable">xmlrpclib</span>
<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>)
<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>)
</pre><div class="caption">Source listing - <a href="listings/finger/fingerXRclient.py"><span class="filename">listings/finger/fingerXRclient.py</span></a></div></div></div><p><a href="../../howto/index.html">Index</a></p><span class="version">Version: 2.5.0</span></body></html>