Back to site
Since 2004, our University project has become the Internet's most widespread web hosting directory. Here we like to talk a lot about web servers, web development, networking and security services. It is, after all, our expertise. To make things better we've launched this science section with the free access to educational resources and important scientific material translated to different languages.

IRC bot

Brian Seitz ( brian@wholok.com )
http://wholok.com/
Napravljeno: 2001-11-10


Šta je to IRC bot?

Automatizovani klijent:

Jedan IRC server, IRC bot se virtuelno ne razlikuje od regularnog IRC klijenta (npr osoba koja koristi program kao što je X-Chat, mIRC, ili ircii). Ipak ne postoji osoba koja kuca iza IRC bot.Ima samo automatizovane odgovore, bazirane na (obično) onome što se dešava sa IRC. IRC bot može da radi stvari bazirane na javnim porukama, privatnim porukama, pingovima, ili bilo kom drugom IRC događaju. Ali bot nije limitiranna svet IRC. Može da omunicira sa bazom podataka, mrežom, sistemom fajlova, ili sa bilo čim drugim što vi možete da zamislite.

Primeri:

Evo nekih uobičajenih IRC bota koji ste možda skoro videli na vašim putovanjima:

  • Serviranje fajlova: Ovaj tip bota radi na FTP programu tako što ima intrakciju sa sistemom fajla. Korisnici razgovaraju sa botom koristeći privatne poruke sa komandama kao što su "ls" i "get". Korisnici mogu da šalju i primaju podatke koristeći DCC (kao deoIRC koja dozvoljava inicijalizaciju lice u loce transfera fajlova).
  • Administracija kanala: Ovaj bot zadržava listu kanalnih opcija (ljudi koji pokreu kanal) i siguran je da je u kontroli toga, čak i kada su individualni ljudi diskonektovani. Channel administration: This bot maintains a list of channel ops (people who run the channel) and makes sure they stay in control of it, even if individual people are disconnected. They may also kick people from the channel who violate its etiquette (e.g., talking in all caps, using colors, flooding, etc.)
  • Games: Some bots will allow the people in the channel to text-based games. We'll learn later how to program a trivia bot.

Etikete:

Mnoge IRC mreže ograničavaju upotrebu bot. Kada se ulogujete na IRC server proverite (dnevne poruke) koja je polisa bota. Ako narušite ta pravila, može vam se zabraniti pristup serveru.

U praksi, ipak, bot se automatski ne određuje. Sve dok se bot ne priključi već ostvarenim kanalima i ne bude ljude nervirao, nećete imati nikakvih problema. Ali IRC kanali su besplatni, napravite vaš izbor, pozovite prijatelja, i imajte žurku.

Ako želite da okruženje bude sigurno, možrtr pokrenuti i vaš sopstveni IRC server. Ako planirate neko dugoročno debagging, pokrenite IRC na lokalnom postu što će vam mnogo vremena uštedeti. Proverite generic IRCd i DALnet's Bahamut IRCd. Ovo su veoma stabilni programi i trebalo bi da se veoma lako kompajliraju na UNUX sistemu, ipak, ove specifikacije konfuguracija su iznad mogućnosti ovog dokumenta.

Šta vam je potrebno za programiranje jednog IRC bota

Perl

Možete da programirate u IRC bot na bilo kom jeziku. Neki IRC klijenti nude svoje sopstvene skriptovane jezike koji automatski dodaju funkcije vašim normalnim IRC sesijama. Ipak, koristićemo Perl.

Net::IRC Module

Net::IRC je Perl modul koji govori IRC protokolom, abstrakujući večinu detalja programa na niskom nivou kod programiranja u IRC bot. On prevashodno radi na programiranju događaja (o čemu ćemo kasnije) Možete doći do Net::IRC na CPAN.

IRC server

Trebaće vam IRC server za konekciju. Veoma razumljiva lista može se naći na at irchelp.org. Ipak, proces antivirus ima u svrhu, samopokretanja kod svog IRC servera.

Drugi softveri za funkcionalnost

Ni jedan IRC bot nije ostrvo. Dok neki IRC bot, kao što je kanalska administracija, mogu biti korisni bez bilo kog interfejsa u spoljašnjem svetu, koristićemo neke ne-IRC-specifične softvere da bi naš bot nije bio koristan.

