Initial import to Tizen
[profile/ivi/python-twisted.git] / doc / core / howto / tutorial / library.html
1 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE html  PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
2   <head>
3 <title>Twisted Documentation: The Evolution of Finger: making a finger library</title>
4 <link href="../stylesheet.css" rel="stylesheet" type="text/css"/>
5   </head>
6
7   <body bgcolor="white">
8     <h1 class="title">The Evolution of Finger: making a finger library</h1>
9     <div class="toc"><ol><li><a href="#auto0">Introduction</a></li><li><a href="#auto1">Organization</a></li><li><a href="#auto2">Easy Configuration</a></li></ol></div>
10     <div class="content">
11
12 <span/>
13
14 <h2>Introduction<a name="auto0"/></h2>
15
16 <p> This is the tenth part of the Twisted tutorial <a href="index.html" shape="rect">Twisted from Scratch, or The Evolution of Finger</a>.</p>
17
18 <p>In this part, we separate the application code that launches a finger service
19 from the library code which defines a finger service, placing the application in
20 a Twisted Application Configuration (.tac) file. We also move configuration
21 (such as HTML templates) into separate files. Configuration and deployment with
22 .tac and twistd are introduced in <a href="../application.html" shape="rect">Using the
23 Twisted Application Framework</a>.</p>
24
25 <h2>Organization<a name="auto1"/></h2>
26
27 <p>Now this code, while quite modular and well-designed, isn't
28 properly organized. Everything above the <code>application=</code> belongs in a
29 module, and the HTML templates all belong in separate files.
30 </p>
31
32 <p>We can use the <code>templateFile</code> and <code>templateDirectory</code>
33 attributes to indicate what HTML template file to use for each Page, and where
34 to look for it.</p>
35
36 <div class="py-listing"><pre><p class="py-linenumber"> 1
37  2
38  3
39  4
40  5
41  6
42  7
43  8
44  9
45 10
46 11
47 12
48 13
49 14
50 15
51 16
52 17
53 18
54 19
55 20
56 21
57 22
58 23
59 24
60 25
61 26
62 27
63 28
64 29
65 30
66 31
67 </p><span class="py-src-comment"># organized-finger.tac</span>
68 <span class="py-src-comment"># eg:  twistd -ny organized-finger.tac</span>
69
70 <span class="py-src-keyword">import</span> <span class="py-src-variable">finger</span>
71
72 <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>
73 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">spread</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pb</span>
74 <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>
75 <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-variable">strports</span>
76 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">log</span>
77
78 <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>)
79 <span class="py-src-variable">f</span> = <span class="py-src-variable">finger</span>.<span class="py-src-variable">FingerService</span>(<span class="py-src-string">'/etc/users'</span>)
80 <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>)
81 <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">finger</span>.<span class="py-src-variable">IFingerFactory</span>(<span class="py-src-variable">f</span>)
82                    ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
83
84 <span class="py-src-variable">site</span> = <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">resource</span>.<span class="py-src-variable">IResource</span>(<span class="py-src-variable">f</span>))
85 <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">site</span>
86                    ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
87
88 <span class="py-src-variable">internet</span>.<span class="py-src-variable">SSLServer</span>(<span class="py-src-number">443</span>, <span class="py-src-variable">site</span>, <span class="py-src-variable">finger</span>.<span class="py-src-variable">ServerContextFactory</span>()
89                    ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
90
91 <span class="py-src-variable">i</span> = <span class="py-src-variable">finger</span>.<span class="py-src-variable">IIRCClientFactory</span>(<span class="py-src-variable">f</span>)
92 <span class="py-src-variable">i</span>.<span class="py-src-variable">nickname</span> = <span class="py-src-string">'fingerbot'</span>
93 <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">i</span>
94                    ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
95
96 <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-number">8889</span>, <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">finger</span>.<span class="py-src-variable">IPerspectiveFinger</span>(<span class="py-src-variable">f</span>))
97                    ).<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">serviceCollection</span>)
98 </pre><div class="caption">Source listing - <a href="listings/finger/organized-finger.tac"><span class="filename">listings/finger/organized-finger.tac</span></a></div></div>
99
100 <p>
101 Note that our program is now quite separated. We have:
102 <ul>
103   <li>Code (in the module)</li>
104   <li>Configuration (file above)</li>
105   <li>Presentation (templates)</li>
106   <li>Content (<code>/etc/users</code>)</li>
107   <li>Deployment (twistd)</li>
108 </ul>
109
110 Prototypes don't need this level of separation, so our earlier examples all
111 bunched together. However, real applications do. Thankfully, if we write our
112 code correctly, it is easy to achieve a good separation of parts.
113 </p>
114
115
116 <h2>Easy Configuration<a name="auto2"/></h2>
117
118 <p>We can also supply easy configuration for common cases with a makeService
119 method that will also help build .tap files later:</p>
120
121 <div class="py-listing"><pre><p class="py-linenumber"> 1
122  2
123  3
124  4
125  5
126  6
127  7
128  8
129  9
130 10
131 11
132 12
133 13
134 14
135 15
136 16
137 17
138 18
139 19
140 20
141 21
142 22
143 23
144 24
145 25
146 26
147 27
148 28
149 29
150 30
151 31
152 32
153 33
154 34
155 35
156 36
157 37
158 38
159 </p><span class="py-src-comment"># Easy configuration</span>
160 <span class="py-src-comment"># makeService from finger module</span>
161
162 <span class="py-src-keyword">def</span> <span class="py-src-identifier">makeService</span>(<span class="py-src-parameter">config</span>):
163     <span class="py-src-comment"># finger on port 79</span>
164     <span class="py-src-variable">s</span> = <span class="py-src-variable">service</span>.<span class="py-src-variable">MultiService</span>()
165     <span class="py-src-variable">f</span> = <span class="py-src-variable">FingerService</span>(<span class="py-src-variable">config</span>[<span class="py-src-string">'file'</span>])
166     <span class="py-src-variable">h</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">IFingerFactory</span>(<span class="py-src-variable">f</span>))
167     <span class="py-src-variable">h</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">s</span>)
168
169     <span class="py-src-comment"># website on port 8000</span>
170     <span class="py-src-variable">r</span> = <span class="py-src-variable">resource</span>.<span class="py-src-variable">IResource</span>(<span class="py-src-variable">f</span>)
171     <span class="py-src-variable">r</span>.<span class="py-src-variable">templateDirectory</span> = <span class="py-src-variable">config</span>[<span class="py-src-string">'templates'</span>]
172     <span class="py-src-variable">site</span> = <span class="py-src-variable">server</span>.<span class="py-src-variable">Site</span>(<span class="py-src-variable">r</span>)
173     <span class="py-src-variable">j</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">site</span>)
174     <span class="py-src-variable">j</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">s</span>)
175
176     <span class="py-src-comment"># ssl on port 443</span>
177     <span class="py-src-keyword">if</span> <span class="py-src-variable">config</span>.<span class="py-src-variable">get</span>(<span class="py-src-string">'ssl'</span>):
178         <span class="py-src-variable">k</span> = <span class="py-src-variable">internet</span>.<span class="py-src-variable">SSLServer</span>(<span class="py-src-number">443</span>, <span class="py-src-variable">site</span>, <span class="py-src-variable">ServerContextFactory</span>())
179         <span class="py-src-variable">k</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">s</span>)
180
181     <span class="py-src-comment"># irc fingerbot</span>
182     <span class="py-src-keyword">if</span> <span class="py-src-variable">config</span>.<span class="py-src-variable">has_key</span>(<span class="py-src-string">'ircnick'</span>):
183         <span class="py-src-variable">i</span> = <span class="py-src-variable">IIRCClientFactory</span>(<span class="py-src-variable">f</span>)
184         <span class="py-src-variable">i</span>.<span class="py-src-variable">nickname</span> = <span class="py-src-variable">config</span>[<span class="py-src-string">'ircnick'</span>]
185         <span class="py-src-variable">ircserver</span> = <span class="py-src-variable">config</span>[<span class="py-src-string">'ircserver'</span>]
186         <span class="py-src-variable">b</span> = <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPClient</span>(<span class="py-src-variable">ircserver</span>, <span class="py-src-number">6667</span>, <span class="py-src-variable">i</span>)
187         <span class="py-src-variable">b</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">s</span>)
188
189     <span class="py-src-comment"># Pespective Broker on port 8889</span>
190     <span class="py-src-keyword">if</span> <span class="py-src-variable">config</span>.<span class="py-src-variable">has_key</span>(<span class="py-src-string">'pbport'</span>):
191         <span class="py-src-variable">m</span> = <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(
192             <span class="py-src-variable">int</span>(<span class="py-src-variable">config</span>[<span class="py-src-string">'pbport'</span>]),
193             <span class="py-src-variable">pb</span>.<span class="py-src-variable">PBServerFactory</span>(<span class="py-src-variable">IPerspectiveFinger</span>(<span class="py-src-variable">f</span>)))
194         <span class="py-src-variable">m</span>.<span class="py-src-variable">setServiceParent</span>(<span class="py-src-variable">s</span>)
195
196     <span class="py-src-keyword">return</span> <span class="py-src-variable">s</span>
197 </pre><div class="caption">Source listing - <a href="listings/finger/finger_config.py"><span class="filename">listings/finger/finger_config.py</span></a></div></div>
198
199 <p>And we can write simpler files now:</p>
200
201 <div class="py-listing"><pre><p class="py-linenumber"> 1
202  2
203  3
204  4
205  5
206  6
207  7
208  8
209  9
210 10
211 11
212 12
213 13
214 14
215 15
216 16
217 17
218 </p><span class="py-src-comment"># simple-finger.tac</span>
219 <span class="py-src-comment"># eg:  twistd -ny simple-finger.tac</span>
220
221 <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">service</span>
222
223 <span class="py-src-keyword">import</span> <span class="py-src-variable">finger</span>
224
225 <span class="py-src-variable">options</span> = { <span class="py-src-string">'file'</span>: <span class="py-src-string">'/etc/users'</span>,
226             <span class="py-src-string">'templates'</span>: <span class="py-src-string">'/usr/share/finger/templates'</span>,
227             <span class="py-src-string">'ircnick'</span>: <span class="py-src-string">'fingerbot'</span>,
228             <span class="py-src-string">'ircserver'</span>: <span class="py-src-string">'irc.freenode.net'</span>,
229             <span class="py-src-string">'pbport'</span>: <span class="py-src-number">8889</span>,
230             <span class="py-src-string">'ssl'</span>: <span class="py-src-string">'ssl=0'</span> }
231
232 <span class="py-src-variable">ser</span> = <span class="py-src-variable">finger</span>.<span class="py-src-variable">makeService</span>(<span class="py-src-variable">options</span>)
233 <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>)
234 <span class="py-src-variable">ser</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>))
235 </pre><div class="caption">Source listing - <a href="listings/finger/simple-finger.tac"><span class="filename">listings/finger/simple-finger.tac</span></a></div></div>
236
237 <pre class="shell" xml:space="preserve">
238 % twisted -ny simple-finger.tac
239 </pre>
240
241
242 <p>Note: the finger <em>user</em> still has ultimate power: he can use
243  <code>makeService</code>, or he can use the lower-level interface if he has
244 specific needs (maybe an IRC server on some other port? Maybe we want the
245 non-SSL webserver to listen only locally?  etc. etc.)  This is an important
246 design principle: never force a layer of abstraction: allow usage of layers of
247 abstractions.</p>
248
249 <p>The pasta theory of design:</p>
250
251 <ul>
252 <li>Spaghetti: each piece of code interacts with every other piece of
253     code [can be implemented with GOTO, functions, objects]</li>
254 <li>Lasagna: code has carefully designed layers. Each layer is, in
255     theory independent. However low-level layers usually cannot be
256     used easily, and high-level layers depend on low-level layers.</li>
257 <li>Ravioli: each part of the code is useful by itself. There is a thin
258     layer of interfaces between various parts [the sauce]. Each part
259     can be usefully be used elsewhere.</li>
260 <li>...but sometimes, the user just wants to order <q>Ravioli</q>, so one
261     coarse-grain easily definable layer of abstraction on top of it all
262     can be useful.</li>
263 </ul>
264
265
266 </div>
267
268     <p><a href="../index.html">Index</a></p>
269     <span class="version">Version: 12.1.0</span>
270   </body>
271 </html>