diff options
Diffstat (limited to 'doc/core/howto/tutorial/protocol.html')
-rw-r--r-- | doc/core/howto/tutorial/protocol.html | 1121 |
1 files changed, 1121 insertions, 0 deletions
diff --git a/doc/core/howto/tutorial/protocol.html b/doc/core/howto/tutorial/protocol.html new file mode 100644 index 0000000..d3915bb --- /dev/null +++ b/doc/core/howto/tutorial/protocol.html @@ -0,0 +1,1121 @@ +<?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"> + <head> +<title>Twisted Documentation: The Evolution of Finger: adding features to the finger service</title> +<link href="../stylesheet.css" rel="stylesheet" type="text/css"/> + </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/> + +<h2>Introduction<a name="auto0"/></h2> + +<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> + +<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. +Resources and XML-RPC are introduced in the Web Applications portion of +the <a href="../../../web/howto/index.html" shape="rect">Twisted Web howto</a>. More examples +using <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.words.protocols.irc.html" title="twisted.words.protocols.irc">twisted.words.protocols.irc</a></code> can be found +in <a href="../clients.html" shape="rect">Writing a TCP Client</a> and +the <a href="../../../words/examples/index.html" shape="rect">Twisted Words examples</a>.</p> + +<h2>Setting Message By Local Users<a name="auto1"/></h2> + +<p>Now that port 1079 is free, maybe we can use it with 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" xml:space="preserve"> +% nc localhost 1079 # or telnet localhost 1079 +moshez +Giving a tutorial now, sorry! +^D +</pre> + +<div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +</p><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">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>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span> + <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</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">message</span> + <span class="py-src-string">'\r\n'</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-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</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">"No such user"</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">user</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span>[<span class="py-src-number">0</span>] + <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>] + <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>) + +<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">fingerFactory</span>): + <span class="py-src-variable">self</span>.<span class="py-src-variable">fingerFactory</span> = <span class="py-src-variable">fingerFactory</span> + + <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>): + <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> + +<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.tac"><span class="filename">listings/finger/finger12.tac</span></a></div></div> + +<p>This program has two protocol-factory-TCPServer pairs, which are +both child services of the application. Specifically, +the <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.application.service.Service.setServiceParent.html" title="twisted.application.service.Service.setServiceParent">setServiceParent</a></code> +method is used to define the two TCPServer services as children +of <code>application</code>, which implements <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.application.service.IServiceCollection.html" title="twisted.application.service.IServiceCollection">IServiceCollection</a></code>. Both +services are thus started with the application.</p> + + +<h2>Use Services to Make Dependencies Sane<a name="auto2"/></h2> + +<p>The previous version had the setter poke at the innards of the +finger factory. This strategy is 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 define a common service +class with methods that will create factories on the fly. The service +also contains methods the factories will depend on.</p> + +<p>The factory-creation methods, <code>getFingerFactory</code> +and <code>getFingerSetterFactory</code>, follow this pattern:</p> + +<ol> + +<li>Instantiate a generic server +factory, <code>twisted.internet.protocol.ServerFactory</code>.</li> + +<li>Set the protocol class, just like our factory class would have.</li> + +<li>Copy a service method to the factory as a function attribute. The +function won't have access to the factory's <code>self</code>, but +that's OK because as a bound method it has access to the +service's <code>self</code>, which is what it needs. +For <code>getUser</code>, a custom method defined in the service gets +copied. For <code>setUser</code>, a standard method of +the <code>users</code> dictionary is copied.</li> + + +</ol> + +<p>Thus, 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> + +<p>As an application service, this new finger service implements the <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.application.service.IService.html" title="twisted.application.service.IService">IService</a></code> interface and +can be started and stopped in a standardized manner. We'll make use of this in +the next example.</p> + +<div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +</p><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">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>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span> + <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</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">message</span> + <span class="py-src-string">'\r\n'</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-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</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">user</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">lines</span>[<span class="py-src-number">0</span>] + <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>] + <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>) + +<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">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">"No such user"</span>)) + + <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>): + <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-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">FingerProtocol</span> + <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> + <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">FingerSetterProtocol</span> + <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> + <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-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.tac"><span class="filename">listings/finger/finger13.tac</span></a></div></div> + +<p>Most application services will want to use the <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.application.service.Service.html" title="twisted.application.service.Service">Service</a></code> base class, which implements +all the generic <code>IService</code> behavior.</p> + +<h2>Read Status File<a name="auto3"/></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><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +</p><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">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>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span> + <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</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">message</span> + <span class="py-src-string">'\r\n'</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-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</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">"No such user"</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">FingerProtocol</span> + <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> + <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.tac"><span class="filename">listings/finger/finger14.tac</span></a></div></div> + +<p>Since this version is reading data from a file (and refreshing the data +every 30 seconds), there is no <code>FingerSetterFactory</code> and thus +nothing listening on port 1079.</p> + +<p>Here we override the standard <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.application.service.Service.startService.html" title="twisted.application.service.Service.startService">startService</a></code> +and <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.application.service.Service.stopService.html" title="twisted.application.service.Service.stopService">stopService</a></code> hooks in +the Finger service, which is set up as a child service of the +application in the last line of the code. <code>startService</code> +calls <code>_read</code>, the function responsible for reading the +data; <code>reactor.callLater</code> is then used to schedule it to +run again after thirty seconds every time it is +called. <code>reactor.callLater</code> returns an object that lets us +cancel the scheduled run in <code>stopService</code> using +its <code>cancel</code> method.</p> + +<h2>Announce on Web, Too<a name="auto4"/></h2> + +<p>The same kind of service can also produce things useful for other +protocols. For example, in twisted.web, the factory itself +(<code base="API" class="twisted.web.server">Site</code>) is almost +never subclassed — instead, it is given a resource, which +represents the tree of resources available via URLs. That hierarchy is +navigated by <code base="API" class="twisted.web.server">Site</code> +and overriding it dynamically is possible with <code base="API" class="twisted.web.resource.Resource">getChild</code>.</p> + +<p>To integrate this into the Finger application (just because we can), we set +up a new TCPServer that calls the <code base="API" class="twisted.web.server">Site</code> factory and retrieves resources via a +new function of <code>FingerService</code> named <code>getResource</code>. +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> + +<div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +</p><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">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>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span> + <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</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">message</span> + <span class="py-src-string">'\r\n'</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-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</span>) + + +<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>): + + <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-string">""" + 'username' is a string. + 'request' is a 'twisted.web.server.Request'. + """</span> + <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>) + <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">messagevalue</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">messagevalue</span> = <span class="py-src-variable">cgi</span>.<span class="py-src-variable">escape</span>(<span class="py-src-variable">messagevalue</span>) + <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>) + <span class="py-src-keyword">else</span>: + <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> + <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">users</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-variable">clear</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">"No such user"</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">FingerProtocol</span> + <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> + <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">FingerResource</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-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-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">f</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">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.tac"><span class="filename">listings/finger/finger15.tac</span></a></div></div> + + +<h2>Announce on IRC, Too<a name="auto5"/></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 <code>connectionMade</code>.</p> + +<div class="py-listing"><pre><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +</p><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">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>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span> + <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</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">message</span> + <span class="py-src-string">'\r\n'</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-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</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">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>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span> + <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</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">message</span>) + <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</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">users</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-variable">clear</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">"No such user"</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">FingerProtocol</span> + <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> + <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">'<h1>%s</h1><p>%s</p>'</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">"No such user <p/> usage: site/user"</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">IRCReplyBot</span> + <span class="py-src-variable">f</span>.<span class="py-src-variable">nickname</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">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">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-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">f</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">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.tac"><span class="filename">listings/finger/finger16.tac</span></a></div></div> + +<p><code>FingerService</code> now has another new +function, <code>getIRCbot</code>, which returns +the <code>ReconnectingClientFactory</code>. This factory in turn will +instantiate the <code>IRCReplyBot</code> protocol. The IRCBot is +configured in the last line to connect +to <code>irc.freenode.org</code> with a nickname +of <code>fingerbot</code>.</p> + +<p>By +overriding <code>irc.IRCClient.connectionMade</code>, <code>IRCReplyBot</code> +can access the <code>nickname</code> attribute of the factory that +instantiated it.</p> + +<h2>Add XML-RPC Support<a name="auto6"/></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><p class="py-linenumber"> 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +</p><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">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>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span> + <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</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">message</span> + <span class="py-src-string">'\r\n'</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-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</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">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>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">onError</span>(<span class="py-src-parameter">err</span>): + <span class="py-src-keyword">return</span> <span class="py-src-string">'Internal error in server'</span> + <span class="py-src-variable">d</span>.<span class="py-src-variable">addErrback</span>(<span class="py-src-variable">onError</span>) + + <span class="py-src-keyword">def</span> <span class="py-src-identifier">writeResponse</span>(<span class="py-src-parameter">message</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">message</span>) + <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">writeResponse</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">users</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-variable">clear</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">"No such user"</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">FingerProtocol</span> + <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> + <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">'<h1>%s</h1><p>%s</p>'</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">"No such user"</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">IRCReplyBot</span> + <span class="py-src-variable">f</span>.<span class="py-src-variable">nickname</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">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">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-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">f</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">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.tac"><span class="filename">listings/finger/finger17.tac</span></a></div></div> + +<p>Instead of a web browser, we can test the XMLRPC finger using a simple +client based on Python's built-in <code>xmlrpclib</code>, which will access +the resource we've made available at <code>localhost/RPC2</code>.</p> + +<div class="py-listing"><pre><p class="py-linenumber">1 +2 +3 +4 +5 +</p><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="../index.html">Index</a></p> + <span class="version">Version: 12.1.0</span> + </body> +</html>
\ No newline at end of file |