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