我正在尝试使用QueryServer连接到TeamSpeak服务器来制作机器人。我已经从this thread获得建议,但是我仍然需要帮助。
这是我正在使用的The TeamSpeak API。
在进行编辑之前,这是我的脚本(1个连接)中实际发生的情况的摘要:
它连接。
它检查频道ID(以及它自己的客户端ID)
它加入频道并开始阅读所有内容
如果有人说了一条特定的命令,它将执行该命令,然后断开连接。
我该如何做才能使其不断开连接?如何使脚本保持“等待”状态,以便在执行命令后继续读取?
我正在使用Python 3.4.1。
我尝试学习线程技术,但要么我很笨,要么以我认为的方式无法正常工作。还有一个“ bug”,一旦等待事件,如果我不使用命令触发任何东西,它将在60秒后断开连接。
#Librerias
import ts3
import threading
import datetime
from random import choice, sample
# Data needed #
USER = "thisisafakename"
PASS = "something"
HOST = "111.111.111.111"
PORT = 10011
SID = 1
class BotPrincipal:
def __init__(self, manejador=False):
self.ts3conn = ts3.query.TS3Connection(HOST, PORT)
self.ts3conn.login(client_login_name=USER, client_login_password=PASS)
self.ts3conn.use(sid=SID)
channelToJoin = Bot.GettingChannelID("TestingBot")
try: #Login with a client that is ok
self.ts3conn.clientupdate(client_nickname="The Reader Bot")
self.MyData = self.GettingMyData()
self.MoveUserToChannel(ChannelToJoin, Bot.MyData["client_id"])
self.suscribirEvento("textchannel", ChannelToJoin)
self.ts3conn.on_event = self.manejadorDeEventos
self.ts3conn.recv_in_thread()
except ts3.query.TS3QueryError: #Name already exists, 2nd client connect with this info
self.ts3conn.clientupdate(client_nickname="The Writer Bot")
self.MyData = self.GettingMyData()
self.MoveUserToChannel(ChannelToJoin, Bot.MyData["client_id"])
def __del__(self):
self.ts3conn.close()
def GettingMyData(self):
respuesta = self.ts3conn.whoami()
return respuesta.parsed[0]
def GettingChannelID(self, nombre):
respuesta = self.ts3conn.channelfind(pattern=ts3.escape.TS3Escape.unescape(nombre))
return respuesta.parsed[0]["cid"]
def MoveUserToChannel(self, idCanal, idUsuario, passCanal=None):
self.ts3conn.clientmove(cid=idCanal, clid=idUsuario, cpw=passCanal)
def suscribirEvento(self, tipoEvento, idCanal):
self.ts3conn.servernotifyregister(event=tipoEvento, id_=idCanal)
def SendTextToChannel(self, idCanal, mensajito="Error"):
self.ts3conn.sendtextmessage(targetmode=2, target=idCanal, msg=mensajito) #This works
print("test") #PROBLEM HERE This doesn't work. Why? the line above did work
def manejadorDeEventos(sender, event):
message = event.parsed[0]['msg']
if "test" in message: #This works
Bot.SendTextToChannel(ChannelToJoin, "This is a test") #This works
if __name__ == "__main__":
Bot = BotPrincipal()
threadprincipal = threading.Thread(target=Bot.__init__)
threadprincipal.start()
在使用2个机器人之前,我进行了测试,以在连接时启动SendTextToChannel,并且它可以完美运行,在将文本发送到通道之后,我可以做任何我想做的事情。只有在manejadorDeEventos触发的情况下,才会停止使整个python代码停止的错误
编辑1-试用线程。
我用线程弄乱了时间,得到了2个客户端同时连接的结果。我以某种方式认为其中之一正在阅读事件,而另一个正在回答。该脚本不再自行关闭,这是一个胜利,但是拥有克隆连接看起来并不好。
编辑2-更新代码和问题的实际状态。
我设法使双连接或多或少地处于“精细”状态,但是如果60秒钟内房间什么也没发生,它将断开连接。使用Threading.timer尝试过,但是我无法使其正常工作。整个问题代码已更新。
我想要一个答案,它可以帮助我从频道中读取内容并对其进行回答,而无需为其连接第二个机器人(就像它实际上在做...)。如果答案也对我有帮助,我会给出额外的分数了解每50秒对服务器进行一次查询的简便方法,这样它就不会断开连接。
最佳答案
通过查看the source,recv_in_thread
不会创建一个在接收消息之前一直循环直到退出时间的线程,而是创建一个接收单个消息然后退出的线程:
def recv_in_thread(self):
"""
Calls :meth:`recv` in a thread. This is useful,
if you used ``servernotifyregister`` and you expect to receive events.
"""
thread = threading.Thread(target=self.recv, args=(True,))
thread.start()
return None
这意味着您必须反复调用
recv_in_thread
,而不仅仅是调用一次。我不确定从阅读文档中该怎么做,但是大概是在由接收到的事件触发的任何回调的末尾。我认为这是您的
manejadorDeEventos
方法? (或者也许与servernotifyregister
方法有关?我不确定servernotifyregister
是什么,on_event
是什么……)manejadorDeEventos
提出了两个要点:您已声明
manejadorDeEventos
错误。每个方法都必须将self
作为其第一个参数。当您传递绑定方法(如self.manejadorDeEventos
)时,该绑定的self
对象将作为第一个参数传递,而调用方将传递任何参数。 (对于classmethod
和staticmethod
,有一些例外,但不适用于此处。)而且,在该方法中,几乎可以肯定的是,您应该访问的是self
,而不是全局变量Bot
恰好与self
是同一对象。如果
manejadorDeEventos
实际上是recv_in_thread
的回调,则这里有一个竞争条件:如果在主线程完成on_event
分配之前出现第一条消息,则recv_on_thread
将无法调用您的事件处理程序。 (这恰恰是这种错误,经常会在一百万次中出现一次,当您在部署或发布代码几个月后发现它时,就很难进行调试。)因此,请反转这两行。最后一件事:简要浏览该库的代码有点令人担忧。它看起来好像不是由真正知道自己在做什么的人写的。我上面复制的方法只有3行代码,但是它包含一个无用的
return None
和一个永远无法被Thread
泄漏的join
,更不用说使您调用此方法的整个设计了(并且在收到的每个事件都怪异之后生成一个新线程),并且在没有真正解释的情况下更是如此。如果这是您必须使用的服务的标准客户端库,那么您实际上没有太多选择,但是如果没有,我会考虑寻找其他库。