编写 twistd 插件¶
本文档介绍了如何向 twistd
命令添加子命令,作为简化应用程序部署的一种方式。
本文档的目标读者是那些已经开发了 Twisted 应用程序并需要基于命令行的部署机制的人。
理解本文档需要一些先决条件
需要对 Twisted 插件系统(即
twisted.plugin
模块)有一个基本的了解,但是会提供逐步说明。建议阅读 Twisted 插件系统,特别是“扩展现有程序”部分。在
twistd
插件中使用了 应用程序 基础设施;特别是,您应该了解如何将程序的功能公开为服务。为了解析命令行参数,
twistd
插件机制依赖于twisted.python.usage
,该机制在 使用 usage.Options 中有介绍。
目标¶
阅读完本文档后,读者应该能够将使用服务的应用程序公开为 twistd
的子命令,并考虑命令行中传递的任何内容。
twistd 插件的替代方案¶
twistd 插件机制的主要替代方案是 .tac
文件,它是一个简单的脚本,可与 twistd 的 -y/--python
参数一起使用。twistd 插件机制旨在为您的应用程序提供更可扩展的基于命令行的界面。有关 .tac
文件的更多信息,请参阅文档 使用 Twisted 应用程序框架。
创建插件¶
假设您的项目的目录结构如下
MyProject
- 顶级目录myproject
- Python 包__init__.py
在开发项目期间,Twisted 插件可以从项目中的一个特殊目录加载,假设您的顶级目录最终位于 sys.path
中。创建一个名为 twisted
的目录,其中包含一个名为 plugins
的目录,并将一个名为 myproject_plugin.py
的文件添加到其中。此文件将包含您的插件。请注意,您不能在此目录结构中添加任何 __init__.py
文件,并且插件文件不能命名为 myproject.py
(因为这会与您的项目的模块名称冲突)。
在此文件中,定义一个提供 twisted.plugin.IPlugin
和 twisted.application.service.IServiceMaker
接口的对象。
您的 IServiceMaker 提供者的 tapname
属性将用作类似 twistd [subcommand] [args...]
命令中的子命令名称,而 options
属性(应该是 usage.Options
子类)将用于解析给定的参数。
from zope.interface import implementer
from twisted.python import usage
from twisted.plugin import IPlugin
from twisted.application.service import IServiceMaker
from twisted.application import internet
from myproject import MyFactory
class Options(usage.Options):
optParameters = [["port", "p", 1235, "The port number to listen on."]]
@implementer(IServiceMaker, IPlugin)
class MyServiceMaker(object):
tapname = "myproject"
description = "Run this! It'll make your dog happy."
options = Options
def makeService(self, options):
"""
Construct a TCPServer from a factory defined in myproject.
"""
return internet.TCPServer(int(options["port"]), MyFactory())
# Now construct an object which *provides* the relevant interfaces
# The name of this variable is irrelevant, as long as there is *some*
# name bound to a provider of IPlugin and IServiceMaker.
serviceMaker = MyServiceMaker()
现在运行 twistd --help
应该在可用子命令列表中打印 myproject
,后跟我们在插件中指定的描述。假设我们在 myproject
中定义了一个 MyFactory
工厂,那么 twistd -n myproject
将在端口 1235 上启动一个使用该工厂的监听服务器。
在 TAP 中使用 cred
¶
Twisted 附带了一个强大的身份验证框架,可用于您的应用程序。如果您的服务器需要身份验证功能,并且您还没有阅读有关 twisted.cred 的内容,请先阅读。
如果您正在构建 twistd 插件,并且希望支持各种身份验证模式,Twisted 为您的 Options 子类提供了一个易于使用的 mixin:strcred.AuthOptionMixin
。以下代码是使用此 mixin 的示例
from twisted.cred import credentials, portal, strcred
from twisted.python import usage
from twisted.plugin import IPlugin
from twisted.application.service import IServiceMaker
from myserver import myservice
class ServerOptions(usage.Options, strcred.AuthOptionMixin):
# This part is optional; it tells AuthOptionMixin what
# kinds of credential interfaces the user can give us.
supportedInterfaces = (credentials.IUsernamePassword,)
optParameters = [
["port", "p", 1234, "Server port number"],
["host", "h", "localhost", "Server hostname"]]
@implementer(IServiceMaker, IPlugin)
class MyServerServiceMaker(object):
tapname = "myserver"
description = "This server does nothing productive."
options = ServerOptions
def makeService(self, options):
"""Construct a service object."""
# The realm is a custom object that your server defines.
realm = myservice.MyServerRealm(options["host"])
# The portal is something Cred can provide, as long as
# you have a list of checkers that you'll support. This
# list is provided my AuthOptionMixin.
portal = portal.Portal(realm, options["credCheckers"])
# OR, if you know you might get multiple interfaces, and
# only want to give your application one of them, you
# also have that option with AuthOptionMixin:
interface = credentials.IUsernamePassword
portal = portal.Portal(realm, options["credInterfaces"][interface])
# The protocol factory is, like the realm, something you implement.
factory = myservice.ServerFactory(realm, portal)
# Finally, return a service that will listen for connections.
return internet.TCPServer(int(options["port"]), factory)
# As in our example above, we have to construct an object that
# provides the IPlugin and IServiceMaker interfaces.
serviceMaker = MyServerServiceMaker()
现在您已经将 TAP 配置为支持我们可能遇到的任何身份验证,您就可以使用它了。以下是如何使用 /etc/passwd
文件进行身份验证来启动服务器的示例。(显然,这在使用 shadow 密码的服务器上不起作用。)
$ twistd myserver --auth passwd:/etc/passwd
有关支持的完整 cred 插件列表,请参阅 twisted.plugins
,或使用命令行帮助
$ twistd myserver --help-auth
$ twistd myserver --help-auth-type passwd
使用 Python 包部署您的应用程序¶
要部署您的应用程序,一种方法是将其打包成 Python 包。为此,您需要编写一个名为 setup.py
的特殊文件,其中包含包的元数据。您需要像这样扩展文件布局
MyProject
- 顶级目录setup.py
- 包的描述文件myproject
- Python 包__init__.py
twisted
插件
myproject_plugins.py
- 包含实际插件的 Dropin 文件
from setuptools import setup, find_packages
setup(
name='MyApplication',
version='0.1dev',
# it is necesary to extend the found package list with the twisted.plugin
# directory. It cannot be automatically detected, because it should not
# contain a __init__.py file.
packages=find_packages() + ['twisted.plugins'],
install_requires=[
'twisted',
],
)
要从目录创建 Python 包,可以使用标准的设置工具
$ python3 setup.py sdist
此命令会在您的项目文件夹中创建一个名为 dist
的目录,其中包含压缩的存档文件 MyApplication-0.1dev.tar.gz
。 此存档包含所有代码和指定的其他文件。 此文件可以复制并用于部署。
要安装应用程序,只需使用 pip。 它还会安装 setup.py
中指定的所有需求。
$ pip install MyApplication-0.1dev.tar.gz
有关 Python 中打包的更多信息,请查看 官方 Python 打包用户指南 或 打包的搭便车指南。
结论¶
您现在应该能够
创建一个 twistd 插件
将身份验证整合到您的插件中
从您的开发环境中使用它
正确安装它并在部署中使用它