Fix die bot command to actually terminate the program

Specifically, this corrects interrupting the main thread as it was waiting on input() if it is a tty.

Server.die() was changed to bypass the sendq for final IRC messages for a quick termination and to interrupt the main thread with os.kill and SIGINT.

This way the code exits gracefully and properly tears the connection down.
This commit is contained in:
Jordyn 2026-03-14 18:55:53 -05:00
commit e682656fe5

29
main.py
View file

@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import sys
import socket import socket
import signal import signal
import threading import threading
@ -61,17 +62,24 @@ class Server():
# Gracefully shuts the server down # Gracefully shuts the server down
def die(self, msg = "Python3 Server() outta here!"): def die(self, msg = "Python3 Server() outta here!"):
print("[SERVER/MAINTHREAD] Sending PART and QUIT") # NOOP if we're in the process of going down
if self._going_down.is_set():
return
print("[SERVER] Sending PART and QUIT")
# Part all of our channels with a cool message, then quit # Part all of our channels with a cool message, then quit
for channel in self.channels: for channel in self.channels:
self._send_q.put(f"PART {channel} : {msg}\r\n".encode()) self.sock.send(f"PART {channel} : {msg}\r\n".encode())
self._send_q.put(f"QUIT : {msg}\r\n".encode()) self.sock.send(f"QUIT : {msg}\r\n".encode())
print("[SERVER/MAINTHREAD] Signaling threads to quit!") print("[SERVER] Signaling threads to quit!")
# Signal threads to quit # Signal threads to quit
self._going_down.set() self._going_down.set()
print("[SERVER] Signaling main thread to quit!")
os.kill(os.getpid(), signal.SIGINT)
# Sends a message to a target (user/channel) # Sends a message to a target (user/channel)
# The bot does NOT have to be a channel to send a message, but most channels # The bot does NOT have to be a channel to send a message, but most channels
# disallow messages from non-JOIN'ed users. # disallow messages from non-JOIN'ed users.
@ -118,8 +126,8 @@ class Server():
self.sock.send(msg) self.sock.send(msg)
except BrokenPipeError: except BrokenPipeError:
# Can't use die because we have no connection... just quit I suppose # Can't use die because we have no connection... just quit I suppose
self._going_down.set() print("[SENDTHREAD] Quitting due to BrokenPipeError!")
raise SystemExit(1) break
print("[SENDTHREAD] Quitting due to thread condition!") print("[SENDTHREAD] Quitting due to thread condition!")
@ -278,9 +286,8 @@ class Server():
self.privmsg(msg["target_channel"], f"Bot PID: {os.getpid()}") self.privmsg(msg["target_channel"], f"Bot PID: {os.getpid()}")
# Kill server # Kill server
if "die" in msg["params"][-1]: if "die" in msg["params"][-1]:
# Tear down server
self.die() self.die()
raise SystemExit(0)
# Send flooding statistics # Send flooding statistics
if "floodstats" in msg["params"][-1]: if "floodstats" in msg["params"][-1]:
self.privmsg(msg["target_channel"], f"Sleep Time: {self._msg_time}") self.privmsg(msg["target_channel"], f"Sleep Time: {self._msg_time}")
@ -351,13 +358,13 @@ if __name__ == "__main__":
# These bypass the send queue # These bypass the send queue
while True: while True:
try: try:
if sys.stdin.isatty():
rawcmd = input() rawcmd = input()
serv.sock.send(f"{rawcmd}\r\n".encode()) serv.sock.send(f"{rawcmd}\r\n".encode())
else:
serv._going_down.wait()
except KeyboardInterrupt: except KeyboardInterrupt:
print("[MAINTHREAD] Interrupt receieved... server going down!") print("[MAINTHREAD] Interrupt receieved... server going down!")
print("[MAINTHREAD] Could take up to 60 seconds for socket timeout!") print("[MAINTHREAD] Could take up to 60 seconds for socket timeout!")
serv.die() serv.die()
raise SystemExit(0) raise SystemExit(0)
except EOFError:
while True:
serv._going_down.wait()