Olá pessoal, minha primeira e por sinal simples implementação em Lua foi a de um IRC Bot capaz de responder a um comando dado pelo owner (proprietário) e responder a mensagens de usuários do canal. Segue abaixo uma breve explicação dos passos básicos para criação de um bot.
Como diz no título, eu utilizei a extensão LuaSocket, que provê suporte para TCP e UDP, e um conjunto de módulos com funcionalidades comuns de uma aplicação para internet. (HTTP, FTP, MIME, etc)
O site da extensão é http://www.cs.princeton.edu/~diego/professional/luasocket/, e tem um link explicando sobre a instalação, é bem simples!
Vamos aos códigos!
Assim temos na variável global irc acesso as funções e variáveis globais do módulo requerido.
Para fazer a conexão é bem simples, basta informar o server e a porta, por exemplo:
-- Conexão
client = irc.connect('irc.brasnet.org', 6667)
Para testar se a conexão foi estabelecida:
if client == nil then
print('Nao foi possivel conectar!')
os.exit()
end
Para especificarmos que nossa conexão é Keep-alive:
client:setoption('keepalive', true)
Bom, já com a conexão estabelecida, precisamos enviar umas informações do cliente (do bot) para o servidor de IRC.
-- Dados do Bot
bot = {}
-- Nick do bot
bot.nick = 'myLUABot'
-- Nome do bot
bot.name = 'LuaBot - by Eclesiastes'
-- Identd
bot.identd = 'bot.lua'
-- Canal a entrar
bot.channel = '#a,#b,#c'
client:send("USER " .. bot.identd .. " 2 3 :" .. bot.name .. "\r\n")
client:send("NICK " .. bot.nick .. " " .. bot.identd .. "\r\n")
client:send("JOIN " .. bot.channel .. "\r\n")
client:send("PRIVMSG " .. bot.channel .. "\r\n")
Assim feito, o bot estará identificado no servidor.
Pronto, a partir daí basta fazer um loop que termina somente quando não receber mais dados do servidor. E de acordo com os dados, você pode programar o bot para efetuar uma operação correspondente. Como por exemplo, responder a mensagem PING, caso não seja respondida, acarretará em desconexão.
Deixo então essa operação para vocês! Deixo abaixo o meu código-fonte para solucionar alguma possível dúvida.
E qualquer dúvida quanto ao protocolo, acesse: http://www.irchelp.org/irchelp/rfc/.
> bot.lua
------------------------------------------------------------------------------
-- LuaBot - IRC bot
-- Author: Felipe Nascimento S. Pena
-- E-mail: felipensp [at] gmail [dot] com
-- Date : 2007-02-07
------------------------------------------------------------------------------
irc = require("socket")
require("ecl.bot.botlib")
-- Verificando os argumentos
-- IP do servidor
if arg[1] == nil then
print('Informe o server!')
os.exit()
end
local server = arg[1]
-- Porta
if arg[2] == nil then
print('Informe a porta!')
os.exit()
end
local port = arg[2]
-- Canal
if arg[3] == nil then
print('Informe o canal!')
os.exit()
end
-- Dados do Bot
bot = {}
-- Nick do bot
bot.nick = 'LUABot'
-- Nome do bot
bot.name = 'LuaBot - by Eclesiastes'
bot.identd = 'bot.lua'
-- Dono do bot
bot.owner = 'ecl'
-- Canal a entrar
bot.channel = arg[3]
-- Conexão
client = irc.connect(server, port)
if client == nil then
print('Nao foi possivel conectar!')
os.exit()
end
client:setoption('keepalive', true)
print('>> LUA Bot (by Eclesiastes)')
print('Conectando em ' .. client:getpeername())
print('---------------------------------------')
client:send("USER " .. bot.identd .. " 2 3 :" .. bot.name .. "\r\n")
client:send("NICK " .. bot.nick .. " " .. bot.identd .. "\r\n")
client:send("JOIN " .. bot.channel .. "\r\n")
client:send("PRIVMSG " .. bot.channel .. "\r\n")
-- Definindo o cliente e os dados do bot
luabot:set(client, bot)
-- Mensagem de entrada no canal
luabot:sendtochannel('y0! Ladies & Gentlemen! :Þ')
repeat
-- Recebendo mensagem
msg = client:receive()
-- Exibe as mensagens recebidas
-- print(msg)
-- Verifica mensagem de ping
luabot:ping(msg)
-- Verifica mensagens recebidas e responde se necessário
luabot:receive(msg)
until msg == nil
-- Stats
-- Bytes enviados, recebidos em segundos
print('Stats')
print('---------------------------------------')
print('Enviado\tRecebido')
print(client:getstats())
O caminho está "ecl.bot.botlib" pois a botlib.lua está em C:\lua\ecl\bot\.
> botlib.lua
------------------------------------------------------------------------------
-- Funcionalidades do bot
-- LuaBot - IRC bot
-- Author: Felipe Nascimento S. Pena
-- E-mail: felipensp [at] gmail [dot] com
-- Date : 2007-02-07
------------------------------------------------------------------------------
luabot = {}
-- Define a conexão e os dados do bot
function luabot:set(client, bot)
self.client = client
self.bot = bot
end
-- Ping pong
function luabot:ping(msg)
if msg ~= nil then
local _,_, daemon = string.find(msg, '^PING :(.+)')
if daemon ~= nil then
self.client:send('PONG :' .. daemon)
end
end
end
-- Envia mensagem para um canal
function luabot:sendtochannel(msg, chan)
if chan == nil then
self.client:send('PRIVMSG ' .. self.bot.channel .. ' :' .. msg .. "\r\n")
else
self.client:send('PRIVMSG ' .. chan .. ' :' .. msg .. "\r\n")
end
end
-- Envia mensagem para um usuário
function luabot:sendtonick(chan, nick, msg)
self.client:send('PRIVMSG ' .. chan .. ' :' .. nick .. ': ' .. msg .. "\r\n")
end
-- Entra em um canal
function luabot:join(channel)
self.client:send('JOIN ' .. channel .. '\r\n')
end
-- Sai de um canal
function luabot:part(channel)
self.client:send('PART ' .. channel .. '\r\n')
end
-- Executa uma ação enviada solicitada pelo owner
function luabot:owner_cmd(chan, cmd)
-- Debug
-- print('O chefe mandou: ' .. cmd)
-- Fechar conexão
if string.find(cmd, '^exit$') then
self:quit()
-- Sair de um canal
elseif string.find(cmd, '^part') then
local _,_, chan = string.find(cmd, '^part (#%S+)')
if chan ~= nil then
self:part(chan)
end
-- Entrar em canal
elseif string.find(cmd, '^join') then
local _,_, chan = string.find(cmd, '^join (#%S+)')
if chan ~= nil then
self:join(chan)
end
elseif string.find(cmd, '^kiss') then
local _,_, user = string.find(cmd, '^kiss (%S+)')
if user ~= nil then
self:sendtonick(chan, user, ':@;')
end
end
end
-- Responde uma mensagem enviada ao bot
function luabot:user_msg(chan, sender, msgr)
-- Debug
-- print('O user ' .. sender .. ' disse para mim: ' .. msgr)
-- Retribuindo um beijo
if string.find(msgr, '^[:;]@[:;]') then
self:sendtonick(chan, sender, msgr)
-- Respondendo uma pergunta
elseif string.find(msgr, '^qual eh o seu nome?') then
self:sendtonick(chan, sender, 'Nem sei hein... :Þ')
-- Respondendo um olhar espantado
elseif string.find(msgr, '^o[.,_]o') then
self:sendtonick(chan, sender, 'O.o')
end
end
-- Lê os dados recebidos e responde se necessário
function luabot:receive(msg)
if msg ~= nil then
-- Comando do owner no canal
local _,_, chan, cmd = string.find(msg, ':' .. self.bot.owner .. '!%S+ PRIVMSG (#%S+) :!(.+)')
if cmd ~= nil then
self:owner_cmd(chan, string.lower(cmd))
return
end
-- Mensagens no canal para o bot
local _,_, sender, chan, msgr = string.find(msg, ':([^!]+)!%S+ PRIVMSG (%S+) :' .. self.bot.nick ..': (.+)')
if msgr ~= nil then
self:user_msg(chan, sender, string.lower(msgr))
return
end
-- Mensagens no canal
-- local _,_, sender, chan, msgr = string.find(msg, ':([^!]+)!%S+ PRIVMSG (%S+) :!(.+)')
end
end
-- Fechar conexão
function luabot:quit()
self.client:send("QUIT :É duro ser bot! :~\r\n")
self.client:close()
end
Como podem ver, eu passo o server, porta e canal como argumento.
Por exemplo:
c:\lua>lua "ecl/bot/bot.lua" irc.brasnet.org 6665 #phpavancado
Sobre as funções disponíveis para um conexão TCP usando LuaSocket:
http://www.cs.princeton.edu/~diego/professional/luasocket/tcp.html
Até a próxima!