Untitled
unknown
c_cpp
2 months ago
15 kB
7
Indexable
~/x1bncwn $ cat ircbot.8.pike #!/data/data/com.termux/files/usr/local/bin/pike 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"; port = 6667; nick = "PikeBot" + random(1000); realname = "Pike IRC Bot"; channels = ({"#pike-test"}); sasl_user = "YourNickServUsername"; // Replace if needed sasl_pass = "YourNickServPassword"; // Replace if needed write("BotConfig: Initialized successfully\n"); } } class IRCBot { BotConfig config; Stdio.File socket; array(Thread) worker_threads; Queue message_queue; Mutex queue_mutex; Mutex socket_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_mutex = Mutex(); socket = 0; worker_threads = ({}); 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); 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); }; if (err) { write("Error: Failed to send NICK/USER commands: %O\n", err); cleanup(); return; } write("IRCBot: NICK/USER commands sent\n"); write("IRCBot: Waiting for connection completion\n"); int timeout = 600; // 60 seconds with 0.1s polling while (timeout > 0 && connected == 0) { Pike.DefaultBackend(0.1); // Slightly slower but still responsive timeout--; if (timeout % 100 == 0) write("IRCBot: Waiting for 001, %d seconds remaining\n", timeout / 10); } 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); } socket->write("PRIVMSG #pike-test :Bot joined successfully!\r\n"); write("IRCBot: Sent test message to #pike-test\n"); }; if (err) { write("Error: Failed to join channels: %O\n", err); cleanup(); return; } write("IRCBot: Connect fully completed\n"); } void start_threads() { int num_workers = 4; // Thread pool size for (int i = 0; i < num_workers; i++) { worker_threads += ({ Thread(process_messages) }); write("IRCBot: Started worker thread %d\n", i + 1); } } 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; MutexKey lock = queue_mutex->lock(); if (lock) { for (int i = 0; i < sizeof(worker_threads); i++) { message_queue->write(-1); // Signal workers to stop } destruct(lock); } } protected void read_callback(mixed id, string data) { if (data && data != "") { buffer += data; write("Main: Read buffer: %s\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]; if (line && line != "") { array(string) parts = line / " "; if (sizeof(parts) >= 2 && parts[1] == "372") { write("Main: Suppressing MOTD: %s\n", line); continue; // Skip MOTD } 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); } } buffer = lines[-1]; destruct(lock); } else { write("Main: Failed to acquire queue lock\n"); } } else { write("Main: Read empty buffer, errno: %d\n", socket->errno()); } } 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 %O: Worker thread started\n", this_thread()); while (connected >= 0) { mixed msg; MutexKey lock = queue_mutex->lock(); if (lock) { msg = message_queue->read(); destruct(lock); } else { write("WorkerThread %O: Failed to acquire queue lock\n", this_thread()); sleep(0.1); continue; } if (msg == -1) { write("WorkerThread %O: Worker thread shutting down\n", this_thread()); break; } if (!msg) { sleep(0.1); continue; } string line = msg; write("WorkerThread %O: Processing RAW: %s\n", this_thread(), line); array(string) parts = line / " "; if (sizeof(parts) < 2) { write("WorkerThread %O: Skipping malformed line\n", this_thread()); continue; } string prefix = parts[0]; string cmd = parts[1]; if (cmd == "PING") { MutexKey lock = socket_mutex->lock(); if (lock) { socket->write("PONG %s\r\n", parts[2..] * " "); write("WorkerThread %O: Responded to PING\n", this_thread()); destruct(lock); } } else if (cmd == "PRIVMSG" && sizeof(parts) >= 4) { string channel = 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 %O: Received PRIVMSG from <%s> in %s: %s\n", this_thread(), nick, channel, message)); if (has_prefix(message, "!hello")) { MutexKey lock = socket_mutex->lock(); if (lock) { mixed err = catch { socket->write("PRIVMSG %s :Hello %s!\r\n", channel, nick); write("WorkerThread %O: Sent hello response to %s\n", this_thread(), nick); }; if (err) { write("WorkerThread %O: Error sending hello response: %O\n", this_thread(), err); } destruct(lock); } } if (has_prefix(message, "!quit")) { write("WorkerThread %O: Received quit command, shutting down\n", this_thread()); MutexKey lock = socket_mutex->lock(); if (lock) { socket->write("QUIT :Bot shutting down\r\n"); connected = -1; destruct(lock); break; } } } } write("WorkerThread %O: Worker thread exiting\n", this_thread()); } protected void _destruct() { if (connected > 0 && socket) { // Avoid null check crash socket->write("QUIT :Bot shutting down\r\n"); write("Main: Sent QUIT on destruct\n"); sleep(1); // Give time to send } 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(); int runtime = 300; // Run for 5 minutes while (runtime > 0 && bot->connected >= 0) { Pike.DefaultBackend(0.1); // Adjusted polling runtime--; if (runtime % 10 == 0) write("Main: Running, %d seconds remaining\n", runtime); } write("Main: Bot shutting down\n"); bot->_destruct(); return 0; }
Editor is loading...
Leave a Comment