PlIB - PerL IrcBot

Stato
Discussione chiusa ad ulteriori risposte.

Robertof

Utente Silver
19 Giugno 2008
186
10
0
98
Salve a tutti! :phonmg:
Sono qui per presentarvi la mia ultima creazione, PlIB..
Cosa è PlIB? PlIB (Pi elle i bi) è un ircbot modulare scritto in Perl, rfc-compliant e con supporto ad SSL.

Resta a voi scoprirlo completamente.. questo è un esempio di usage:
Codice:
#!/usr/bin/perl

###############################################################
# @name..................................................plib #
# @realname.......................................PerL IrcBot #
# @author............................................Robertof #
# @[email protected] #
# @licence..........................................GNU/GPL 3 #
# @lang..................................................Perl #
# @requirements...IO::Socket::INET or IO::Socket::SSL for SSL #
# @isthisfinished.........................................yes #
#                            Enjoy                            #
###############################################################

use strict;
use warnings;
use Plib::main;
# Usage: new (nick, user, real, idpass, isop, debug, usessl, server, port)
# !! WARNING !! Use class->setChans (chan1:key, chan2:key, chan3, chan4, ecc.) to add chans to join !!
my $plib = Plib::main->new ("Plib", "plib", "PerL IrcBot", "", 0, 1, 1, "irc.unitx.net", 6697);
$plib->setChans ("#Unit-X");
### ↓↓↓↓↓ OPTIONAL MODULES ↓↓↓↓↓                                     ###
#   Usage: $mainclass->hook_modules (module1, module2, module3 ecc.) ###
$plib->hook_modules ("firstplugin", "dml", "autorejoin");
#
$plib->startAll;
Download: http://github.com/Robertof/PlIB/tarball/master (tar.gz)
Github: http://github.com/Robertof/PlIB
Sono inclusi alcuni moduli predefiniti, come l'autorejoin, il dynamic plugin loader (mi raccomando di impostarlo!), il plugin per UnitX ecc.
Infine, ho appena finito di scrivere una megaguida per chi volesse approfondire PlIB, con annessa guida per la creazione di moduli.
Eccola qui:
Codice:
PlIB -- HowTo

Italian:
Ciao mondo!
PlIB è un ircbot modulare, rfc compliant con numerose features. Una di queste è, ad esempio, il supporto ad SSL :)
Ma resta a voi scoprirle tutte, con questo grande manuale!

