continued BotLoader, added ModManager.class.php & timers
authorpk910 <philipp@zoelle1.de>
Wed, 27 Jul 2011 23:54:44 +0000 (01:54 +0200)
committerpk910 <philipp@zoelle1.de>
Wed, 27 Jul 2011 23:54:44 +0000 (01:54 +0200)
BotLoader/BotLoader.class.php
Bots/ExampleBot.class.php
Bots/ModManager.class.php [new file with mode: 0644]
Tools/timer.inc.php [new file with mode: 0644]
Uplink/Numerics.class.php
Uplink/P10Formatter.class.php
Uplink/Uplink.class.php
main.php

index df06eeaed4d1f137aeb63ff3b6cecf3f5f45c5c6..b5dc87b252cd482c934e5cf7581a0f91dc1d8e66 100644 (file)
@@ -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
index 53e248db617b60705aaac0174922df090b71c893..299f151bdfbd8d4ff03d4a0f0f96e3beff3d9e8f 100644 (file)
@@ -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 (file)
index 0000000..4eac48c
--- /dev/null
@@ -0,0 +1,117 @@
+<?php
+/********************************* PHP-P10 ******************************
+ *    P10 uplink class by pk910   (c)2011 pk910                         *
+ ************************************************************************
+ *                          Version 2 (OOP)                             *
+ *                                                                      *
+ * PHP-P10 is free software; you can redistribute it and/or modify      *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or    *
+ * (at your option) any later version.                                  *
+ *                                                                      *
+ * This program is distributed in the hope that it will be useful,      *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
+ * GNU General Public License for more details.                         *
+ *                                                                      *
+ * You should have received a copy of the GNU General Public License    *
+ * along with PHP-P10; if not, write to the Free Software Foundation,   *
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.       *
+ *                                                                      *
+ ************************************************************************
+ * 
+ *  Bots/ModManager.class.php
+ *
+ * module manager bot...
+ *
+ */
+
+class {$_NAME} extends Bot {
+       private $uplink;
+       private $modman;
+       
+       public function load($uplink, $old = false) {
+               $this->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;$i<count($lines);$i++) {
+                                       if($lines[$i]!="") {
+                                               $this->uplink->privmsg($this->modman, $channel, $lines[$i]);
+                                       }
+                               }
+                               $lines = explode("\n",$ret);
+                               for($i=0;$i<count($lines);$i++) {
+                                       if($lines[$i]!="") {
+                                               $this->uplink->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 (file)
index 0000000..57c6318
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+$timers['id']=0;
+
+function timer_loop() {
+ global $timers;
+ $mtime = microtime(true);
+ $ret = false;
+ foreach ($timers as $id => $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
index 2af7132f404dfd473298188d8f82aa94eeb3802f..7b6bee116e219da74223c50deb4d5ff1f215d480 100644 (file)
@@ -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 = "";
index e4235f458a3705901e858b8a7308142068a7a71b..05cb8e3622b26187c1a562c2e2dfa489ce7f1826 100644 (file)
@@ -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
        );
        
index d7d40fa86b3e4100ee10a4a42f4bf4907e111c89..867cb8587da7e40752c344a007e31276685a717d 100644 (file)
@@ -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);
        }
index 7cfe0fc1c2cadc79a0447359fe9113a0887ea1e1..57ec8624e912e340e931b5294dcc6f4db7956dd0 100644 (file)
--- a/main.php
+++ b/main.php
  * 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