IRC-Bot Klassendesign



  • ipsec schrieb:

    Ich würde es auch besser finden, wenn die Zeile nicht ständig neu geparst werden muss. Dann schleichen sich nämlich schnell solche Nachlässigkeiten wie bei jhkhjkhjk ein, wo statt nur auf PING auch auf DING, BINGO oder bIber reagiert wird und die Privmsg-Funktion doppelte Leerzeichen in der Nachricht verschluckt.

    Möglicherweise bekommt man mit ein bisschen aufwendiger Metaprogrammierung so etwas hin (ich zeig mal nur die ungefähre Verwendung):

    void ban(session& s, string nick, string channel, int seconds, string reason);
    
    int main()
    {
        session s;
    
        cmdprocessor cmd(s);
        cmd.register_cmd("!ban", ban);    // "!ban ipsec #c-plusplus.net 12345 ohne grund" -> ban(s, "ipsec", "#c-plusplus.net", "ohne grund");
    }
    

    Das könnte schwierif werden, da Befehle bekanntlich unterschiedliche Parameter annehmen. Daher wäre es sinnvoller, wenn die Parameter als std::vector übergeben werden.



  • Sieht eigentlich gut aus. Denk auch dran, dass irc::session auch threadsicheren Zugriff auf die Channel- und Userinformationen bieten sollte.
    Bei mir sieht das Design sehr ähnlich aus, allerdings heißen die event_handler Plugins und der event_manager ist bei mir dementsprechend der plugin_manager.

    Ein Pluginsystem würde ich auf jeden Fall empfehlen. Ich habe über die Jahre auch eine ganze Reihe von IRC-Bots geschrieben und erst mit dem letzten (zum ersten Mal mit Pluginsystem) bin ich jetzt schon seit längerer Zeit zufrieden.
    Dank zur Laufzeit ladbarer Plugins kann man Funktionalität wie Logging, verschiedene Channelservices, Spiele, Remoteaccess, FServ, GUI-Client etc. jederzeit aktualisieren, entfernen oder hinzufügen, ohne dass man den Betrieb in den Channels durch Neustarten des Bots aufhalten müsste.



  • So ein Pluginsystem ist auf alle Fälle geplant, allerdings durch die schon angesprochenen Python-Scripte. C++ Plugins sind nicht geplant, da ich dann keine Plattformunabhängigen Plugins schreiben kann.



  • Ich habe mir noch folgendes dazu überlegt:
    irc::command_handler
    - Spezieller Handler-Typ für Befehle
    - Hat nur die Methode on_command
    - Wird beim event_manager, der auf plugin_manager umbenannt wird mit einer extra Funktion registrert



  • Ich sitze gerade an der Implementierung des event_managers und bin etwas verzweifelt. Und zwar implementiere ich gerade die Funktionen read_line(), put_back() und run(). Alle 3 Funktionen müssen thread-safe sein.

    read_line() Liest eine Zeile und gibt diese zurück.
    put_back(const std::string&) Gibt eine Zeile zurück in den Buffer.
    run() liest laufend Daten ein, schreibt in den Buffer und informiert anschließend andere Threads über vorhandene Daten.

    Ich habe eine std::liststd::string als Buffer, einen boost::mutex und eine boost::condition_variable.
    (Die Variablen, die mit global_ anfangen sind nicht global, sondern heißen so, weil sie für "globale" IRC Nachrichten verwendet werden)

    std::string irc::event_manager::read_line()
    {
    	boost::unique_lock<boost::mutex> lock(global_mutex);
    
    	while(global_buffer.empty())
    		global_condition.wait(lock);
    
    	std::string str = std::move(global_buffer.front());
    	global_buffer.pop_front();
    	return std::move(str);
    }
    
    void irc::event_manager::put_back(const std::string& line)
    {
    	boost::lock_guard<boost::mutex> lock(global_mutex);
    	global_buffer.push_back(line);
    	global_condition.notify_one();
    }
    
    void irc::event_manager::run()
    {
    	for(;;)
    	{
    		std::string line = session.read_line();
    		{
    			boost::lock_guard<boost::mutex> lock(global_mutex);
    			global_buffer.push_back(std::move(line));
    			global_condition.notify_one();
    		}
    	}
    }
    

    Ich kenne mich mit Conditions noch kaum aus und wollte daher wissen, ob dieser Code korrekt sein kann. Gibt es vielleicht einen schönen Weg nur mit Mutexes?



  • möp



  • Niemand hier, der die Muse hat, sich mit hässlichem Code ala PI zu beschäftigen? Oder ist mein Post einfach unvollständig / fehlt irgendwas?



  • Code sieht OK aus.

    Die Art und Weise wie du die Condition-Variable + Mutex verwendest ist auch OK, das ist genau so "wie mans macht". Schöneren Weg gibt es da keinen.

    Was anderes noch:

    314159265358979 schrieb:

    void irc::event_manager::put_back(const std::string& line)
    {
    	boost::lock_guard<boost::mutex> lock(global_mutex);
    	global_buffer.push_back(line);
    	global_condition.notify_one();
    }
    

    Wenn du schon std::move im restlichen Code verwendest, wieso dann nicht auch hier?

    Nimm den Parameter by-value, und "move" den Parameter dann in die Liste hinein:

    void irc::event_manager::put_back(std::string line)
    {
    	boost::lock_guard<boost::mutex> lock(global_mutex);
    	global_buffer.push_back(std::move(line));
    	global_condition.notify_one();
    }
    

    Wenn put_back ohne "move" aufgerufen wird, wird der String 1x kopiert, nämlich beim "by-value" übergeben. Bei global_buffer.push_back wird jetzt nur mehr gemoved, d.h. das ist billig.
    Ist also in dem Fall etwa gleich schnell wie deine Version (die immer genau 1x kopiert, nämlich bei global_buffer.push_back ).

    Wenn put_back aber MIT "move" aufgerufen wird, ist "meine" Variante schneller, da dann gar keine Kopie mehr gemacht wird.



  • Vielen Dank für den Tipp! 🙂

    Was mir noch nicht ganz klar ist: Wieso brauche ich hier diese while-Schleife? (Ich hab mir die Verwendung aus der boost-Doku abgeguckt und verstehe deshalb noch nicht so ganz, was da abgeht.)



  • 314159265358979 schrieb:

    Was mir noch nicht ganz klar ist: Wieso brauche ich hier diese while-Schleife? (Ich hab mir die Verwendung aus der boost-Doku abgeguckt und verstehe deshalb noch nicht so ganz, was da abgeht.)

    http://en.wikipedia.org/wiki/Spurious_wakeup


Anmelden zum Antworten