Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
TwistedPythonIRC Bot-如何在Bot运行命令时侦听命令?_Python_Twisted_Irc - Fatal编程技术网

TwistedPythonIRC Bot-如何在Bot运行命令时侦听命令?

TwistedPythonIRC Bot-如何在Bot运行命令时侦听命令?,python,twisted,irc,Python,Twisted,Irc,我有一个使用TwistedPythonIRC协议编写的IRC机器人。我希望能够运行命令,同时仍然允许bot同时侦听和执行其他命令 例如,假设我有一个命令,可以将一个大的文本文件打印到一个频道。如果我想在命令运行时通过在通道中输入“!stop”来停止命令,我该如何实现这一点?或者,假设我想在一个通道中执行“!打印大文件”,然后转到另一个通道并键入“!打印另一个文件”,让它在打印完第一个文件之前将该文件打印到另一个通道 我想我会使用线程来实现这个目的?我不太确定 编辑(澄清): 如果我想运行!pri

我有一个使用TwistedPythonIRC协议编写的IRC机器人。我希望能够运行命令,同时仍然允许bot同时侦听和执行其他命令

例如,假设我有一个命令,可以将一个大的文本文件打印到一个频道。如果我想在命令运行时通过在通道中输入“!stop”来停止命令,我该如何实现这一点?或者,假设我想在一个通道中执行“!打印大文件”,然后转到另一个通道并键入“!打印另一个文件”,让它在打印完第一个文件之前将该文件打印到另一个通道

我想我会使用线程来实现这个目的?我不太确定

编辑(澄清):


如果我想运行
!printfile
一次在两个通道中运行,或者在运行printfile命令时停止它,我该怎么办?

不能中断printfile命令的原因是它包含一个文件整个内容的循环。这意味着
privmsg
函数将一直运行,直到它读取并发送了文件中的所有行。只有完成了那项工作,它才会回来

Twisted是一个单线程协作多任务系统。一次只能运行程序的一部分。在irc bot可以处理来自irc服务器的下一行输入之前,
privmsg
必须返回

然而,Twisted也擅长处理事件和管理并发性。因此,这个问题的一个解决方案是使用Twisted中包含的一个工具(而不是for循环)发送文件,该工具与系统的其余部分协作,同时允许处理其他事件

下面是一个简单的示例(未经测试,并且存在一些明显的问题(例如两个printfile命令靠得太近时的不良行为),我不会在这里尝试修复这些问题):

这使用了
twisted.internet.task.cooperation
,这是一个帮助函数,它接受迭代器(包括生成器),并以与应用程序其余部分协作的方式运行迭代器。它通过迭代迭代器几次,然后让其他工作运行,然后返回到迭代器,依此类推,直到迭代器耗尽

这意味着即使在发送文件时,也会处理来自irc的新消息

然而,另一个要考虑的问题是IRC服务器通常包括防洪保护,这意味着很快地向它们发送许多线路可能会使您的BOT断开连接。即使在最好的情况下,irc服务器也可能会缓冲这些线路,并且只会缓慢地将它们释放到整个网络中。如果bot已经发送了这些行,并且它们位于irc服务器的缓冲区中,那么您将无法通过告诉bot停止来阻止它们出现在网络上(因为它已经完成)。此外,由于这一点,Twisted的irc客户端也有缓冲,因此即使在您调用
self.msg
之后,线路也可能不会实际发送,因为irc客户端正在缓冲线路,以避免发送速度过快,以至于irc服务器将bot从网络上启动。由于我编写的代码只处理对
self.msg
的调用,因此,如果所有行都已进入irc客户端的本地缓冲区,您可能仍然无法阻止它们被发送

对于所有这些问题,一个明显的(也许不是理想的)解决方案是在
\u printfile
中插入一个新的延迟,使迭代器稍微复杂化:

在这里,我更改了迭代器,因此从迭代器中产生的元素与
deletlater
(以前,元素都是
None
,因为这是
self.msg
的返回值)


cooperative
遇到一个
Deferred
时,它将停止对该迭代器的工作,直到该
Deferred
触发<代码>延迟延迟以这种方式使用基本上是一种协作睡眠功能。它返回一个
延迟的
,直到2秒后才会触发(然后以
触发,而
合作
并不特别关心)。触发后,
cooperative
将继续使用迭代器。所以现在,
\u printfile
每两秒只发送一行,这将更容易用stop命令中断。

这是一种开放式的方式。我可以告诉你,你不需要线程,但你真的从中学到了什么实用的东西吗?试着问一个更具体的问题。例如,发布一些代码。您尝试编写的无法接受输入的IRC bot在哪里?然后有人可以评论你应该改变什么。看,我提出的问题是我的问题,不管你能否回答。
def privmsg(self, user, channel, msg):
    nick = user.split('!', 1)[0]
    parts = msg.split(' ')
    trigger = parts[0]
    data = parts[1:]
    if trigger == '!printfile':
        myfile = open('/files/%s' % data[0], 'r')
        for line in myfile:
            line = line.strip('/r/n')
            self.msg(channel, line)
    if trigger == '!stop':
        CODE TO STOP THE CURRENTLY RUNNING PRINTFILE COMMAND
from twisted.internet.task import cooperate

....

def privmsg(self, user, channel, msg):
    nick = user.split('!', 1)[0]
    parts = msg.split(' ')
    trigger = parts[0]
    data = parts[1:]
    if trigger == '!printfile':
        self._printfile(channel, data[0])
    if trigger == '!stop':
        self._stopprintfile()

def _printfile(self, channel, name):
    myfile = open('/files/%s' % (name,), 'r')
    self._printfiletask = cooperate(
        self.msg(channel, line.rstrip('\r\n')) for line in myfile)


def _stopprintfile(self):
    self._printfiletask.stop()
from twisted.internet import reactor
from twisted.internet.task import deferLater

def _printfileiterator(self, channel, myfile):
    for line in myfile:
        self.msg(channel, line)
        yield deferLater(reactor, 2, lambda: None)

def _printfile(self, channel, name):
    myfile = open('/files/%s' % (name,), 'r')
    self._printfiletask = cooperate(self._printfileiterator(channel, myfile))