Cominciamo a spiegare come è composto PlIB.
PlIB è formato da 3 moduli principali: main, sockutil e functions.
Il primo, main, è il modulo principale.
Le sue funzioni sono:
- new ~ il costruttore. Parametri:
-- nickname, username, realname
-- idpass (identify pass)
-- isOp (il bot sarà operatore nei canali? NB: questa funzione non serve a nulla nelle classi predefinite del bot, ma potrebbe servire ad un eventuale plugin)
-- debug (il bot deve abilitare il debug? Con il debug avrete alcuni messaggi speciali, e sarà visualizzato ciò che il server invia)
-- usessl (il bot dovrà usare SSL? Attenzione, è necessario il modulo IO::Socket::SSL per l'SSL!)
-- server (a quale server il bot dovrà connettersi?)
-- port (che porta?)
~~~~~~~~~~~~~~~~~~~
- setChans ~ questa funzione serve per impostare i chans del bot. Attenzione: è obbligatorio usare questa funzione prima di avviare il bot con startAll! Parametri:
-- canale1 (canale)
-- canale2:chiave (un canale con annessa chiave)
-- canale3 (un altro canale senza chiave)
-- ecc. (si possono aggiungere infiniti canali)
~~~~~~~~~~~~~~~~~~~
- isDebug ~ funzione interna - restituisce 1 o 0 in base all'opzione "debug" inserita nel costruttore.
~~~~~~~~~~~~~~~~~~~
- hook_modules ~ questa funzione serve per "hookare" un modulo. Un modulo può contenere qualsiasi cosa, dalla possibilità di ricercare da un motore di ricerca alla possibilità di implementare persino un'intelligenza artificiale (sì, ok, giusto per dire!). Parametri:
-- modulo1
-- modulo2
-- ecc. (si possono aggiungere infiniti moduli, nei limiti della memoria ovviamente!)
~~~~~~~~~~~~~~~~~~~
- getAllChannels ~ questa funzione ritorna la lista dei canali joinati [quelli specificati con setChans], con un separatore a scelta. Parametri:
-- chanSeparator (il separatore per ciascun chan, per esempio ',' produrra' #ciao,#mondo,#bello ecc.)
-- withKey (nel risultato sarà restituita anche la key?)
-- keySeparator (se è stato specificato withKey, questo sarà il separatore della chiave del canale. Per esempio, se inserisco ':', produrrà: #ciao:bello,#mondo:0,#bello:cavolo; ATTENZIONE allo 0 finale, che viene inserito quando un canale non ha la chiave!
~~~~~~~~~~~~~~~~~~~
- sendMsg ~ questa funzione invia un messaggio, ma solo se è stato aperto il socket (quindi se è stata lanciata la funzione startAll) - Parametri:
-- to (destinazione del messaggio, puo' essere anche un username)
-- what (cosa deve inviare PlIB?)
~~~~~~~~~~~~~~~~~~~
- matchMsg ~ questa funzione matcha un messaggio, e ritorna un hash reference (ovvero da usare come $x->{'elemento'}) formato da 3 elementi: userinfo (le informazioni dell'utente in formato :nick!ident@host, inutile se usato con un plugin, poiché alla funzione 'onWhile' del plugin vengono passate le variabili 'nick, 'ident' e 'host'), chan (il canale dove è stato inviato il messaggio), message (il messaggio). Parametri:
-- onWhat (su cosa deve matchare il messaggio? Dev'essere una riga mandata dal server)
~~~~~~~~~~~~~~~~~~~
- getUserData ~ questa funzione matcha le informazioni di un utente, in formato :nick!ident@host, e restituisce un hash reference formato da 3 elementi: nick (il nick dell'utente), ident (l'ident dell'utente), host (l'host dell'utente). Questa funzione è utile solo nel caso si abbiano delle informazioni non parsate automaticamente da PlIB (quindi non nel caso dell'onWhile dei plugin). Parametri:
-- onWhat (su cosa deve matchare i dati dell'utente? Dev'essere una riga mandata dal server)
~~~~~~~~~~~~~~~~~~~
- startAll ~ questa funzione apre il socket, ed avvia la ricezione dei dati da esso. Necessaria per far connettere il bot. Attenzione: avviare questa funzione solo DOPO aver hookato i plugin & aver impostato i chan.

Queste sono le funzioni del modulo principale. Ma ora passiamo a sockutil. Sockutil è il modulo che fornisce alcuni utili funzioni per il socket. È possibile accedere a questo modulo grazie al main, che metterà a disposizione nel mainhash l'attributo "socket", in modo da poterci accedere tramite $mainClass->{"socket"}->funzioniSockUtil. NOTA: questa classe non dev'essere inizializzata dall'utente, ma dalla main di PlIB!! Verrà fatto automaticamente dal metodo 'startAll'. Rendo comunque disponibili i parametri della 'new' per chi fosse interessato in generale.
Ma passiamo alle sue funzioni.
- new ~ il costruttore. Nota che la connessione sarà inizializzata in seguito grazie ad un'altra funzione, non con il costruttore. Parametri:
-- sockaddr (l'indirizzo a cui connettersi)
-- sockport (la porta)
-- isSSL (usare SSL o no?)
-- mainHash (l'hash principale, ovvero l'istanza della classe 'main')
~~~~~~~~~~~~~~~~~~~
- startConnection ~ questa funzione avvierà la connessione. Si occuperà anche di notificare all'utente eventuali errori di moduli (come per esempio la mancata installazione del socket). Anche questa funzione è ad uso interno, ad opera della funzione 'startAll' della classe main.
~~~~~~~~~~~~~~~~~~~
- send ~ questa funzione serve per inviare un determinato comando al server. È possibile usarla da qualsiasi parte, tramite $mainClass->{"socket"}->send ("xx"). Parametri:
-- what (cosa inviare al socket? ATTENZIONE: NON OMETTERE IL \N!)
~~~~~~~~~~~~~~~~~~~
- closeConnection ~ questa funzione invia il messaggio di QUIT al server, chiude il socket ed elimina la variabile. Parametri:
-- quitMessage: il messaggio di quit.
~~~~~~~~~~~~~~~~~~~
- getSock ~ questa funzione restituisce il socket. Non serve a molto per un uso normale, ma potrebbe essere utile per altri scopi.

Ma ora passiamo al modulo functions.
Anche esso viene inizializzato automaticamente dalla classe principale, e viene reso accessibile grazie alla proprietà dell'hash functions.
Ma passiamo alle sue funzioni.

- new ~ il costruttore. Nessun parametro
~~~~~~~~~~~~~~~~~~~
- checkVars ~ questa funzione controlla se una variabile è definita o no. Ritorna 1 se tutte le variabili sono definite, 0 se viceversa. Parametri:
-- $variabile (una variabile),
-- $variabiledue (un'altra variabile),
-- ecc. (questa funzione accetta infiniti parametri)
~~~~~~~~~~~~~~~~~~~
- hashJoin ~ questa funzione è molto utile, e funge come 'join' ma per gli hash. Funziona solo con gli hash references. Parametri:
-- kvsep (il separatore tra chiave e valore. Per esempio, con => e con un hash del tipo '{ciao => "mondo"}', il risultato sarà ciao => mondo).
-- valsep (il separatore tra un valore. Per esempio, con , come valsep e con => come kvsep, con un hash del tipo '{mondo => "bello", dicosulserio => "si"}', il risultato sarà: mondo => bello, dicosulserio => si)
-- onlyVals (questa variabile puo' essere 0 o 1, indica se visualizzare solo i valori e non le chiavi)
-- onlyKeys (questa variabile pou' essere 0 o 1, indica se visualizzare solo le chiavi e non i valori)
-- hash (l'hash reference)
~~~~~~~~~~~~~~~~~~~
- preg_quote ~ questa funzione è basata sulla regex creata dal sito phpjs.org, e serve per fare l'escape di caratteri speciali riservati alle regex. Parametri:
-- str (la stringa da escapare)
~~~~~~~~~~~~~~~~~~~
- matchServerNumeric ~ questa funzione serve per matchare il numeric di un server, ovvero una risposta numerica del server. Nota che questa funzione non mostrerà il valore restituito dal server, ma solo 0 o 1 a seconda del match. Parametri:
-- rcnick (alias di regex compatible nick, ovvero il nick 'trattato' con preg_quote)
-- rcserver (lo stesso di prima, ma con il server)
-- numeric (numeric da matchare)
-- onWhat (su cosa matchare; dev'essere una risposta del server)
~~~~~~~~~~~~~~~~~~~
- trim ~ questa funzione serve per eliminare caratteri inutili da una stringa. Eliminerà gli \n, i \r, i \r\n e gli \s dall'inizio e dalla fine di una stringa. Utile per usare risposte del server.
-- str (stringa da 'trimmare')

Finalmente siamo giunti alla fine delle classi principali. Prima di introdurre i moduli, questo è l'usage del bot:
use Plib::main;
my $plib = Plib::main->new ("nick", "ident", "real", "idpass", op, debug, ssl, "server, "port");
$plib->setChans ("#canale1", "#canale2", "#canale3:chiave");
$plib->hook_modules ("modulo1", "modulo2");
$plib->startAll;
Dettagli sui vari parametri li trovate all'inizio.

Ed ora passiamo ai moduli. Un modulo è uno script Perl usato per aggiungere funzionalità al bot. Il modulo deve essere nella cartella "Plib/modules/" ed estensione "pm" (perl module).
Creare un modulo è molto semplice. Un esempio è il modulo predefinito "firstplugin".
Ma vediamo come farne uno da 0! :)
Innanzitutto, aggiungiamo il solito "#!/usr/bin/perl" (o il proprio path a Perl) nella prima riga del file.
Poi, aggiungiamo sotto questo:
package Plib::modules::nomemodulo;
In pratica questa riga serve per dire a Perl che questo è un modulo che fa parte di "Plib::modules". Il "nomemodulo" deve avere lo stesso nome del file del modulo, e non deve avere spazi.
Sotto alla linea package, è possibile includere qualsiasi altro modulo Perl, a seconda delle proprie esigenze (come per esempio IO::Socket, per dirne una).
Passiamo ora a crare la funzione costruttrice: new.
Innanzitutto, se non dobbiamo far configurare nulla all'utente in questo plugin, possiamo tranquillamente fare:
sub new { return $_[0]; }
Ovvero, quando verrà chiamato il main, verrà restituita l'istanza della classe con le sole funzioni, e nessuna variabile.
Se invece dobbiamo far configurare qualcosa all'utente, semplicemente facciamo una cosa del genere:
sub new {
	my $opzione = "giallo";
	my $coloremutande = "verde";
	## FINE CONFIGURAZIONE !! ##
	my $options = { "opzione" => $opzione, "coloremutande" => $coloremutande };
	bless $options, $_[0];
	return $options;
}

Questo snippet sembra complesso, ma in realta' e' molto semplice. Innanzitutto come potrete notare le opzioni sono nella funzione stessa, precedute da "my" e con il valore tra virgolette.
Una volta finita la configurazione, creiamo una hash reference con le chiavi pari a quelle del nome delle variabili, e il valore con quello delle variabili. Ovviamente è possibile specificare anche nomi diversi delle chiavi. Una volta fatto, lanciamo la funzione "bless" con due argomenti. Questa funzione serve per rendere un oggetto parte del package. Quindi, in questo caso, si rende l'hash "options" parte del package "nomemodulo". Infatti, $_[0] significa "il primo parametro", ovvero il nome del package. Per finire, ritorniamo il nuovo $options, che equivale a ritornare l'istanza della classe.

Adesso passiamo a definire le funzioni che saranno usate da PlIB: atInit e atWhile.
atInit è la funzione che viene richiamata quando il server invia il messaggio di fine motd / motd non presente, e dopo il join/identify. Quindi per esempio, con questa funzione è possibile stampare un hello world su tutti i canali. I parametri che vengono passati sono "isTest" e "botClass". isTest è una variabile che viene passata per fare un test, ovvero per verificare se la funzione esiste e si esegue correttamente o no. Dopo vedremo cosa farcene. Poi viene passato "botClass", ovvero la classe principale del bot.
Ecco un semplice esempio che stampa un "Hello world!" su tutti i chan joinati.
sub atInit {
	my ($self, $isTest, $botClass) = @_; # Da notare che come primo parametro viene passato 'self', ovvero l'istanza della classe principale (nomeplugin in questo caso)
	return 1 if $isTest; # Se e' un test, ritorniamo uno. Possiamo ritornare anche 0, 5, 324535 o quello che vogliamo. In questo modo fermiamo l'esecuzione della funzione.
	$botClass->sendMsg ($botClass->getAllChannels (",", 0), "Hello world!"); # La funzione vera e propria, che invia un messaggio a tutti i chan separati da una virgola con il contenuto "Hello world!". Semplice, vero? :P
}
Ecco qui la funzione, ampliamente commentata.
Adesso passiamo all'ultimo argomento di questa guida, ovvero la funzione 'atWhile', che viene eseguita ogni volta che il server invia qualcosa.
I parametri che vengono passati sono isTest (che abbiamo già visto prima), botClass (la classe principale, ovvero main), sent (cosa ha inviato il server), nick (il nick dell'utente, se presente, che ha fatto un azione), ident (l'ident dell'utente, sempre se presente), host (l'hostmask dell'utente, se presente ovviamente).
Vediamo un esempio che registra il comando "!ciao" che outputta "Ciao mondo!"..
sub atWhile {
	my ($self, $isTest, $botClass, $sent, $nick, $ident, $host) = @_;
	return 1 if $isTest;
	my $info; # Comincio a registrare questa variabile che conterra' l'hashref ritornato da matchMsg (i dettagli stanno all'inizio!)
	if ($nick and $ident and $host and $info = $botClass->matchMsg ($sent) and $info->{"message"} =~ /^!ciao/i) { # Niente paura! Non è niente di difficile. Innanzitutto controlliamo se $nick, $ident e $host sono dichiarati. Poi controlliamo se quello che è stato inviato è un messaggio, in caso positivo assegnamo l'hashref generato da matchMsg. Infine controlliamo se il message matcha !ciao. Il ^ iniziale è per evitare che matchi anche frasi come ciao, hai visto il comando !ciao ?, mentre il /i finale serve per rendere case insensitive, ovvero per farlo funzionare sia con !cIao sia con !CiAo sia con qualsiasi altra cosa.
		$botClass->sendMsg ($info->{"chan"}, "Ciao mondo!"); # Inviamo il messaggio al chan dove è stato inviato il messaggio principale
	}
}
1;
Da notare l'uno finale, mi raccomando di inserirlo sempre, altrimenti il vostro plugin darà un errore!

Questo è tutto. In fondo, non è così complicato, o sbaglio? Buon divertimento, con la vostra copia di PlIB!

Robertof.
robertof [at] anche {Dot} no
Enjoy :)
 
Stato
Discussione chiusa ad ulteriori risposte.