Untitled
unknown
c_cpp
10 months ago
15 kB
14
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