我有一个IRC bot,我使用了Python的扭曲IRC协议中写道。 我希望能够运行命令,同时仍然允许机器人倾听并同时执行其他命令。
举例来说,假设我有命令,将打印大量文本文件的通道。 如果我想通过输入停止命令,而它运行!“停止”进入通道,我怎么能做到这一点? 还是让说,我想在一个频道做“!打印largefile”,然后去一个不同的频道和类型“!打印anotherfile”,并把它打印文件给另一个信道,甚至在完成打印第一个文件之前。
我在想,我会用线程用于这一目的? 我不太清楚。
编辑(澄清):
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
如果我想跑!printfile
在两个通道同时或停止printfile命令在运行时,我该怎么办?
你不能打断你的printfile命令的原因是,它包含了一个文件的全部内容的循环。 这意味着privmsg
功能将运行至具有读取和发送文件中的所有行。 它仅完成后的工作将其返回。
Twisted是一个单线程的协作式多任务系统。 只有一个你的计划的一部分,可以同时运行。 之前输入的来自IRC服务器的下一行可以通过你的IRC bot的处理, privmsg
必须返回。
然而,扭曲还善于处理事件和管理并发性。 所以,一个解决这个问题是发送使用包含在扭曲的工具之一文件(而不是一个for循环) - 一个工具,它与系统的其他部分合作,并允许其他事件的同时进行处理。
这里有一个简单的例子(未经测试,并与一些明显的问题(比如当两个printfile命令到达靠得太近穷人的行为),我不会在这里试着修复):
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()
这使用twisted.internet.task.cooperate
,它接受一个迭代器(包括发电机),并运行它们在与应用程序的其余部分配合的方式辅助功能。 它是通过遍历迭代器几次,然后让其他工作运行,然后回来给迭代,依此类推,直到迭代耗尽做到这一点。
这意味着即使在正在发送的文件从IRC新邮件将被处理。
然而,还有一点要考虑的是IRC服务器通常包括防洪,这意味着许多发送行他们很快就可以让你的机器人断开。 即使在最好的情况下,IRC服务器可以缓冲线,其中只有在大的缓慢释放到网络。 如果机器人已经派出,他们都坐在IRC服务器的缓存行,你将无法从告诉机器人停止(因为它已经完成)出现在网络上阻止他们。 进一步,正因为如此,Twisted的IRC客户端也有缓冲,你叫那么即使self.msg
,该行实际上可能没有发送,因为为了避免送他们这么快的IRC客户端缓存行的IRC服务器踢机器人关闭网络。 因为我写的代码只能用电话对任self.msg
,你可能还没有真正能够被发送停止线,如果他们都已经进入了IRC客户端的本地缓存。
一个明显的(也许不是理想的)解决所有这些问题是稍微使用的iterator复杂_printfile
,通过插入一个新的延迟有 :
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))
在这里,我已经改变了迭代器,这样说出来它的元素是Deferreds从deferLater
(以前的元素都None
,因为这是的返回值self.msg
)。
当cooperate
遇到一个Deferred
,它停止工作对迭代器,直到后Deferred
火灾。 deferLater
以这种方式使用基本上是一个合作的睡眠功能。 它返回一个Deferred
,这将不会触发直到凌晨2秒钟后(然后将它与触发None
,其cooperate
并不特别在意)。 它触发后, cooperate
将继续在迭代器工作虽然。 所以,现在_printfile
只发送每两秒钟一个线,东西,这将是更容易与停止命令中断。
文章来源: Twisted Python IRC Bot - How to listen for commands while bot is running a command?