IRC-Bot Klassendesign
-
Dann kannst du das auch mal tun, indem du einfach mal die Klassen dazu erstellst. Die nötigen öffentlichen Funktionen dazu und dann in etwa wie die zusammen arbeiten sollen. Dann siehst du relativ schnell ob das gut zusammenspielt und wo du Sachen verallgemeinern kannst, damit es erweiterbarer wird.
Ich weiss nicht ob es so viel bringt das hier breit auszudiskutieren. Du kannst mal die grobe Struktur machen, denken, implementieren. Am Ende weisst du dann ja ob es gut war oder nicht. Du kannst natürlich im vornherein Ratschläge hier einholen, aber imo lernt man so Sachen besser, wenn man das einfach mal selber macht und daraus lernt. Und beim nächsten mal kannst du es besser machen.
-
@volkard: Prosa?
Hier mal die Deklaration:#ifndef SOCKET_HPP #define SOCKET_HPP #include <string> #include <vector> #include <boost/asio.hpp> #include <boost/noncopyable.hpp> namespace irc { // Um code übersichtlicher zu machen namespace io { using namespace boost::asio; typedef ip::tcp::socket socket; typedef ip::tcp::resolver resolver; } // Stellt eine _eindeutige_ Verbindung zum IRC dar class socket : public boost::noncopyable { const std::string server; std::string nick; // Wichtig für Identifizierung, von einem Host, können mehrere Clients kommen const unsigned short port; io::streambuf buffer; // Lesepuffer io::socket sock; // "roher" TCP Socket std::vector<std::string> split(const std::string& str, const std::string& delim); // Hilfsfunktion um einen String anhand von Leerzeichen zu splitten // \r\n wird abgeschnitten / angehängt std::string read_line(); void write_line(const std::string& line); public: socket(io::io_service& io_service, const std::string& server, const std::string& nick, unsigned short port = 6667); }; } #endif // SOCKET_HPP
-
314159265358979 schrieb:
@volkard: Prosa?
Hier mal die Deklaration:#ifndef SOCKET_HPP #define SOCKET_HPP #include <string> #include <vector> #include <boost/asio.hpp> #include <boost/noncopyable.hpp> namespace irc { namespace io { using namespace boost::asio; typedef ip::tcp::socket socket; typedef ip::tcp::resolver resolver; } class socket : public boost::noncopyable { const std::string server; std::string nick; const unsigned short port; io::streambuf buffer; io::socket sock; std::vector<std::string> split(const std::string& str, const std::string& delim); std::string read_line(); void write_line(const std::string& line); public: socket(io::io_service& io_service, const std::string& server, const std::string& nick, unsigned short port = 6667); }; } #endif // SOCKET_HPP
Jupp, jetzt reden wir eine Sprache.
Prosa: Schreib normale deutsche Sätze dazu, was, warum, weshalb und warum nicht.Du schreibst, ein socket HAT einen nick. Mööp.
-
Editiert, war das so gemeint?
-
Das ist alles noch ziemlich low-level. Setz höher an. Was eine Klasse für Daten-Member und Hilfsfunktionen hat interessiert erstmal nicht.
Interessant ist erstmal was du überhaupt für Klassen hast, und für was die zuständig sind. Und wer wie mit wem kommuniziert.
-
hustbaer schrieb:
Das ist alles noch ziemlich low-level. Setz höher an. Was eine Klasse für Daten-Member und Hilfsfunktionen hat interessiert erstmal nicht.
Naja, die meisten Daten-Member sind schon höchst interessant. Viel interessanter, als diese oder jene öffentliche Methode, die eh problemlos ist.
Wie hier, wo ich den nick im socket entdeckt habe.
(Deswegen mag ich auch im Code die Members vorne.)
-
Wo würdest du den Nick denn sonst hingeben?
-
volkard schrieb:
hustbaer schrieb:
Das ist alles noch ziemlich low-level. Setz höher an. Was eine Klasse für Daten-Member und Hilfsfunktionen hat interessiert erstmal nicht.
Naja, die meisten Daten-Member sind schon höchst interessant. Viel interessanter, als diese oder jene öffentliche Methode, die eh problemlos ist.
Wie hier, wo ich den nick im socket entdeckt habe.
(Deswegen mag ich auch im Code die Members vorne.)Also ich sehe das anders.
Was den Nick angeht, das siehst du im Prinzip genau so im Ctor.
Und ich finde gar nicht dass der dort nicht hingehört. Nur heisst die Klasse falsch, die sollte "irc_session" o.ä. heissen.
-
314159265358979 schrieb:
Wo würdest du den Nick denn sonst hingeben?
Vielleicht in die Sitzung.
-
Ich habe mir hier einmal das Interface des event_managers überlegt.
#ifndef EVENT_MANAGER_HPP #define EVENT_MANAGER_HPP #include "socket.hpp" #include <string> #include <functional> #include <boost/noncopyable.hpp> namespace irc { enum event_type { USER_JOIN, USER_PART, USER_KICK, USER_BAN, USER_QUIT, ... }; // alle funktionen thread-safe class event_manager : public boost::noncopyable { public: typedef std::function<void(std::vector<std::string> args, event_manager& instance)> event_handler; event_manager(irc::socket& socket); void register_handler(event_type type, const std::string& chan, event_handler handler); // channel-spezifischer handler void register_handler(event_type type, event_handler handler); // globaler handler void unregister_handler(event_handler handler); void write_line(); std::string read_line(); std::string nick() const; std::string server() const; unsigned short port() const; }; } #endif
-
void unregister_handler(event_handler handler);
Da bin ich aber echt gespannt, wie die Implementierung aussieht
Eventuell ist auch Boost.Signal was für dich...
-
Nexus schrieb:
void unregister_handler(event_handler handler);
Da bin ich aber echt gespannt, wie die Implementierung aussieht
Eventuell ist auch Boost.Signal was für dich...
Ja ich habe daran gedacht, das mit boost::signal zu implementieren, genauer gesagt mit boost::signal2
Allerdings ist mir gerade ein anderes Konzept eingefallen, das mir auch recht gut gefällt. Und zwar zwei abstrakte Basisklassen "packet" und "event" von denen dann weitere packet- und event-Klassen für jeden Event-Typ abgeleitet werden. Dadurch kann man anstatt nur die Argumente am Handler zu bekommen direkt mit den geparsten Daten arbeiten und muss sich die Strings nicht selbst zusammenbauen.
-
Ich denke an sowas:
#ifndef DINGENS_HPP #define DINGENS_HPP #include "socket.hpp" #include <string> #include <boost/noncopyable.hpp> namespace irc { class dingens : public boost::noncopyable { public: dingens(irc::socket& socket); void register_handler(event_handler* handler); void write_line(); std::string read_line(); std::string nick() const; std::string server() const; unsigned short port() const; }; } #endif class event_handler { virtual void receive_line(std::string line)=0; //oder virtual void join/leave/msg/whisper/kick/ban/motd/...
-
Angst vorm inner platform effect hab.
-
volkard schrieb:
Angst vorm inner platform effect hab.
?
-
314159265358979 schrieb:
volkard schrieb:
Angst vorm inner platform effect hab.
?
Ich baue Methoden und nenne sie join und leave und so.
Du baust Dir ein Framework, setzt event_type/lamda-Paare ab, und so Sachen.
Ich kann sogar Vererbung.
Du kannst events an Default-Eventhandler weiterreichen lassen.
Ich will nicht sagen, daß Dein Entwurf schlecht wäre.
Mußt nur irgendwo zwischen
http://en.wikipedia.org/wiki/God_object
und
http://en.wikipedia.org/wiki/Inner-platform_effect
landen und am besten nicht zu weit am Rand.
-
Sorry, ich verstehe nicht was du mir damit sagen möchtest. Wo versuche ich denn so eine "God-Klasse" zu machen?
-
314159265358979 schrieb:
Sorry, ich verstehe nicht was du mir damit sagen möchtest. Wo versuche ich denn so eine "God-Klasse" zu machen?
Nicht Du. Mir könnte es passieren, wenn ich aus Angst vor dem inner platform effect zu wenig trickse.
-
volkard schrieb:
Ich will nicht sagen, daß Dein Entwurf schlecht wäre.
Sags ruhig
Genau deshalb habe ich ja diesen Thread eröffnet.
-
314159265358979 schrieb:
Sags ruhig
Mein Bot sah so aus wie Deiner. Weiß nicht, ob das Design vielleicht doch gut ist. Also damals hatte ich mich ziemlich darüber gefreut. Oder ob es an der Implemetierungssprache (Perl) lag. Er konnte viele Kunststücke. ~Allerdings habe ich ihn wegen schlechter Wartbarkeit aufgegeben.~