python3(Bot)脚本停止工作

2024-06-06 11:07:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试连接到一个TeamSpeak服务器,使用QueryServer来创建一个bot。我已经听取了this thread的建议,但是我仍然需要帮助。在

这是我正在使用的The TeamSpeak API。在

在编辑之前,这是我的脚本中实际发生的事情的摘要(1个连接):

  1. 它连接在一起。在
  2. 它检查通道ID(以及它自己的客户端ID)
  3. 它加入频道,开始阅读所有内容
  4. 如果有人说了一个特定的命令,它执行该命令,然后断开连接。在

我怎么才能让它不断开呢?如何使脚本保持在“等待”状态,以便在执行命令后继续读取?在

我使用的是python3.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个bot之前,我测试了在SendTextToChannel连接并且工作正常时启动它,允许我在它将文本发送到频道后执行任何我想做的事情。使整个python代码停止的bug只有在由manejadorDeEventos触发时才会发生

编辑1-试验线程。
我在线程方面把它搞砸了,结果是两个客户机同时连接。不知怎么的,我觉得他们中的一个在读事件,另一个在回答。脚本不再自动关闭,这是一个胜利,但是有一个克隆连接看起来不太好。在

编辑2-更新的代码和问题的实际状态。
我设法使双重连接工作或多或少“好”,但它断开,如果在房间里什么事都没有发生60秒。尝试使用线程.计时器但我无法让它发挥作用。整个问题代码已经更新。在

我想要一个答案,帮助我既从频道阅读,又回答它,而不需要为它连接第二个机器人(就像它实际上在做…),我会给额外的分数,如果答案也帮助我理解一个简单的方法,每50秒向服务器查询一次,这样它就不会断开连接。在


Tags: theimportselfclientevent编辑defbot
1条回答
网友
1楼 · 发布于 2024-06-06 11:07:09

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对象将作为第一个参数传递,在调用方传递的任何参数之前。(对于classmethods和staticmethods也有例外,但这些在这里不适用。)此外,在该方法中,您几乎可以肯定地访问self,而不是一个全局变量Bot,它恰好与self是同一个对象。在
  • 如果manejadorDeEventos实际上是recv_in_thread的回调,那么这里有一个竞争条件:如果第一条消息在主线程完成on_event分配之前到达,则recv_on_thread将无法调用事件处理程序。(这正是一种百里挑一的bug,当您在部署或发布代码数月后发现它时,调试会非常痛苦。)因此,请颠倒这两行代码。在

最后一件事:简单地看一下这个库的代码有点令人担忧。它看起来不像是一个真正知道自己在做什么的人写的。我在上面复制的方法只有3行代码,但它包含了一个无用的return None和一个永远不会join的泄漏{},更不用说,在接收到每个事件后让您调用此方法(并生成一个新线程)的整个设计都很奇怪,而且考虑到它没有得到真正的解释。如果这是您必须使用的服务的标准客户机库,那么您在这方面确实没有太多选择,但如果不是,我会考虑寻找另一个库。在

相关问题 更多 >