Update irc_bot.py
This commit is contained in:
parent
0b1f91f5b7
commit
4982a7ecbf
94
irc_bot.py
94
irc_bot.py
|
@ -1,15 +1,16 @@
|
||||||
|
import queue
|
||||||
|
import redis
|
||||||
|
import requests
|
||||||
import socket
|
import socket
|
||||||
|
import ssl
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
import ssl
|
|
||||||
from auth_db import auth_db
|
from auth_db import auth_db
|
||||||
from utils import strip_bbcode, parse_username
|
from utils import strip_bbcode, parse_username
|
||||||
from config import (
|
from config import (
|
||||||
SERVER, PORT, BOTNICK, NICKSERV_USER, NICKSERV_PASS, API_ENDPOINT, API_TOKEN, VERIFY_ENDPOINT,
|
SERVER, PORT, BOTNICK, NICKSERV_USER, NICKSERV_PASS, API_ENDPOINT, API_TOKEN, VERIFY_ENDPOINT,
|
||||||
LOBBY_CHANNEL, MAIN_CHANNEL, ADMIN_CHANNEL, STAFF_CHANNELS,
|
LOBBY_CHANNEL, MAIN_CHANNEL, ADMIN_CHANNEL, STAFF_CHANNELS,
|
||||||
RECONNECT_DELAY, GROUP_NAMES, STAFF_GROUP_IDS, ADMIN_GROUP_IDS, OPER_USER, OPER_PASS
|
RECONNECT_DELAY, GROUP_NAMES, STAFF_GROUP_IDS, ADMIN_GROUP_IDS, OPER_USER, OPER_PASS, REDIS_PW
|
||||||
)
|
)
|
||||||
|
|
||||||
class IRCBot:
|
class IRCBot:
|
||||||
|
@ -18,6 +19,7 @@ class IRCBot:
|
||||||
self.nickname = BOTNICK
|
self.nickname = BOTNICK
|
||||||
self.running = False
|
self.running = False
|
||||||
self.lock = threading.Lock()
|
self.lock = threading.Lock()
|
||||||
|
self.send_queue = queue.Queue()
|
||||||
|
|
||||||
# Connect to IRC server, handle nick conflicts, wait for welcome, and join channel
|
# Connect to IRC server, handle nick conflicts, wait for welcome, and join channel
|
||||||
def connect(self):
|
def connect(self):
|
||||||
|
@ -84,8 +86,13 @@ class IRCBot:
|
||||||
if self.running:
|
if self.running:
|
||||||
return
|
return
|
||||||
self.running = True
|
self.running = True
|
||||||
|
print("[+] Starting IRC listener thread")
|
||||||
threading.Thread(target=self.listen_loop, daemon=True).start()
|
threading.Thread(target=self.listen_loop, daemon=True).start()
|
||||||
print("[+] IRC listener started")
|
print("[+] Starting IRC writer thread")
|
||||||
|
threading.Thread(target=self.writer_loop, daemon=True).start()
|
||||||
|
print("[+] Starting Redis subscriber thread")
|
||||||
|
threading.Thread(target=self.redis_subscribe_loop, daemon=True).start()
|
||||||
|
print("[+] IRC + Redis bridge fully initialized")
|
||||||
|
|
||||||
def listen_loop(self):
|
def listen_loop(self):
|
||||||
while True:
|
while True:
|
||||||
|
@ -107,6 +114,21 @@ class IRCBot:
|
||||||
print(f"[-] IRC error: {e}")
|
print(f"[-] IRC error: {e}")
|
||||||
self.connect()
|
self.connect()
|
||||||
|
|
||||||
|
def redis_subscribe_loop(self):
|
||||||
|
r = redis.Redis(host='localhost', port=6969, password=REDIS_PW, db=0)
|
||||||
|
pubsub = r.pubsub()
|
||||||
|
pubsub.subscribe("chatbox_to_irc")
|
||||||
|
print("[REDIS] Subscribed to chatbox_to_irc")
|
||||||
|
|
||||||
|
for message in pubsub.listen():
|
||||||
|
if message["type"] == "message":
|
||||||
|
try:
|
||||||
|
text = message["data"].decode()
|
||||||
|
print(f"[REDIS] Got message: {text}")
|
||||||
|
self.send_to_channel(text)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[-] Redis IRC dispatch error: {e}")
|
||||||
|
|
||||||
# Handle verification messages from users
|
# Handle verification messages from users
|
||||||
def handle_message(self, line):
|
def handle_message(self, line):
|
||||||
user = parse_username(line)
|
user = parse_username(line)
|
||||||
|
@ -197,25 +219,43 @@ class IRCBot:
|
||||||
|
|
||||||
# Send notice to user
|
# Send notice to user
|
||||||
def send_notice(self, nick, msg):
|
def send_notice(self, nick, msg):
|
||||||
|
if not self.irc or not self.is_connected():
|
||||||
|
print("[-] IRC connection is closed or unavailable.")
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.irc.send(f"NOTICE {nick} :{msg}\r\n".encode("utf-8"))
|
with self.lock: # Ensure thread-safe socket access
|
||||||
|
print(f"[QUEUE] Queuing message: {msg.strip()}")
|
||||||
|
self.send_queue.put(f"NOTICE {nick} :{msg}\r\n")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[-] Notice failed: {e}")
|
print(f"[-] Notice failed: {e}")
|
||||||
|
|
||||||
# Send IRC message to channel
|
# Send IRC message to channel
|
||||||
def send_to_channel(self, msg):
|
def send_to_channel(self, msg):
|
||||||
|
if not self.irc or not self.is_connected():
|
||||||
|
print("[-] IRC connection is closed or unavailable.")
|
||||||
|
return
|
||||||
clean = strip_bbcode(msg).replace("\n", " ").replace("\r", " ")
|
clean = strip_bbcode(msg).replace("\n", " ").replace("\r", " ")
|
||||||
try:
|
try:
|
||||||
self.irc.send(f"PRIVMSG {LOBBY_CHANNEL} :{clean}\r\n".encode("utf-8"))
|
with self.lock: # Ensure thread-safe socket access
|
||||||
|
print(f"[QUEUE] Queuing message: {clean.strip()}")
|
||||||
|
self.send_queue.put(f"PRIVMSG {LOBBY_CHANNEL} :{clean}\r\n")
|
||||||
|
except ssl.SSLEOFError as e:
|
||||||
|
print(f"[SSL ERROR] IRC connection closed: {e}")
|
||||||
|
self.irc = None # Mark socket dead
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[-] Failed to send: {e}")
|
print(f"[-] Failed to send: {e}")
|
||||||
|
|
||||||
# Send IRC commands to server
|
# Send IRC commands to server
|
||||||
def send_raw_command(self, command):
|
def send_raw_command(self, command):
|
||||||
|
if not self.irc or not self.is_connected():
|
||||||
|
print("[-] IRC connection is closed or unavailable.")
|
||||||
|
return
|
||||||
if self.irc:
|
if self.irc:
|
||||||
try:
|
try:
|
||||||
self.irc.send(f"{command}\r\n".encode("utf-8"))
|
with self.lock: # Ensure thread-safe socket access
|
||||||
print(f"[IRC CMD] {command}")
|
print(f"[QUEUE] Queuing message: {command.strip()}")
|
||||||
|
self.send_queue.put(f"{command}\r\n")
|
||||||
|
print(f"[IRC CMD] {command}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[-] Failed to send IRC command: {e}")
|
print(f"[-] Failed to send IRC command: {e}")
|
||||||
|
|
||||||
|
@ -249,4 +289,40 @@ class IRCBot:
|
||||||
user = parse_username(line)
|
user = parse_username(line)
|
||||||
auth_db.remove_verified_user(user)
|
auth_db.remove_verified_user(user)
|
||||||
|
|
||||||
|
# Helper method for checking connection
|
||||||
|
def is_connected(self):
|
||||||
|
try:
|
||||||
|
if not self.irc:
|
||||||
|
return False
|
||||||
|
self.irc.getpeername()
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# IRC writer method to work with queue
|
||||||
|
def writer_loop(self):
|
||||||
|
print("[WRITER] Writer loop started")
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
msg = self.send_queue.get()
|
||||||
|
print(f"[WRITER] Got message from queue: {msg.strip()}")
|
||||||
|
|
||||||
|
if not self.irc or not self.is_connected():
|
||||||
|
print("[-] Writer loop: IRC socket is down, message discarded.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
with self.lock:
|
||||||
|
print(f"[WRITER] Sending to IRC: {msg.strip()}")
|
||||||
|
self.irc.send(msg.encode("utf-8"))
|
||||||
|
|
||||||
|
except (ConnectionResetError, BrokenPipeError, ssl.SSLError) as net_err:
|
||||||
|
print(f"[WRITER NET ERROR] Socket error: {net_err}")
|
||||||
|
self.irc = None
|
||||||
|
time.sleep(RECONNECT_DELAY)
|
||||||
|
continue
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[WRITER ERROR] Unexpected error: {e}")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
bot = IRCBot()
|
bot = IRCBot()
|
||||||
|
|
Loading…
Reference in New Issue