Twisted和txpostgres回调混乱

时间:2015-10-22 23:34:54

标签: python multithreading postgresql twisted psycopg2

我正在尝试使用twistedtxpostgres编写一个简单的服务。连接的第一件事就是注册,所以我想我会先写一个注册函数。我几乎立刻感到困惑。

这是我写的代码 - 我会在之后解释我的困惑。

from txpostgres        import txpostgres
from twisted.internet  import reactor, protocol, endpoints
from twisted.protocols import basic

# Start by just connecting to my PostgreSQL server.
conn = txpostgres.Connection()
d = conn.connect('dbname=matchmaker user=postgres')

# Ensure my user table exists.
d.addCallback(lambda _: conn.runOperation('CREATE TABLE IF NOT EXISTS user(username text);'))

class PubProtocol(basic.LineReceiver):
    def __init__(self, factory):
        self.factory = factory

    def connectionMade(self):
        print('Connection made.')
        self.factory.clients.add(self)

    def connectionLost(self, reason):
        print('Connection lost.')
        self.factory.clients.remove(self)

    def lineReceived(self, line):
        # Check whether the user already exists or not...
        d.addCallback(lambda _: conn.runQuery('SELECT EXISTS(SELECT 1 FROM user WHERE username = "{}"'.format(line)))

        # Wait - how do I actually branch based on that?

class PubFactory(protocol.Factory):
    def __init__(self):
        self.clients = set()

    def buildProtocol(self, addr):
        return PubProtocol(self)

endpoints.serverFromString(reactor, "tcp:1025").listen(PubFactory())
print('Starting...')
reactor.run()

所以这开始并没有太糟糕 - 我连接到我的数据库(它设置为信任localhost所以我不需要提供密码),然后我确保该表存在。

由于我刚刚开始,我只是天真地将任何收到的行解释为使用该行作为用户名注册的请求。我意识到这现在容易受到SQL注入的攻击 - 当用户实际注册/被拒绝时,这将是我的首要任务。

问题是,我如何根据该查询的结果实际分支?我可以添加另一个回调,它接受该查询返回的内容,但lambdas仅限于一个表达式(没有语句),因此我似乎必须添加一个简单地接受True或一个False基于是否使用了用户名,然后它必须实际处理创建用户或引发异常。

但这听起来很快就会溶解到意大利面条代码中。我只会有一堆函数,因为每次我想要分支时,我都要编写另一个函数。

我的理解是twisted是多线程的。每次建立连接时,它都会获得自己的线程。回调用于在其他线程上执行操作......但是在另一个线程上实际执行它的重点是什么?在查询我的数据库之前,没有消息可以发送给用户 - 在另一个线程上执行此操作似乎毫无意义。

如何根据用户名是否已被占用进行分支?我该怎么写这段代码?我应该使用单个Defer对象(d)并在全局范围和方法中使用它,如果不是,我应该如何处理它?<​​/ p>

1 个答案:

答案 0 :(得分:0)

有一点:twisted不是多线程的。它适用于反应堆模型,每当您的代码 阻塞IO之类的东西时,它就会使用select系统调用,这会导致内核在IO操作后通知进程准备好了。执行此操作时,twisted将移至可继续运行的其他代码。多段代码永远不会同时运行。