Development > Coding and development discussion

Some thoughts about a new structure

(1/2) > >>

Alreadythere:
I've experimented with a possible new structure for BeBot, taking advantage of the PHP 5.2 object system. Before I do anything besides simple testing I want to put the ideas up to discussion, as the changes would require a modification of almost every file of the bot.

The underlying idea of all the changes is to take advantage of the PHP 5.2 object system to make the code easier to support, easier to read and easier to change, as well as offering the possibility for some new features. Here a first list of the changes, I may have forgotten some I already thought about.
* Add a BotManager. The BotManager is supposed to do pretty much the job that the current Main.php and StartBot.php files are doing. Mainly starting the bot as well as keeping it running. Instead of the current secondary execution loop with a system() it would be done by creating and destroying instances of the Bot class directly. This way there would only be one php instance per BeBot instance instead of the current two. In addition the BotManager could support running more then one bot under one instance. This works, though it may require some slight changes in the Bot handling. And there are a couple if disadvantages in it, mainly the serial nature of PHP. This means that if one of several bots in a single instance is delayed in any command execution it would lock all other bots till it is done. Queueing all operations as far as possible could reduce this of course.
* Force all modules to explicitly register themself with the BotManager. If we want to support more then one bot under one instance of a BotManager we have to make sure that all definitions inside the modules are fully encapsulated, without needing any outside definitions like the current $command or $cron arrays, or the creating of tables outside of the class code. The single instance of each class that is created would have to be removed too. This all would be divided in two parts. One external call to a function in the BotManager, which would announce the existence of the module at all. And then a couple of function calls inside the constructor of each module, which would register commands and cronjobs with the Bot instance, as well as create all needed table and do all other database operations.
* Support module loading and unloading during runtime. Using complete object encapsulation would allow the Bot to load and unload modules during runtime by creating and destroying instances of the module objects. This possibility coupled with a runtime configuration which modules should be loaded and unloaded would offer a much more flexibility then the current way of handling modules. It would not enable module code to be reloaded though.
* Create an abstract base class which all modules use as parent class. This way we could handle repetitive configuration jobs in a central way as well as create handlers for incoming chat to the modules semi-automatic. The module creator still would have to write the specific handler() function, but at least we could automatically redirect incoming tells as well as private group and org chat to the handler. On top we could make sure here that only valid registered commands get forwarded. This could be implemented with either the __call() function or specific tell/gc/pgmsg() functions.
* Make the core module references private in the Bot class. My idea is to make the handling here more flexible. I plan to hide the references to the core modules from direct outside access, instead the core modules should only be accessed via getCoreModule() functions. This would make any changes or extensions to the core modules much easier, as we developer would only have to change the get() functions, and no code in any module would have to be changed. This would require a well-thought partition of all core functions (including functions of the DB, AOChat and Bot classes) to fully take advantage of it.

Temar:

--- Quote from: Alreadythere on February 27, 2008, 11:36:51 am --- And there are a couple if disadvantages in it, mainly the serial nature of PHP. This means that if one of several bots in a single instance is delayed in any command execution it would lock all other bots till it is done. Queueing all operations as far as possible could reduce this of course.

--- End quote ---

with the Onlineorg.php orgs.php modules im working on
i plan on implimenting anti lag stuff
i have already done it on orgs.php
this module gets entire list list 1 letter at time
i changed to to do 1 letter at a time then take a few seconds break useing cron which is easy done by adding the cron $this -> bot -> cron["5sec"]["orgs"] or something :p, i think i added a min time too (just incase 5sec ran as i entered it)

Blueeagle:
Bot manager:
This could be implemented as a single php-process that spawns one php process for each bot. That way you get ($num_bots+1) processes instead of ($num_bots * 2) as it is today. This avoids the bottle neck of the serial process while not adding any processes in any scenario.

Register modules with bot manager:
I'm not quite sure if I think this is the way to go. I think having the abillity to have separate module-directories for each bot is a good thing. That way you can have fail-over bots run in case some experimental module craps up on the cutting edge bot.

Module loading and unloading:
This would be activating and deactivating. This is in general a good idea. The default should IMO be a minimum of modules activated when a bot is first started. Then the owner would configure which modules that should be activated.

Abstract base class:
I definetly advocate this. Not only will it help when writing modules but it will also make modules more uniform. I have been working on something and it currently looks like this

--- Code: ---<?php