Program koristi bot u tutorijalu, koristićete Perl module LWP (Biblioteka za WWW pristup Perl), HTML::Parser, i Text::Wrapper. Za TriviaBot, koristićemo MySQL bazu podataka il DBI modul. Dok učimo o IRC bot, možete takoše naći Data::Dumper modul veoma korisnim. Idite na CPAN da bi ste dobili ove info ako ih već nemate.

Veoma jednostavan bot: HelloBot

Šta HelloBot radi

HelloBot je pozdravni bot. Kada korisnik, hajde da ga nazovemo "Joe," pristupi kanalima, HelloBot će reći "Hello, Joe!" Kada Joe ode, HelloBot će reći "Goodbye, Joe!" (Naravno, pošto je Joe već otišao, neće videti poruku, ali drugi koji koriste kanale hoće.)

[02:03:53] HelloBot (brian@L36-72.DATANET.NYU.EDU) has joined ##
[02:03:53] <HelloBot> Hello everyone!
[02:03:53] <HelloBot> Hello, HelloBot!
[02:04:20] Harry (brian@turtle.wholok.com) has joined ##
[02:04:20] <HelloBot> Hello, Harry!
[02:04:25] Sally (brian@turtle.wholok.com) has left ##
[02:04:25] <HelloBot> Goodbye, Sally!
[02:04:38] Harry (brian@turtle.wholok.com) has left ##
[02:04:38] <HelloBot> Goodbye, Harry!

Stvaranje $irc objekata

Prva stvar koja nam je neophodna pri stvaranju jeste $irc objekat. Taj $irc objekat može da se nosi sa više od jedneIRC konekcije, ali za ovaj tutorijal mi ćemo samo koristiti jednu. Pa hajde da to uradimo:

use Net::IRC;

# create the IRC object
my $irc = new Net::IRC;

Stvaranje $conn objekata

Sada bi trebalo da napravimo objekat konekcije. To zahteva nekoliko argumenata, koji bi trebalo da imaju smisla ako poznajete IRC. Naša interakcija sa IRC serverom biće prikazana kroz $conn objekat.

# Napravite konekciju objekta. Možete imati više od jednog "connection" per

# IRC objekat,ali ćemo samo raditi sa jednim.

my $conn = $irc->newconn(
	Server 		=> shift || 'turtle.wholok.com',
	# Note: IRC port is normally 6667, but my firewall won't allow it
	Port		=> shift || '80',
	Nick		=> 'HelloBot',
	Ircname		=> 'I like to greet!',
	Username	=> 'hello'
);

# We're going to add this to the conn hash so we know what channel we
# want to operate in.
$conn->{channel} = shift || '##';

Ovaj "shift ||" deo nam dozvoljava da promenimo ove parametre u komandoj liniji. Na primer, mogu da pokrenem:

./hello_nick.pl irc.slashnet.org 6667 #mychannel

Programiranje na osnovu događaja

Dakle kako HelloBot zna kada neko pristupi kanalu? Kod iterativnih programa povući ćete IRC rukovođenje fajlom, parsirati input, i pozvati podrutinu ako imate povezani ili napušteni događaj. Koristeći Net::IRC uklanjate prva dva koraka. Samo morate da odlučite koji događaj hoćete da rukovodite, i da definišete podrutinu kojom se rukovodimo.

on_connect

Prvo, događaj moramo da rukovodimo što se tiče povezivanja. Znamo da smo povezani kada dođemo do kraja MOTD događaja, što je normalno za slanje jednog IRC servera. Ovaj dogašaj ima vrednost "376". Kada dođemo do događaja, ono što želimo je priključenje kanalu i pozdrav. Evo kako:

sub on_connect {

	# shift in our connection object that is passed automatically
	my $conn = shift;
  
	# when we connect, join our channel and greet it
	$conn->join($conn->{channel});
	$conn->privmsg($conn->{channel}, 'Hello everyone!');
	$conn->{connected} = 1;
}

# Kraj MOTD (poruka dana), broj 376 označava da smo povezani 

$conn->add_handler('376', \&on_connect);

Kod on_connect subrutine, mi uvodimo dve metode $conn objekata, povezivanje i privmsg. Povezivanje jednostavno zauzima kanal kao argument. prvimsg je malo više komplikovano. Koristi se za slanje i privatnih i javnih poruka (uprkos imenu). Ako ime kanala stavite kao prvi argumnt, javno ćete ga poslati kanalu. Ako stavite nadimak, poslaćete ga privatno osobi koja ima taj nadimak. Drugi argument jeste niz koji želite da pošaljete.

