Finger演化:生成finger库 The Evolution of Finger: making a finger library
介绍(Introduction)
这是Twisted教程《Twisted入门 - Finger演化》的第十部分。
This is the tenth part of the Twisted tutorial Twisted from Scratch, or The Evolution of Finger.
在这个部分中,我们把装载finger服务的应用代码从定义finger服务的库代码中分离出来,将应用放在Twisted应用配置(Twisted Application Configuration)(.tac)文件中。我们同样将配置(象 HTML 模板)放入到分离的文件中。
In this part, we separate the application code that launches a finger service from the library code which defines a finger service, placing the application in a Twisted Application Configuration (.tac) file. We also move configuration (such as HTML templates) into separate files.
组织(Organization)
现在这些代码,尽管设计良好并且相当模块化,但组织得不合适。在应用之上的所有东西应归于一个模块,所有的 HTML 模板应归于分离的文件。
Now this code, while quite modular and well-designed, isn't properly organized. Everything above the application belongs in a module, and the HTML templates all belong in separate files.
我们可以使用 templateFile 和 templateDirectory属性来指明,对每个页面使用什么 HTML 模板文件,并且到哪里去寻找。
We can use the templateFile and templateDirectory attributes to indicate what HTML template file to use for each Page, and where to look for it.
1 # organized-finger.tac
2 # eg: twistd -ny organized-finger.tac
3
4 import finger
5
6 from twisted.internet import protocol, reactor, defer
7 from twisted.spread import pb
8 from twisted.web import resource, server
9 from twisted.application import internet, service, strports
10 from twisted.python import log
11
12 application = service.Application('finger', uid=1, gid=1)
13 f = finger.FingerService('/etc/users')
14 serviceCollection = service.IServiceCollection(application)
15 internet.TCPServer(79, finger.IFingerFactory(f)
16 ).setServiceParent(serviceCollection)
17
18 site = server.Site(resource.IResource(f))
19 internet.TCPServer(8000, site
20 ).setServiceParent(serviceCollection)
21
22 internet.SSLServer(443, site, ServerContextFactory()
23 ).setServiceParent(serviceCollection)
24
25 i = finger.IIRCClientFactory(f)
26 i.nickname = 'fingerbot'
27 internet.TCPClient('irc.freenode.org', 6667, i
28 ).setServiceParent(serviceCollection)
29
30 internet.TCPServer(8889, pb.PBServerFactory(finger.IPerspectiveFinger(f))
31 ).setServiceParent(serviceCollection)
Source listing - listings/finger/organized-finger.tac Note that our program is now quite separated. We have:
Code (in the module) Configuration (file above) Presentation (templates) Content (/etc/users) Deployment (twistd) 原型并不需要这种层次的分离,因此早先的例子全都绑在了一起。然而,真正的应用需要。要感谢的是,如果我们编写的代码正确,使各部分很好的分离是容易的。
Prototypes don't need this level of separation, so our earlier examples all bunched together. However, real applications do. Thankfully, if we write our code correctly, it is easy to achieve a good separation of parts.
容易的配置(Easy Configuration)
我们也可以利用makeService方法为通常的情况提供容易的配置,后面这个方法还将对建立.tap文件提供帮助:
We can also supply easy configuration for common cases with a makeService method that will also help build .tap files later:
1 # Easy configuration
2 # makeService from finger module
3
4 def makeService(config):
5 # finger on port 79
6 s = service.MultiService()
7 f = FingerService(config['file'])
8 h = internet.TCPServer(79, IFingerFactory(f))
9 h.setServiceParent(s)
10
11 # website on port 8000
12 r = resource.IResource(f)
13 r.templateDirectory = config['templates']
14 site = server.Site(r)
15 j = internet.TCPServer(8000, site)
16 j.setServiceParent(s)
17
18 # ssl on port 443
19 if config.get('ssl'):
20 k = internet.SSLServer(443, site, ServerContextFactory())
21 k.setServiceParent(s)
22
23 # irc fingerbot
24 if config.has_key('ircnick'):
25 i = IIRCClientFactory(f)
26 i.nickname = config['ircnick']
27 ircserver = config['ircserver']
28 b = internet.TCPClient(ircserver, 6667, i)
29 b.setServiceParent(s)
30
31 # Pespective Broker on port 8889
32 if config.has_key('pbport'):
33 m = internet.TCPServer(
34 int(config['pbport']),
35 pb.PBServerFactory(IPerspectiveFinger(f)))
36 m.setServiceParent(s)
37
38 return s
Source listing - listings/finger/finger_config.py 同时我们现在可以编写更简单的文件:
And we can write simpler files now:
1 # simple-finger.tac
2 # eg: twistd -ny simple-finger.tac
3
4 from twisted.application import service
5
6 import finger
7
8 options = { 'file': '/etc/users',
9 'templates': '/usr/share/finger/templates',
10 'ircnick': 'fingerbot',
11 'ircserver': 'irc.freenode.net',
12 'pbport': 8889,
13 'ssl': 'ssl=0' }
14
15 ser = finger.makeService(options)
16 application = service.Application('finger', uid=1, gid=1)
17 ser.setServiceParent(service.IServiceCollection(application))
Source listing - listings/finger/simple-finger.tac % twisted -ny simple-finger.tac
注意:这个finger用户仍然拥有基本的能力:他可以使用makeService,或者如果有特殊需要(也许是在另一个端口上的IRC?也许我们想让non-SSL的web服务器只在本地进行监听?等等,等等)的话,他可以使用底层接口。这是一个很重要的设计原则:永远不要强加抽象层:允许抽象层的使用。
Note: the finger user still has ultimate power: he can use makeService, or he can use the lower-level interface if he has specific needs (maybe an IRC server on some other port? maybe we want the non-SSL webserver to listen only locally? etc. etc.) This is an important design principle: never force a layer of abstraction: allow usage of layers of abstractions.
意大利面条设计理论:(The pasta theory of design:)
细面条(Spaghetti):每一块要同其它代码块交互的代码[可以用GOTO、函数、对象来实现] 宽面条(Lasagna):拥有仔细设计过层的代码。每一个层是指在理论上独立。然后低级的层通常不易使用,而高级的层要依赖低级的层。 面卷(Ravioli):每一部分代码对自身都是有用的。在各部分之间有一个细的接口层[调料]。每一部分都可以用于其它地方。 ...但有时候,用户只想要订面卷,所以在它之上有一个容易定义的谷粒(coarse-grain)抽象层更加有用。
Spaghetti: each piece of code interacts with every other piece of code [can be implemented with GOTO, functions, objects] Lasagna: code has carefully designed layers. Each layer is, in theory independent. However low-level layers usually cannot be used easily, and high-level layers depend on low-level layers. Ravioli: each part of the code is useful by itself. There is a thin layer of interfaces between various parts [the sauce]. Each part can be usefully be used elsewhere. ...but sometimes, the user just wants to order Ravioli, so one coarse-grain easily definable layer of abstraction on top of it all can be useful.
return index-->["TwistedTUT"]
Version: 1.3.0