Untitled
unknown
c_cpp
2 months ago
13 kB
8
Indexable
import Stdio; import Thread; class BotConfig { string host; int port; string nick; string realname; array(string) channels; string sasl_user; string sasl_pass; void create() { write("BotConfig: Initializing\n"); host = "irc.deft.com"; // Switch to "irc.libera.chat" if needed port = 6667; nick = "PikeBot" + random(1000); realname = "Pike IRC Bot"; channels = ({"#pike-test"}); // Use "#test" for irc.libera.chat sasl_user = "YourNickServUsername"; // Replace if needed sasl_pass = "YourNickServPassword"; // Replace if needed write("BotConfig: Initialized successfully\n"); } } class IRCBot { BotConfig config; Stdio.File socket; Thread worker_thread; Queue message_queue; Mutex queue_mutex; int connected; // 0 = not connected, 1 = connected, -1 = shutting down string buffer; void create(BotConfig _config) { write("IRCBot: Starting create\n"); if (!_config) { write("Error: No config provided\n"); return; } config = _config; connected = 0; message_queue = Queue(); queue_mutex = Mutex(); socket = 0; worker_thread = 0; buffer = ""; write("IRCBot: Config assigned\n"); connect(); write("IRCBot: Create completed\n"); } protected void connect() { write("IRCBot: Starting connect\n"); socket = Stdio.File(); if (!socket) { write("Error: Failed to create socket\n"); return; } write("IRCBot: Attempting connection to %s:%d\n", config->host, config->port); mixed err = catch { if (!socket->connect(config->host, config->port)) { write("Error: Failed to connect to IRC server, errno: %d\n", socket->errno()); socket->close(); socket = 0; return; } }; if (err) { write("Error: Connection attempt failed: %O\n", err); socket->close(); socket = 0; return; } write("IRCBot: Socket connection succeeded\n"); socket->set_nonblocking(read_callback, write_callback, close_callback); socket->set_keepalive(1); write("IRCBot: Socket connected, sending initial commands\n"); err = catch { socket->write("NICK %s\r\n", config->nick); socket->write("USER %s 0 * :%s\r\n", config->nick, config->realname); socket->write("MODE %s +i\r\n", config->nick); }; if (err) { write("Error: Failed to send initial commands: %O\n", err); cleanup(); return; } write("IRCBot: Initial commands sent\n"); write("IRCBot: Waiting for connection completion\n"); int timeout = 60; while (timeout > 0 && connected == 0) { Pike.DefaultBackend(0.1); timeout--; } if (connected != 1) { write("Error: Connection timeout waiting for 001\n"); cleanup(); return; } write("IRCBot: Joining channels\n"); err = catch { foreach(config->channels; ; string channel) { socket->write("JOIN %s\r\n", channel); write("IRCBot: Sent JOIN for %s\n", channel); } sleep(2); socket->write("WHO #pike-test\r\n"); write("IRCBot: Sent WHO #pike-test to confirm join\n"); socket->write("NAMES #pike-test\r\n"); write("IRCBot: Sent NAMES #pike-test to refresh state\n"); socket->write("PRIVMSG #pike-test :Bot joined successfully!\r\n"); write("IRCBot: Sent test message to #pike-test\n"); socket->write("PRIVMSG %s :Self-test message\r\n", config->nick); write("IRCBot: Sent self-test PRIVMSG\n"); }; if (err) { write("Error: Failed to join channels or send test: %O\n", err); cleanup(); return; } write("IRCBot: Connect fully completed\n"); } void start_threads() { worker_thread = Thread(process_messages); write("IRCBot: Worker thread started\n"); } protected void cleanup() { if (socket && socket->is_open()) { socket->write("QUIT :Bot shutting down\r\n"); sleep(1); socket->close(); socket = 0; write("Main: Socket closed cleanly\n"); } connected = -1; } protected void read_callback(mixed id, string data) { write("Main: read_callback triggered with data length: %d\n", sizeof(data)); if (!socket || !socket->is_open()) { write("Main: Socket is closed or invalid in read_callback\n"); connected = -1; return; } write("Main: Socket state - is_open: %d, errno: %d\n", socket->is_open(), socket->errno()); if (data && data != "") { buffer += data; write("Main: Read raw buffer: %O\n", data); array(string) lines = buffer / "\n"; MutexKey lock = queue_mutex->lock(); if (lock) { for (int i = 0; i < sizeof(lines) - 1; i++) { string line = lines[i]; write("Main: Processing line: %s\n", line); if (line && line != "" && line[-1] == '\r') { line = line[..sizeof(line)-2]; if (connected == 0 && has_value(line, "001")) { write("IRCBot: Connection completed (001 received) in read_callback\n"); connected = 1; } message_queue->write(line); write("Main: Queued message: %s\n", line); } else { write("Main: Incomplete line skipped: %s\n", line); } } buffer = lines[-1]; write("Main: Remaining buffer: %s\n", buffer); destruct(lock); } else { write("Main: Failed to acquire queue lock\n"); } } else { write("Main: Read empty buffer\n"); } } protected void write_callback(mixed id) { write("Main: Write callback triggered\n"); } protected void close_callback(mixed id) { write("Main: Socket closed by server\n"); connected = -1; cleanup(); } protected void process_messages() { write("WorkerThread: Worker thread started\n"); int heartbeat = 0; while (connected >= 0) { heartbeat++; write("WorkerThread: Loop iteration, connected=%d, queue_size=%d\n", connected, message_queue->size()); if (heartbeat % 10 == 0) { write("WorkerThread: Heartbeat, connected=%d\n", connected); if (socket && socket->is_open()) { socket->write("PRIVMSG #pike-test :Heartbeat check %d\r\n", heartbeat / 10); write("WorkerThread: Sent heartbeat message\n"); socket->write("PING :irc.deft.com\r\n"); write("WorkerThread: Sent PING to keep connection alive\n"); } else { write("WorkerThread: Socket invalid during heartbeat\n"); connected = -1; break; } } // Manual socket read to bypass read_callback issues if (socket && socket->is_open()) { string data = socket->read(1024, 1); // Non-blocking read if (data && data != "") { write("WorkerThread: Manual read data: %O\n", data); buffer += data; array(string) lines = buffer / "\n"; MutexKey lock = queue_mutex->lock(); if (lock) { for (int i = 0; i < sizeof(lines) - 1; i++) { string line = lines[i]; if (line && line != "" && line[-1] == '\r') { line = line[..sizeof(line)-2]; message_queue->write(line); write("WorkerThread: Queued manual message: %s\n", line); } } buffer = lines[-1]; destruct(lock); } } } mixed msg; MutexKey lock = queue_mutex->lock(); if (lock) { msg = message_queue->read(); destruct(lock); } else { write("WorkerThread: Failed to acquire queue lock\n"); sleep(1); continue; } if (msg == -1) { write("WorkerThread: Worker thread shutting down\n"); break; } if (!msg) { sleep(0.1); continue; } string line = msg; write("WorkerThread: Processing RAW: %s\n", line); array(string) parts = line / " "; if (sizeof(parts) < 2) { write("WorkerThread: Skipping malformed line\n"); continue; } string prefix = parts[0]; string cmd = parts[1]; write("WorkerThread: Command received: %s\n", cmd); if (cmd == "PING") { socket->write("PONG %s\r\n", parts[2..] * " "); write("WorkerThread: Responded to PING\n"); } else if (cmd == "PONG") { write("WorkerThread: Received PONG from server\n"); } else if (cmd == "PRIVMSG" && sizeof(parts) >= 4) { string target = parts[2]; string message = parts[3..] * " "; if (message[0] == ':') message = message[1..]; if (prefix[0] == ':') prefix = prefix[1..]; string nick = (prefix / "!")[0]; write(sprintf("WorkerThread: Received PRIVMSG from <%s> to %s: %s\n", nick, target, message)); if (target == config->nick) { write("WorkerThread: Direct message received: %s\n", message); if (has_value(message, "VERSION")) { socket->write("NOTICE %s :\001VERSION PikeBot 1.0\001\r\n", nick); write("WorkerThread: Sent VERSION response to %s\n", nick); } } else if (target == "#pike-test") { if (has_prefix(message, "!hello")) { mixed err = catch { socket->write("PRIVMSG %s :Hello %s!\r\n", target, nick); write("WorkerThread: Sent hello response to %s\n", nick); }; if (err) { write("WorkerThread: Error sending hello response: %O\n", err); } } if (has_prefix(message, "!quit")) { write("WorkerThread: Received quit command, shutting down\n"); socket->write("QUIT :Bot shutting down\r\n"); connected = -1; break; } } } else if (cmd == "353" || cmd == "366") { write("WorkerThread: Channel join confirmation: %s\n", line); } else if (cmd == "352" || cmd == "315") { write("WorkerThread: WHO response: %s\n", line); } else if (cmd == "JOIN" && prefix[0] == ':') { string nick = (prefix / "!")[0]; write("WorkerThread: %s joined %s\n", nick, parts[2]); } } write("WorkerThread: Worker thread exited\n"); } protected void _destruct() { if (connected > 0 && socket && socket->is_open()) { socket->write("QUIT :Bot shutting down\r\n"); write("Main: Sent QUIT on destruct\n"); } if (worker_thread) { MutexKey lock = queue_mutex->lock(); if (lock) { message_queue->write(-1); destruct(lock); } } cleanup(); } } int main() { write("Main: Starting\n"); BotConfig config = BotConfig(); if (!config) { write("Error: Failed to create config\n"); return 1; } write("Main: Config created\n"); IRCBot bot = IRCBot(config); if (!bot) { write("Error: Failed to create bot\n"); return 1; } write("Main: Bot created\n"); bot->start_threads(); while (bot->connected >= 0) { Pike.DefaultBackend(0.1); write("Main: Running, connected=%d\n", bot->connected); } write("Main: Bot shutting down\n"); bot->_destruct(); return 0; }
Editor is loading...
Leave a Comment