简体   繁体   English

从 Django 控制 Twisted 服务器

[英]Controlling a Twisted Server from Django

I'm trying to build a Twisted/Django mashup that will let me control various client connections managed by a Twisted server via Django's admin interface.我正在尝试构建一个 Twisted/Django mashup,它可以让我通过 Django 的管理界面控制由Twisted 服务器管理的各种客户端连接。 Meaning, I want to be able to login to Django's admin and see what protocols are currently in use, any details specific to each connection (eg if the server is connected to freenode via IRC, it should list all the channels currently connected to), and allow me to disconnect or connect new clients by modifying or creating database records.意思是,我希望能够登录到 Django 的管理员并查看当前正在使用的协议,每个连接特定的任何详细信息(例如,如果服务器通过 IRC 连接到 freenode,它应该列出当前连接的所有通道),并允许我通过修改或创建数据库记录来断开或连接新客户端。

What would be the best way to do this?什么是最好的方法来做到这一点? There are lots of posts out there about combining Django with Twisted , but I haven't found any prior art for doing quite what I've outlined.有很多关于DjangoTwisted 结合的帖子,但我还没有找到任何可以完成我所概述的工作的现有技术。 All the Twisted examples I've seen use hardcoded connection parameters, which makes it difficult for me to imagine how I would dynamically running reactor.connectTCP(...) or loseConnection(...) when signalled by a record in the database.我见过的所有 Twisted 示例都使用硬编码的连接参数,这让我很难想象当数据库中的记录发出信号时,我将如何动态运行 reactor.connectTCP(...) 或 lossConnection(...)。

My strategy is to create a custom ClientFactory that solely polls the Django/managed database every N seconds for any commands, and to modify/create/delete connections as appropriate, reflecting the new status in the database when complete.我的策略是创建一个自定义 ClientFactory,它每 N 秒轮询一次 Django/托管数据库的任何命令,并根据需要修改/创建/删除连接,在完成时反映数据库中的新状态。

Does this seem feasible?这看起来可行吗? Is there a better approach?有没有更好的方法? Does anyone know of any existing projects that implement similar functionality?有谁知道任何实现类似功能的现有项目?

Polling the database is lame, but unfortunately, databases rarely have good tools (and certainly there are no database-portable tools) for monitoring changes.轮询数据库是蹩脚的,但不幸的是,数据库很少有用于监视更改的好工具(当然也没有数据库可移植工具)。 So your approach might be okay.所以你的方法可能没问题。

However, if your app is in Django and you're not supporting random changes to the database from other (non-Django) clients, and your WSGI container is Twisted, then you can do this very simply by doing callFromThread(connectTCP, ...) .但是,如果您的应用程序在 Django 中并且您不支持从其他(非 Django)客户端对数据库进行随机更改,并且您的 WSGI 容器是 Twisted,那么您可以通过执行callFromThread(connectTCP, ...) .

I've been working on yet another way of combing django and twisted.我一直在研究另一种结合 django 和扭曲的方法。 Fell free to give it a try: https://github.com/kowalski/featdjango .随意尝试一下: https : //github.com/kowalski/featdjango

The way it works, is slightly different that the others.它的工作方式与其他方式略有不同。 It starts a twisted application and http site.它启动了一个扭曲的应用程序和 http 站点。 The requests done to django are processed inside a special thread pool.对 django 的请求在一个特殊的线程池中处理。 What makes it special, is that that these threads can wait on Deferred, which makes it easy to combine synchronous django application code with asynchronous twisted code.它的特别之处在于,这些线程可以在 Deferred 上等待,这使得将同步 django 应用程序代码与异步扭曲代码结合起来很容易。

The reason I came up with structure like this, is that my application needs to perform a lot of http requests from inside the django views.我想出这样的结构的原因是我的应用程序需要从 django 视图内部执行大量 http 请求。 Instead of performing them one by one I can delegate all of them at once to "the main application thread" which runs twisted and wait for them.我可以一次将它们全部委托给“主应用程序线程”,它运行扭曲并等待它们,而不是一个一个地执行它们。 The similarity to your problem is, that I also have an asynchronous component, which is a singleton and I access it from django views.与您的问题的相似之处在于,我还有一个异步组件,它是一个单例,我从 Django 视图访问它。

So this is, for example, this is how you would initiate the twisted component and later to get the reference from the view.因此,例如,这就是您将如何启动扭曲组件以及稍后从视图中获取引用的方式。

import threading

from django.conf import settings

_initiate_lock = threading.Lock()

def get_component():
    global _initiate_lock
    if not hasattr(settings, 'YOUR_CLIENT')
        _initiate_lock.acquire()
        try:
            # other thread might have did our job while we
            # were waiting for the lock
            if not hasattr(settings, 'YOUR_CLIENT'):
                client = YourComponent(**whatever)
                threading.current_thread().wait_for_deferred(
                    client.initiate)
                settings.YOUR_CLIENT = client
        finally:
            _initiate_lock.release()
    return settings.YOUR_CLIENT

The code above, initiates my client and calls the initiate method on it.上面的代码启动我的客户端并调用其上的启动方法。 This method is asynchronous and returns a Deferred.此方法是异步的,并返回一个延迟。 I do all the necessary setup in there.我在那里做了所有必要的设置。 The django thread will wait for it to finish before processing to next line. django 线程将等待它完成,然后再处理到下一行。

This is how I do it, because I only access it from the request handler.我就是这样做的,因为我只从请求处理程序访问它。 You probably would want to initiate your component at startup, to call ListenTCP|SSL.您可能希望在启动时启动您的组件,以调用 ListenTCP|SSL。 Than your django request handlers could get the data about the connections just accessing some public methods on the your client.比您的 django 请求处理程序可以获取有关连接的数据,只需访问您客户端上的一些公共方法。 These methods could even return Deferred, in which case you should use .wait_for_defer() to call them.这些方法甚至可能返回 Deferred,在这种情况下,您应该使用 .wait_for_defer() 来调用它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM