tdlib / td

Cross-platform library for building Telegram clients
https://core.telegram.org/tdlib
Boost Software License 1.0
7.07k stars 1.44k forks source link

Cannot ctrl+c out of Python-wrapped TDLib program when td_set_log_message_callback verbosity_level > 1 #1690

Closed p-i- closed 3 years ago

p-i- commented 3 years ago

If I enable logging with a verbosity level > 1, I am now unable to terminate a running TDLib program using ctrl+c

I'm Python-wrapping TDLib:

LOGLEVEL = 1  # setting > 1 causes ctrl+c fail-to-exit
log_message_callback_type = CFUNCTYPE(None, c_int, c_char_p)

_td_set_log_message_callback = tdjson.td_set_log_message_callback
_td_set_log_message_callback.restype = None
_td_set_log_message_callback.argtypes = [c_int, log_message_callback_type]

def on_log_message_callback(verbosity_level, message):
    print('🦆', verbosity_level, message)
c_on_log_message_callback = log_message_callback_type(on_log_message_callback)
_td_set_log_message_callback(LOGLEVEL, c_on_log_message_callback)

ret = td_execute({'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 5, '@extra': 1.01234})

My code simply loops on td_receive:

_td_receive = tdjson.td_receive
_td_receive.restype = c_char_p
_td_receive.argtypes = [c_double]

def td_receive():
    result = _td_receive(1.0)
    if result:
        result = json.loads(result.decode('utf-8'))
    return result

while True:
    if event_json := td_receive(timeout=1.0):
        self.process_event(event_json)

Setting LOGLEVEL=1 everything works. I get log messages, although the handler doesn't trigger, which is expected as TDLib isn't emitting any level-1 log messages. I can ctrl+c out fine:

⚠️  empty event_json
TICK
[ 3][t 0][1632898884.285699129][Client.cpp:276][&td_requests]   Begin to wait for updates with timeout 1.000000
[ 3][t 0][1632898885.286751031][Client.cpp:284][&td_requests]   End to wait for updates, returning object 0 (nil)
⚠️  empty event_json
TICK
[ 3][t 0][1632898885.286826133][Client.cpp:276][&td_requests]   Begin to wait for updates with timeout 1.000000
^C[ 3][t 0][1632898886.287183284][Client.cpp:284][&td_requests] End to wait for updates, returning object 0 (nil)
Traceback (most recent call last):
  File "/root/gold/sync/td3-class-logfail.py", line 302, in <module>
    tdclient.arun()
  File "/root/gold/sync/td3-class-logfail.py", line 182, in arun
    if event_json := td_receive(timeout=1.0):
  File "/root/gold/sync/td3-class-logfail.py", line 62, in wrapper
    c_ret = c_func(*c_args) if c_args else c_func()
KeyboardInterrupt

Setting LOGLEVEL to say 3, now my handler also picks up these log messages. But now ctrl+c fails:

⚠️  empty event_json
TICK
[ 3][t 0][1632898668.575134992][Client.cpp:276][&td_requests]   Begin to wait for updates with timeout 1.000000
🦆 3 b'[ 3][t 0][1632898668.575134992][Client.cpp:276][&td_requests]\tBegin to wait for updates with timeout 1.000000\n'
^C^C^C^C^C^C^C^C^C^C^C^C[ 3][t 0][1632898669.575610876][Client.cpp:284][&td_requests]   End to wait for updates, returning object 0 (nil)
Exception ignored on calling ctypes callback function: <function on_log_message_callback at 0x7f0e1c7ff040>
Traceback (most recent call last):
  File "/root/gold/sync/td3-class-logfail.py", line 115, in on_log_message_callback
    def on_log_message_callback(verbosity_level, message):
KeyboardInterrupt:
⚠️  empty event_json
TICK
:

(Had to reboot the box)

I notice I'm getting duplicate log messages. So I try to only get the callback ones:

LOGLEVEL=3
_td_set_log_message_callback(LOGLEVEL, c_on_log_message_callback)
# ret = td_execute({'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 5, '@extra': 1.01234})

Again unable to ctrl+c out. And I notice still duplication of log messages:

⚠️  empty event_json
TICK
[ 3][t 0][1632899896.898507118][Client.cpp:276][&td_requests]   Begin to wait for updates with timeout 1.000000
🦆 3 b'[ 3][t 0][1632899896.898507118][Client.cpp:276][&td_requests]\tBegin to wait for updates with timeout 1.000000\n'

So maybe TDLib remembers the {'@type': 'setLogVerbosityLevel', 'new_verbosity_level': 5 from a previous run. So I set that to 1.

Now I just don't get log messages at all.

It seems something within TDLib is eating / not propagating the ctrl+c signal.

levlam commented 3 years ago

TDLib does nothing with signals. See https://stackoverflow.com/questions/1364173/stopping-python-using-ctrlc.