abstract class BaseModule
{
protected $bot; // A reference to the bot
public $help; //A window containing help text for this module
public $module_name; //Name of the module extending this class

//This would be called in the constructor of the extending module
function __construct (&$bot, $module_name)
{
//Save reference to bot
$this -> bot = &$bot;
$this -> module_name = $module_name;
}

//Prototype for the command_handler
abstract protected function command_handler($name, $msg, $origin);

//Interface to register command. Now with checks for duplicate command definitions.
//(I'm not sure if this can be moved into Bot.php as it needs access to $this -> module_name;
protected function register_command($channel, $command, $access="SUPERADMIN") //Upgraded default level as SUPERADMIN to maintain security.
{
if(!isset($this -> bot -> commands[$channel][$command]))
{
$this -> bot -> commands[$channel][$command] = &$this;
$this -> bot -> accesscontrol -> create($channel, $command, $access);
}
else
{
//Say something useful for modules not registering commands properly. (THIS IS BUGGED)
if (!empty($this -> bot -> commands[$channel][$command] -> module_name))
{
$old_module = "an old module";
}
else
{
$old_module = $this -> bot -> commands[$channel][$command] -> module_name;
}
$this -> bot -> log("CMD", "ERROR", "Duplicate command definition! The command '$command' for channel '$channel'".
" has already been registered by $old_module and is attempted re-registered by {$this -> module_name}");
}
}

protected function register_event($event)
{
$this -> bot -> commands[$event][] = &$this;
}

protected function parse_com($command, $pattern = array('com', 'sub', 'args'))
{
$num_pieces=count($pattern);
$pieces = explode(' ', $command, $num_pieces);
$com = array_combine($pattern, $pieces);
return ($com);
}

/************************************************************************
 Default to replying in the same channel as the command has been recieved
*************************************************************************/

public function tell($name, $msg)
{
$reply = $this -> command_handler($name, $msg, "tell");
if ($reply !== FALSE)
$this -> bot -> send_tell($name, "##normal## $reply ##end##");
}

public function gc($name, $msg)
{
$reply = $this -> command_handler($name, $msg, "gc");
if ($reply !== FALSE)
$this -> bot -> send_gc("##normal## $reply ##end##");
}

public function pgmsg($name, $msg)
{
$reply = $this -> command_handler($name, $msg, "pgmsg");
if ($reply !== FALSE)
$this -> bot -> send_pgroup("##normal## $reply ##end##");
}
}
?>

--- End code ---
As you can see the three responding functions are public to allow for a module to re-define their behaviour. This is mainly to allow control over where the reply would be going.

Make core modules private:
I think protecting the core and making a uniform API a good idea. However I haven't given the implementation for this much thought.

Alreadythere:

--- Quote from: Blueeagle on February 28, 2008, 06:42:35 am ---Bot manager:
This could be implemented as a single php-process that spawns one php process for each bot. That way you get ($num_bots+1) processes instead of ($num_bots * 2) as it is today. This avoids the bottle neck of the serial process while not adding any processes in any scenario.
--- End quote ---
Sounds nice, I just haven't found any functions to allow for non-blocking sub-execution which work on all platforms...
Stuff like system() or exec() is blocking, process forking would be nice, but isn't supported under windows.
Besides, fully seperated processes would deal with any possible deadlock problems but would remove a few of the added possibilities I was thinking about. If all is in one process controlled by a central manager we could make an easier to use relay for example, by directly putting the chat into the functions that have to handle them. This would need no sent chat on the chatservers at all. Was just a thought I had though :)


--- Quote from: Blueeagle on February 28, 2008, 06:42:35 am ---Register modules with bot manager:
I'm not quite sure if I think this is the way to go. I think having the abillity to have separate module-directories for each bot is a good thing. That way you can have fail-over bots run in case some experimental module craps up on the cutting edge bot.
--- End quote ---
We could add the directory name to the module name, dividing the modules in some categories that way. This would allow the loading of two modules with the same name for worst cases. Though my ideas won't remove the need to restart the whole bot manager if you want some changes in files to take effect.
This would pretty much only be of advantage in a production environment, testbeds most likely won't really profit of it much. It won't prevent anything in them though, there won't be any lost functionality compared with today.


--- Quote from: Blueeagle on February 28, 2008, 06:42:35 am ---Module loading and unloading:
This would be activating and deactivating. This is in general a good idea. The default should IMO be a minimum of modules activated when a bot is first started. Then the owner would configure which modules that should be activated.
--- End quote ---
Something like that, yes. We just have to make sure the required core modules are always active, and I guess we should make sure that the most important user interfaces can't be disabled too.


--- Quote from: Blueeagle on February 28, 2008, 06:42:35 am ---Abstract base class:
I definetly advocate this. Not only will it help when writing modules but it will also make modules more uniform. I have been working on something and it currently looks like this [...]
As you can see the three responding functions are public to allow for a module to re-define their behaviour. This is mainly to allow control over where the reply would be going.
--- End quote ---
Yes, I was thinking about something like your class. I was thinking about a simple check for command/channel combos in the tell/gc/pgmsg functions, but basically we are thinking about the same thing.

clashbot:
currently right now I am running 5 bots, which means 5 command windows in Windows. As this is a nuisance, I deal with it as I do like final control and being able to see what is going on with any of the bots, which is why I do not have them running as a service. With those 5 command windows, that also means I have 5 instances of the logs etc, one per bot. With this bot man that you are talking about, I am assuming all bots would run from a single command window, which means line monitoring will be harder. That I can deal with, are you still going to maintain a directory structure where multiple bots will be able to output it's log independantly of the other bot and not be a uniform log of all bots in one log file? Also, if there is an ability to turn modules on and off inside the bot ingame, then the only reason you would have to reload everything to implement a change would be a mod to any of the core files, not the module files, or customs, as these you would be able to unload via bot config, update, reload via bot config, and depending how you are implementing the base calls, should allow for the new module to load straight way, or am I totally off base here?

Navigation

[0] Message Index

[#] Next page

Go to full version