From 74fcc85514c9bd0a4a8dfbd909d9555a9f1ee5b8 Mon Sep 17 00:00:00 2001 From: pk910 Date: Thu, 28 Jul 2011 01:54:44 +0200 Subject: [PATCH] continued BotLoader, added ModManager.class.php & timers --- BotLoader/BotLoader.class.php | 135 +++++++++++++++++++++++++++++++++- Bots/ExampleBot.class.php | 6 +- Bots/ModManager.class.php | 117 +++++++++++++++++++++++++++++ Tools/timer.inc.php | 53 +++++++++++++ Uplink/Numerics.class.php | 16 +++- Uplink/P10Formatter.class.php | 1 + Uplink/Uplink.class.php | 21 +++++- main.php | 28 +++++++ 8 files changed, 372 insertions(+), 5 deletions(-) create mode 100644 Bots/ModManager.class.php create mode 100644 Tools/timer.inc.php diff --git a/BotLoader/BotLoader.class.php b/BotLoader/BotLoader.class.php index df06eea..b5dc87b 100644 --- a/BotLoader/BotLoader.class.php +++ b/BotLoader/BotLoader.class.php @@ -29,16 +29,22 @@ require_once("Bot.class.php"); require_once("saxdb.class.php"); class BotLoader { + const BOT_DIR = "Bots"; + const TMP_DIR = "tmp"; private $uplink; private $saxdb; private $botdb; private $loadedBots = array(); + private $botDatabases = array(); + private static $botloader; public function __construct($uplink) { $this->uplink = $uplink; $this->saxdb = new saxdb(); $this->saxdb->loadDB("php_p10.db"); $this->botdb = $this->saxdb->getSection("BotLoader"); + self::$botloader = $this; + timer(60*10, array($this, "autosave"), array()); } public function loadBots() { @@ -51,14 +57,141 @@ class BotLoader { } } + public function unloadBots() { + foreach($this->loadedBots as $name => $bot) { + $this->unloadBot($name, false); + } + } + + public function save() { + $this->saxdb->writeDB("php_p10.db"); + } + + public function autosave() { + foreach($this->loadedBots as $name => $bot) { + if(array_key_exists(strtolower($name), $this->botDatabases)) { + $db = $bot->writeDB(); + $this->saxdb->setSection($this->botDatabases[strtolower($name)],$db); + } + } + $this->save(); + timer(60*10, array($this, "autosave"), array()); + } + + public function loop() { + foreach($this->loadedBots as $name => $bot) { + $bot->loop(); + } + } + private function loadBot($name, $botfile) { - if(array_key_exists($name, $this->loadedBots)) return; + if(array_key_exists(strtolower($name), $this->loadedBots)) return false; //load bot + $bot = $this->loadClass($botfile, $name); + if(!$bot) return false; + $bot->load($this->uplink); + $this->loadedBots[strtolower($name)] = $bot; if(!array_key_exists($name, $this->botdb["bots"])) { $this->botdb["bots"][$name] = $botfile; } } + private function unloadBot($name, $delete = true) { + if(!(array_key_exists(strtolower($name), $this->loadedBots))) return false; + //unload bot + $bot = $this->loadedBots[strtolower($name)]; + if(array_key_exists(strtolower($name), $this->botDatabases)) { + $db = $bot->writeDB(); + $this->saxdb->setSection($this->botDatabases[strtolower($name)],$db); + unset($this->botDatabases[strtolower($name)]); + } + ModCMD::unbindBot($bot); + $bot->unload(false); + unset($this->loadedBots[strtolower($name)]); + if(array_key_exists($name, $this->botdb["bots"]) && $delete) { + unset($this->botdb["bots"][$name]); + } + } + + private function rehashBot($name) { + if(!(array_key_exists(strtolower($name), $this->loadedBots))) return false; + //rehash bot + $bot = $this->loadedBots[strtolower($name)]; + if(array_key_exists(strtolower($name), $this->botDatabases)) { + $db = $bot->writeDB(); + $this->saxdb->setSection($this->botDatabases[strtolower($name)],$db); + unset($this->botDatabases[strtolower($name)]); + } + ModCMD::unbindBot($bot); + $data = $bot->unload(true); + unset($this->loadedBots[strtolower($name)]); + //ok bot is unloaded... load it again... + $bot = $this->loadClass($botfile, $name); + if(!$bot) return false; + $bot->load($this->uplink, $data); + $this->loadedBots[strtolower($name)] = $bot; + } + + private function listLoadedBots() { + return $this->loadedBots; + } + + private function addDBsection($bot, $section) { + if(!is_a($bot, "Bot")) return false; + $name = null; + foreach($this->loadedBots as $botname => $cbot) { + if($cbot === $bot) { + $name = $botname; + break; + } + } + if($name == null) return false; + if(array_key_exists(strtolower($name), $this->botDatabases)) { + return false; + } + $this->botDatabases[strtolower($name)] = $section; + $bot->readDB($this->saxdb->getSection($section)); + } + + private function loadClass($file, $classprefix) { + $dir = self::BOT_DIR; + $tmp = self::TMP_DIR; + $maincode=file_get_contents($dir."/".$file); + if(!$maincode) return; + $class = rand(10000,99999); + while(class_exists("bot_".$classprefix."_".$class)) { + $class = rand(10000,99999); + } + $maincode = str_replace('{$_NAME}', "module_".$classprefix."_".$class, $maincode); + $fp = fopen($tmp."/modules_".$classprefix."_".$class.".tmp.php", 'w'); + fwrite($fp, $maincode); + fclose($fp); + include($tmp."/modules_".$classprefix."_".$class.".tmp.php"); + $classname = "module_".$classprefix."_".$class; + $newclass = new $classname(); + unlink($tmp."/modules_".$classprefix."_".$class.".tmp.php"); + return $newclass; + } + + public static function load($name, $botfile) { + return self::$botloader->loadBot($name, $botfile); + } + + public static function unload($name) { + return self::$botloader->unloadBot($name); + } + + public static function rehash($name) { + return self::$botloader->rehashBot($name); + } + + public static function listBots() { + return self::$botloader->listLoadedBots(); + } + + public static function registerDB($bot, $name) { + return self::$botloader->addDBsection($bot, $name); + } } ?> \ No newline at end of file diff --git a/Bots/ExampleBot.class.php b/Bots/ExampleBot.class.php index 53e248d..299f151 100644 --- a/Bots/ExampleBot.class.php +++ b/Bots/ExampleBot.class.php @@ -73,7 +73,11 @@ class {$_NAME} extends Bot { // {$_NAME} will be replaced by our script later ; } public function unload($rehash = false) { //this function is triggered, when the Bot is unloaded... If it's just a rehash the return value of this method is passed to $old in the load method. - return $this->example_bot; + if($rehash) { + return $this->example_bot; + } else { + $this->uplink->delUser($this->example_bot, "Bye."); + } } public function recive_privmsg($user, $channel, $message) { diff --git a/Bots/ModManager.class.php b/Bots/ModManager.class.php new file mode 100644 index 0000000..4eac48c --- /dev/null +++ b/Bots/ModManager.class.php @@ -0,0 +1,117 @@ +uplink = $uplink; + if(!$old) { + $nick = "ModuleMan"; + $ident = "modman"; + $host = "Services.WebGamesNet.net"; + $ip = "0::0"; + $realname = "Module Manager"; + $modes = "ioknISD"; + $this->modman = $this->uplink->addUser($nick,$ident,$host,$ip,$modes,$realname); + if(is_a($this->modman, "P10_User")) { + $this->uplink->join($this->modman, "#opers", (P10_Channel::USERPRIV_OPED | P10_Channel::USERPRIV_VOICE)); + $this->uplink->join($this->modman, "#dev", P10_Channel::USERPRIV_VOICE); + } + } else { + $this->modman = $old; + } + + ModCMD::bind($this, BIND_PRIVMSG, "recive_privmsg"); + ModCMD::bind($this, BIND_QUIT, "recive_quit"); + } + + public function unload($rehash = false) { + if($rehash) { + return $this->modman; + } else { + $this->uplink->delUser($this->modman, "Bye."); + } + } + + function recive_privmsg($user, $channel, $message) { + if(!$user->getModes()->hasMode('o')) return 0; + $exp=explode(" ",$message); + switch (strtolower($exp[0])) { + case "~loadmod": + if(BotLoader::load($exp[1],$exp[2])) { + $this->uplink->privmsg($this->modman, $channel, "done."); + } else { + $this->uplink->privmsg($this->modman, $channel, "error."); + } + break; + case "~unloadmod": + if(BotLoader::unload($exp[1])) { + $this->uplink->privmsg($this->modman, $channel, "done."); + } else { + $this->uplink->privmsg($this->modman, $channel, "error."); + } + break; + case "~rehash": + if(BotLoader::rehash($exp[1])) { + $this->uplink->privmsg($this->modman, $channel, "done."); + } else { + $this->uplink->privmsg($this->modman, $channel, "error."); + } + break; + case "~debug": + $exp=explode(" ",$message,2); + ob_start(); + $ret = eval($exp[1]); + $out = ob_get_contents(); + ob_end_clean(); + $lines = explode("\n",$out); + for($i=0;$iuplink->privmsg($this->modman, $channel, $lines[$i]); + } + } + $lines = explode("\n",$ret); + for($i=0;$iuplink->privmsg($this->modman, $channel, $lines[$i]); + } + } + break; + } + } + + function recive_quit($user, $reason) { + if($user === $this->modman) { + $this->load($this->uplink); + } + } +} + +?> \ No newline at end of file diff --git a/Tools/timer.inc.php b/Tools/timer.inc.php new file mode 100644 index 0000000..57c6318 --- /dev/null +++ b/Tools/timer.inc.php @@ -0,0 +1,53 @@ + $timer) { + if(($timer['expire'] - 0.00019) <= $mtime) { //we expire a timer 0,19 ms before (to reduce timer desyncs) + if((is_array($timer['function']) && method_exists($timer['function'][0],$timer['function'][1])) || (!is_array($timer['function']) && function_exists($timer['function']))) { + call_user_func_array($timer['function'],$timer['params']); + } + $ret = true; + unset($timers[$id]); + } + } + return $ret; +} + +function timer($seconds,$command,$parameter) { + global $timers; + $new['expire'] = microtime(true) + $seconds; + $new['function'] = $command; + $new['params'] = $parameter; + while(isset($timers[$timers['id']])|| !isset($timers['id'])) { + $timers['id']++; + if($timers['id'] > 9999999) $timers['id'] = 0; + } + $timers[$timers['id']] = $new; + return $timers['id']; +} + +function utimer($seconds,$command,$parameter) { + global $timers; + $new['expire'] = microtime(true) + ($seconds / 1000); + $new['function'] = $command; + $new['params'] = $parameter; + while($timers[$timers['id']] || !$timers['id']) { + $timers['id']++; + if($timers['id'] > 9999999) $timers['id'] = 0; + } + $timers[$timers['id']] = $new; + return $timers['id']; +} + +function kill_timer($id) { + global $timers; + unset($timers[$id]); +} + +$timers['id']=0; + +?> \ No newline at end of file diff --git a/Uplink/Numerics.class.php b/Uplink/Numerics.class.php index 2af7132..7b6bee1 100644 --- a/Uplink/Numerics.class.php +++ b/Uplink/Numerics.class.php @@ -137,14 +137,25 @@ class Numerics { $ipv6 = array(); $ip = explode(":",$ip); $last_zero = false; $zero_sequence = 0; $biggest_zero_sequence = 0; $max_start = -1; - foreach($ip as $i => $v) { + $i = 0; + foreach($ip as $v) { if($v == "") { $skipBlocks = (8 - count($ip)); for($j = 0; $j < $skipBlocks; $j++) { $ipv6[$i+$j] = "_"; } $max_start = $i; - $biggest_zero_sequence = $skipBlocks; + if($last_zero) { + $zero_sequence += $skipBlocks; + } else { + $last_zero = true; + $zero_sequence = $skipBlocks; + } + $i+=$skipBlocks; + if($zero_sequence > $biggest_zero_sequence) { + $biggest_zero_sequence = $zero_sequence; + $max_start = $i-($zero_sequence-1); + } } else { $value = hexdec($v); if($value == 0) { @@ -163,6 +174,7 @@ class Numerics { $ipv6[$i] = self::intToNum($value,3); $last_zero = false; } + $i++; } } $ip = ""; diff --git a/Uplink/P10Formatter.class.php b/Uplink/P10Formatter.class.php index e4235f4..05cb8e3 100644 --- a/Uplink/P10Formatter.class.php +++ b/Uplink/P10Formatter.class.php @@ -59,6 +59,7 @@ class P10Formatter { "330" => "{num} 330 %s %s %s :is logged in as", "318" => "{num} 318 %s %s :End of /WHOIS list.", "401" => "{num} 401 %s %s :No such nick", + "SQ" => "{num} SQ :%s", null => null ); diff --git a/Uplink/Uplink.class.php b/Uplink/Uplink.class.php index d7d40fa..867cb85 100644 --- a/Uplink/Uplink.class.php +++ b/Uplink/Uplink.class.php @@ -142,6 +142,15 @@ class Uplink { } } + public function shutdown() { + if($this->client->connected()) { + if(($this->flags & self::FLAG_P10SESSION)) { + $this->send("SQ", "Shutdown requested."); + } + $this->client->disconnect(); + } + } + public function setUplinkHost($host, $port, $ssl = false, $bind = null) { $this->setSetting("host", $host); $this->setSetting("port", $port); @@ -728,6 +737,7 @@ class Uplink { $numeric = substr($this->server->getNumeric(),0,2).Numerics::intToNum($this->last_local_numeric, 3); } $this->last_local_numeric++; + $modes = new P10_UserModeSet($modes); $user = new P10_User($nick, $numeric, $this->server, time(), $ident, $host, $ip, $realname, $modes); if(($this->flags & self::FLAG_CONNECTED)) { $ip = Numerics::numericFromIP($user->getIP()); @@ -756,7 +766,7 @@ class Uplink { } } - public function join($user, $chanName) { + public function join($user, $chanName, $privs = 0) { if(!is_a($user, "P10_User") || !($user->getServer() === $this->server)) return ERR_INVALID_USER; if($chanName[0] != "#") @@ -767,6 +777,15 @@ class Uplink { $channel->joinUser($user); if(($this->flags & self::FLAG_CONNECTED)) $this->send("J", $user->getNumeric(), $chanName, time(), 0); + if($privs != 0) { + $channel->setUserPrivs($user, $privs); + if(($this->flags & self::FLAG_CONNECTED)) { + $modestr = "+".(($privs & P10_Channel::USERPRIV_OPED) ? "o" : "").(($privs & P10_Channel::USERPRIV_VOICE) ? "v" : ""); + $modestr .= (($privs & P10_Channel::USERPRIV_OPED) ? " ".$user->getNumeric() : ""); + $modestr .= (($privs & P10_Channel::USERPRIV_VOICE) ? " ".$user->getNumeric() : ""); + $this->send("OM", $user->getNumeric(), $chanName, $modestr); + } + } if($this->eventHandler) $this->eventHandler->event_join($user, $channel, false); } diff --git a/main.php b/main.php index 7cfe0fc..57ec862 100644 --- a/main.php +++ b/main.php @@ -25,9 +25,18 @@ * initial php file * */ +declare(ticks = 1); +error_reporting(E_ALL & ~E_STRICT); + require_once("Uplink/Uplink.class.php"); require_once("ModCMD/ModCMD.class.php"); require_once("BotLoader/BotLoader.class.php"); +require_once("Tools/timer.inc.php"); + +if(function_exists("pcntl_signal")) { + pcntl_signal(SIGINT, 'shutdown'); + pcntl_signal(SIGTERM, 'shutdown'); +} //basicly here is nothing, yet :D $uplink = new Uplink(); @@ -41,8 +50,27 @@ $uplink->initialize(); $botloader = new BotLoader($uplink); $botloader->loadBots(); +BotLoader::load("ModManager", "ModManager.class.php"); + +function shutdown($signal) { + global $botloader; + global $uplink; + if($signal == SIGINT) $type="SIGINT"; + else if($signal == SIGTERM) $type="SIGTERM"; + else $type = $signal; + echo "\n\nrecived shutdown instruction... ".$type."\n"; + $botloader->unloadBots(); + $botloader->save(); + $uplink->shutdown(); + exit; +} while(true) { $uplink->loop(); + $botloader->loop(); + timer_loop(); + if(function_exists("pcntl_signal_dispatch")) + pcntl_signal_dispatch(); } + ?> \ No newline at end of file -- 2.20.1