Kada podesimo niz, koristimo add_handler metodu da bi se povezali sa događajem kojim rukovodimo. Prvi argument jeste rukovođenje događajima, što jeste niz "376," ne broj 376. Neće raditi ako pošajete to u formi broja. najpopularniji događaji se identifikiću kao alfabetski niz, kao što ćemo kasnije videti. Sledeći argumen jeste referenca funkcije.

on_join

Sledeće ćemo podesiti naš udruženi rukovodilac:

sub on_join {

	# get our connection object and the event object, which is passed
	# with this event automatically
	my ($conn, $event) = @_;

	# this is the nick that just joined
	my $nick = $event->{nick};
	# say hello to the nick in public
	$conn->privmsg($conn->{channel}, "Hello, $nick!");
}

$conn->add_handler('join', \&on_join);

Sledeći niz ovde jeste $event pored toga što je prebačen na funkciju. Većina rukovodilaca funkcijama će uzeti ovo kao argument (to je jedini argument koji će rukovodilac preuzeti, ako se ne uzme u obzir objekat, naravno). Zavisno od događaja sadržaj će varireti. Kasnije ćemo videti kako da odštampamo sadržaj $event da bi smo naučili kako da programiramo za različite dogašaje. Jedini deo to $event u koji smo zainteresovani jeste ovde nadimak koji se odnosi na događaj. To se odvija na očiglednom mestu, kao što možemo videti. Sledeće kažemo "Hello" nadimku.

$irc->start()

Sada kada smo sve podesili, spremni smo da započnemo IRC. Ovo se radi pomoću jednostavne komande:

$irc->start();

Sada bi trebalo da smo povezani i spremni za akciju. Primetite da koristimo pri objekat koji smo napravili, $irc, a ne $conn objekat. To je zato jer Net::IRC može da rukovodi sa više od jedne IRC konekcije u jednom trenutku operacije.

Rukovođenje drugim komandama: RokerBot

Šta RokerBot radi

RokerBot (takoše će vam trebati WeatherGet.pm i WeatherParse.pm) ima povratnu informaciju o vremenskim prilikama sa http://www.weatherunderground.com/auto/roker/ i šalje ih IRC. To radi uvek kada korisnik kaže "!roker [city], [state]"

[02:03:40] RokerBot (roker@turtle.wholok.com) has joined ##
[02:03:40] <RokerBot> booya!  it's Roker time!
[02:05:58] <wholok> !roker New York, NY
[02:05:59] <RokerBot> wholok, it's 50 F in New York, NY right now. Wind 
	is NNW at 8 mph.  Humidity is 61%.  Roker would say it's Clear.  
	Tonight Mostly clear.  Lows in the lower 40s.  North wind 10 to 
	15 mph becoming light. Thursday Mostly sunny.  Highs in the upper
	50s.  Light and variable wind becoming south and increasing to 10 mph.
[02:08:55] <wholok> !roker adsfoi34 234lkndf
[02:08:57] <RokerBot> Unable to retrieve weather.  Sorry, wholok.

on_public

Ovo je novi događaj kome rukovodimo, događaj sa javnim porukama. Evo kako RokerBot rukuje s tim:

sub on_public {

	# on an event, we get connection object and event hash
	my ($conn, $event) = @_;

	# this is what was said in the event
	my $text = $event->{args}[0];
	
	# regex the text to see if it begins with !roker
	if ($text =~ /^\!roker (.+)/) {
		
		# if so, pass the text and the nick off to the weather method
		my $weather_text = weather($1, $event->{nick});
	
		# wrap text at 400 chars (about as much as you should put
		# into a single IRC message
		my $wrapped_text = $wrapper->wrap($weather_text);
		my @texts = split("\n", $wrapped_text);
		
		# $event->{to}[0] is the channel where this was said
		foreach (@texts) {
			$conn->privmsg($event->{to}[0], $_);
		}	
	}
}
$conn->add_handler('public', \&on_public);


Evo dva nova dela $event hash sa kojima rukujemo. Prvi je $event->{args}. To se odnosi na strelice. Prva vrednost u ovoj strelici jeste tekst javne poruke. Vraćamo se na tekst da bi smo ga proverili ako počinje sa !roker. Ako je tako, prebacujemo ostatak poruke u bilo koju podrutinu, koja će se vratiti na početan tekst.

Drugi novi $event hash delovi koje tražimo su {to}. To je referenca strelica hsvake pojedinačne celine kojoj je sadržaj bio poslat. U našem slučaju, samo želimo naše ime kanala, tako da preuzimamo prvi deo stranice.

