我正在尝试用 Python 编写一个 Hexchat 插件,它将启动一个服务器,然后使用 DBus 和 python-dbus 库与它进行通信。一切正常,直到我尝试卸载插件或关闭 Hexchat(卸载所有插件)。应用程序冻结。如果我不使用 DBus 调用任何方法,则不会发生这种情况。
我试图查明问题,所以我创建了一个最小的示例:
服务器.py
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib
class EchoService(dbus.service.Object):
def __init__(self):
DBusGMainLoop(set_as_default=True)
self.loop = GLib.MainLoop()
bus_name = dbus.service.BusName(name='com.skontar.Echo', bus=dbus.SessionBus())
super().__init__(conn=None, object_path='/com/skontar/Echo', bus_name=bus_name)
def run(self):
self.loop.run()
@dbus.service.method(dbus_interface='com.skontar.Echo', in_signature='', out_signature='')
def quit(self):
self.loop.quit()
@dbus.service.method(dbus_interface='com.skontar.Echo', in_signature='s', out_signature='s')
def echo(self, text):
print(text)
return 'ACK'
EchoService().run()
dbus_plugin_unload_test.py
import subprocess
import time
import dbus
import hexchat
__module_name__ = 'dbus_plugin_unload_test'
__module_description__ = 'TBD'
__module_version__ = '1.0'
def get_dbus_interface():
session_bus = dbus.SessionBus()
dbus_object = session_bus.get_object(bus_name='com.skontar.Echo',
object_path='/com/skontar/Echo')
interface = dbus.Interface(object=dbus_object, dbus_interface='com.skontar.Echo')
return interface
def unload(userdata):
hexchat.prnt('Unloading {}, version {}'.format(__module_name__, __module_version__))
global interface
interface.quit()
time.sleep(1)
# raise Exception
hexchat.prnt('Loading {}, version {}'.format(__module_name__, __module_version__))
subprocess.Popen('python3 /home/skontar/Python/Examples/DBus/server.py', shell=True)
time.sleep(1)
interface = get_dbus_interface()
time.sleep(1)
interface.echo('TEST')
hexchat.hook_unload(unload)
在这个例子中,一切正常。当我尝试卸载插件或关闭 Hexchat 时,服务器退出(因此.quit
调用有效),但 Hexchat 挂起。
如果我将两者都 注释掉interface.echo('TEST')
并且interface.quit()
它卸载得很好,但插件也没有做任何有用的事情。我还发现,如果我raise Exception
在卸载回调结束时,一切都“正确”关闭,没有挂起。
我在想也许我应该做一些 DBus 清理?还是我错过了 Hexchat 插件系统的一些细微差别?如果我在插件系统之外尝试使用常规 Python 代码,服务器和客户端都可以正常退出。