Untitled

 avatar
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