Odavde, umotavamo teskt u određene granice (ponekada izveštaji o vremenksim uslovima mogu biti vema dugački) i vsaki niz mora biti poslat kanalu.

on_msg

Naš sledeći događaj jeste rukovođenje porukama. Poruka jeste privatna poruka koja se direktno šalje IRC botu. Najbolje je koristiti poruke za interakciju sa botom ako će biti mnogo interakcije koja može da remeti korisnike. Nema praktične razlike u korišćenju poruka nasuprot javnim porukama, tako da evo kratkog primera:

sub on_msg {
	my ($conn, $event) = @_;

	# Under normal circumstances, simply reply to the nick that there's
	# no reason to /msg RokerBot.
	$conn->privmsg($event->{nick}, "Don't nobody /msg RokerBot.");
	
}
$conn->add_handler('msg', \&on_msg);

Očigledno, možete načiniti ovu interakciju korsnijom, ali primer pokazuje koncept.

Drugi događaji i metode

Proverite izvorni kod Events.pm (ili uradite perldoc Net::IRC::Events) da vidite kojim drugim događajima IRC bot može da rukuje. Kada ekspirementišete sa tim događajima možete želeti da koristite modul Data::Dumperda bi ste videli koji vam se događaj šalje:

use Data::Dumper;

sub default {

        # This is helpful to see what an event returns.  Data::Dumper will
        # recursively reveal the structure of any value
        my ($conn, $event) = @_;
        print Dumper($event);
}
        
# experiment with the cping event, printing out to standard output
$conn->add_handler('cping', \&default);

Skoro svaki IRC klijent komanda jeste metoda IRC::Connection. Ako pogledate izvor Connection.pm, imaćete prilično dobru dokumentaciju o tome kako ih nazvati. Na primer, evo kako možete da koristite metodu da bi ste napravili nekome op:

$conn-$gt;mode('#linux', '+o', 'tux');

TriviaBot: korišćenje $irc->do_one_loop

Šta TriviaBot radi

TriviaBot (trebaće vam takođe Trivia.pm) uzima pitanja iz baze podataka, postavlja ih, i proverava korisnike i odgovore. Ima i tik pitanja, ali i pored toga mora postojati interval od 10 sekundi između pitanja. Pomoću našeg modela, možemo skoor i ovo uraditi.

[01:52:30] TriviaBot (brian@L36-72.DATANET.NYU.EDU) has joined ##
[01:52:30] <TriviaBot> booya!  it's Trivia time!
[01:53:10] <Joe> !trivon
[01:53:10] <TriviaBot> Trivia is on!  First question in 10 seconds.
[01:53:22] <TriviaBot> Pick a hand.
[01:53:22] <TriviaBot> *****
[01:53:25] <Joe> le
[01:53:30] <Joe> left
[01:53:34] <wholok> ri
[01:53:34] <TriviaBot> ri***
[01:53:35] <wholok> rig
[01:53:35] <TriviaBot> rig**
[01:53:39] <Sally> right
[01:53:39] <TriviaBot> Correct answer by Sally!
[01:53:39] <TriviaBot> right
[01:53:39] <TriviaBot> Next question in 10 seconds
[01:53:51] <TriviaBot> How large is an IPv6 address?
[01:53:51] <TriviaBot> *** ****
[01:53:56] <wholok> really big
[01:54:01] <Joe> 128 bits
[01:54:01] <TriviaBot> Correct answer by Joe!
[01:54:01] <TriviaBot> 128 bits
[01:54:01] <TriviaBot> Next question in 10 seconds
[01:54:12] <Joe> !score
[01:54:12] <TriviaBot> Score:
[01:54:12] <TriviaBot> Sally: 1
[01:54:12] <TriviaBot> Joe: 1
[01:54:13] <TriviaBot> Who invented Perl?
[01:54:13] <TriviaBot> ***** ****
[01:54:28] <Sally> Larry rall
[01:54:28] <TriviaBot> Larry *all
[01:54:32] <wholok> larry wall
[01:54:32] <TriviaBot> Correct answer by wholok!
[01:54:32] <TriviaBot> Larry Wall
[01:54:32] <TriviaBot> Next question in 10 seconds
[01:54:36] <wholok> ha ha Sally!
[01:54:44] <TriviaBot> Who is the Linux mascot?
[01:54:44] <TriviaBot> ***
[01:54:50] <Joe> penguin
[01:54:56] <wholok> TUX!
[01:54:56] <TriviaBot> Correct answer by wholok!
[01:54:56] <TriviaBot> Tux
[01:54:56] <TriviaBot> Next question in 10 seconds
[01:55:08] <TriviaBot> What TV network does Mickey Mouse own?
[01:55:08] <TriviaBot> ***
[01:55:14] <Sally> NBC
[01:55:14] <TriviaBot> *BC
[01:55:19] <wholok> ABC
[01:55:19] <TriviaBot> Correct answer by wholok!
[01:55:19] <TriviaBot> ABC
[01:55:19] <TriviaBot> Next question in 10 seconds
[01:55:23] <wholok> !trivoff
[01:55:23] <TriviaBot> Trivia is off!
[01:55:25] <wholok> !score
[01:55:25] <TriviaBot> Score:
[01:55:25] <TriviaBot> Sally: 1
[01:55:25] <TriviaBot> Joe: 1
[01:55:25] <TriviaBot> wholok: 3

