MyIRCBot

Stato
Discussione chiusa ad ulteriori risposte.

fojeaf

Utente Silver
3 Marzo 2008
235
8
0
95
Inizialmente non pensavo di pubblicare questo codice, o al massimo di metterlo su github come gist e basta, ma visto che questa sezione sta morendo, quindi cerco di rivitalizzarlo, almeno un minimo.

Caratteristiche Principali e Features: RFC Compliant, SSL Support, Modular

Ho realizzato il bot in modo un po' "a basso livello", per quanto basso si possa definire, nel senso che nn ho usato moduli preconfezionati (tipo asynchat e twisted) per quanto essi siano molto buoni in verità, semplicemente perché, ove posso, sono in grado e dove nn sia troppo pesante, preferisco farmi le cose da solo :asd:

Ora illustro brevemente il codice: ho fatto uso dei moduli queue, threading, socket e re (in realtà mi serviva solo una regex, ma vabbè); oltre che al dizionario modules del modulo sys, questo per creare un minimo di dmi (dynamic module import).
Al momento tale tecnica non è ancora stata molto sviluppata nel bot, in quanto il bot è sì in grado di aggiungere plugins successivamente, è in grado di trovare plugin non presenti inizialmente nella cartella, ma nn è tuttavia in grado di caricare eventuali modifiche apportate runtime (nemmeno unloadando e ricaricando il modulo in questione). Sono già all'opera per cercare di sistemare questo problemino.

Il funzionamento del bot è semplice: viene connesso un socket al server, inviate le stringhe NICK e USER. Dopodiché vengono runnati due thread, i quali hanno il compito uno di prendere le stringhe inviate dal server, parsarle, convertirle in un dizionario e metterle in una Queue. L'altro thread ha invece il compito di aspettare stringhe da un'altra coda e, una volta ricevute, inviarle al server. Il main thread intanto, prende il dizionario dalla prima coda e itera la lista dei plugin, avviando un apposito thread per ognuno di essi, i quali vengono richiamati passando l'oggetto corrente (self) e il dizionario appunto. I plugin fanno poi uso di una funzione send la quale mette le stringhe ricevute nella seconda coda, dalla quale la funzione __send poi procederà all'invio vero e proprio.

I plugin devono avere ciascuno un nome diverso (ma va?) ed essere contenuti nella cartella plugin. Essi devono contenere OBBLIGATORIAMENTE una funzione col lo stesso nome del plugin stesso, la quale deve richiedere esattamente due argomenti: l'oggetto (si consiglia l'uso di 'ref' per indicare tale parametro) e il dizionario, il quale conterrà i vari parametri ottenuti dal parsing (ad es diz['nick'], diz['mex'] etc). Purtroppo, presumo a causa del contemporaneo uso della dmi e dei thread, l'uso di variabili, funzioni e classi definite nel plugin fuori dalla funzione principale da molti problemi: consiglio di dichiarare ogni funzione classe e/o variabile all'interno della funzione stessa. Se si ha necessità di salvare dati da una precedente esecuzione del plugin, consiglio di creare una variabile interna alla classe, del tipo ref.plugin_nomevariabile .

La classe fornisce allo scrittore di plugin essenzialemente 4 funzioni utili: send, utilizzata per inviare stringhe al server (rispettate l'rfc, mi raccomando, non occorre aggiungere i \r\n, lo fa in automatico); loadPlugin e unloadPlugin, le quali accettano come parametro il nome del plugin e ritornano una stringa indicante la riuscita o meno dell'operazione;
close, la quale chiude la connessione (non invia il mex di quit, a quello dovete pensarci voi) e cerca di terminare i vari thread.

Purtroppo, per quanto il threading in python sia fatto bene, presenta alcune pecche: non vi sono infatti metodi eleganti per terminare un thread secondario, mentre per terminare il thread principale da uno secondario è necessario usare _thread.interrupt_main(), che però non sempre funziona, anzi. Inoltre, sebbene col terminare del thread principale dovrebbero terminare anche gli altri, ciò non accade, quindi ho dovuto usare un metodo gay, sostituendo i while True con dei while not self.die,, e costringendomi ad usare get_nowait, con conseguente perdita di prestazioni.

Known Issues: impossibilità di reloadare plugin modificati, necessità di dichiarare tutto DENTRO alle funzioni omonime del plugin, necessità di controllare (ove i plugin rischino di andare in loop infinito) la variabile Bot.die che se settata a True implica l'uscita immediata dal plugin

TODO: implementare il supporto ai server con password; migliorare il sistema di chiusura (possibilmente agendo proprio sulla classe Thread); inserire delle primitive più semplici per l'invio; inserire un check dei mex in invio, in modo che controllino che sia rfc valid; inserire un sistema di gestione degli errori migliore; migliorare il supporto per gli encoding del server; migliorare il sistema dei plugin.

Core: http://gist.github.com/346302

Provvedo al + presto ad uppare anche quel minimo di plugins necessari, e provvederò anche a fornire una doc migliore (forse apro un repo su github)



EDIT: ho trovato dove sta il problema che obbliga a definire tutto dentro la funzione del plugin: è da bestemmiare a livello implementativo farne la soluzione, dovrò studiarmi il sistema per un po' per trovare una soluzione elegante ed efficace.
 
Stato
Discussione chiusa ad ulteriori risposte.