Rukovođenje vremenom

Naš problem je fiksiran metodom do_one_loop. TOvo zauzima položaj početne metode. Nakon uspostavljanja rukovošenja, pozivamo ga ovako:

sub handle_trivia_loop {

        my $conn = shift;

        
        $_ = $conn->{trivia}{status};
        STATUS: {
                if (/^getquestion$/) {
                        # get question from trivia object
                        $conn->{trivia}->get_question();
                        # say the question, and show the hint
                        repeat_question($conn);
                        repeat_hint($conn);
                        last STATUS;
                }
                if (/^waiting$/) {
                        handle_waiting($conn);
                        last STATUS;
                }
        }

}

# while forever, handle_trivia, then do an IRC loop
while (1) {
        
        handle_trivia_loop($conn);
        $irc->do_one_loop();
}       

Unutar handle_trivia_loop, proveravamo vremenski raspon pošto nam je potreban interval od 10 sekundi. Takođe dolazimo do novog pitanja ako nam status pokaže da tako treba. Ipak, proveravanje trivijalnih odgovora i dalje obavlja model na osnovu događaja.

Parsing komande

Jedna od glavnih stavki IRC bot koja se odnosi na javnu komandu jeste i sintaksa "!command". Ovo dozvoljava botu da lako parsira promet kanala, pošto je veoma neobično da bi neko želeo da kaže pravu, realnu rečenicu koja bi počinjala sa "!".

sub on_public {

        
        # two args are passed on events, the connection object and a
        # hash that describes the event
        my ($conn, $event) = @_;
        
        # this is the text of the event, eg, what the person said
        my $text = $event->{args}[0];

        # we first check to see if it's a command (if it starts with !)
        if ($text =~ /^\!(.+)$/) {
                on_public_command($conn, $1, $event->{nick});
        }
        # otherwise, we assume it's a guess to the current question
        else {
                # check the answers
                my $res = $conn->{trivia}->check_answer($event->{nick}, $text);
                # if we've got the right answer, then celebrate
                if ($res) {
                        on_answer($conn, $res, $event->{nick});
                }
                # otherwise, repeat the current hint
                else {
                        repeat_hint($conn);
                }       
                        
        }
}

sub on_public_command {
        
        
        # here, we get the connection object, the text of the command, and
        # the nick of the person who issued the command
        my ($conn, $command, $nick) = @_;

        # branch off given the nature of the command
        $_ = $command;
        COM: {
                # this turns trivia on
                if (/^trivon$/) {
                        
                        # don't turn on trivia unless it's off
                        if ($conn->{trivia}{status} ne '') {
                                last COM;
                        }
                        
                        # set status to wait 10 seconds
                        $conn->{trivia}{status} = 'waiting';
                        # alert users that trivia is starting
                        $conn->privmsg($conn->{channel}, "Trivia is on!  First question in 10 seconds.");
                        # save the current timestamp
                        $conn->{newtime} = time;
                        # set the amount we've waited to 0
                        $conn->{waittime} = 0;
                        last COM;
                
                }
                if (/^trivoff$/) {
                        # set status to nothing 
                        $conn->{trivia}{status} = '';
                        # tell everyone that trivia over
                        $conn->privmsg($conn->{channel}, "Trivia is off!");
                        last COM;       
                }
                if (/^score$/) {
                        # we want to see the scores, so let's have 'em
                        handle_score($conn);
                        last COM;
                }       
        }       
}
Published (Last edited): 21-03-2013 , source: http://wholok.com/irc/