Ayuda al desarrollador de plugins de Botube2

  • por javier
  • 22 de Marzo de 2023

Ayuda al desarrollador de plugins de Botube2


botube2

Vamos a estudiar, a modo de ejemplo, el plugin "last", para descubrir cómo programar plugins en botube2.

1. Importación de bibliotecas Python. En éstas líneas, se deben importar los siguientes archivos:

from commands import DBC, commands

import time, re
import config

Del archivo <commmands>, es importante incluir la clase <commands>, que nos permitirá dotar a nuestro plugin de eventos y realizar llamadas a acciones relacionadas con el ambito del IRC.</commands></commmands>

También deberemos incluir DBC, que se trata de una clase base para la interacción con la base de datos MySQL y deberemos instanciar como clase base en nuestro plugin. En <config> podremos hallar configuraciones personalizadas del programa, que deberían estar actualizadas para el uso del bot. También existen parámetros de ayuda al programa que son esenciales para el funcionamiento de éste. Esto incluye los plugins. </config>

2. Nivel mínimo de Acceso a la funcionalidad del plugin.

ACCESS="User"

Los niveles validos y predefinidos, son : None, User, Master, lo que permite configurar quién accederá a nuestro plugin. El comando !set access , permite configurar dichos niveles de acceso.

3. Expresion Regular del comando que definimos y Ayuda del plugin.

HCODE=config.HLAST
regexp="^last ([\\w\\_\\^\\d]+)"
HELP=[
    "!last <nickname>",
    "Shows last activity time from selected nick",
    "Example: !last Javitux"]


</nickname>

En éstas líneas, que son obligatorias también, configuramos:

  HCODE=config.HLAST

Aquí pondremos un identificador, previamente definido con un número único en los definidos en config y se lo asignamos a HCODE. Si creamos un nuevo plugin, pondremos, por ejemplo : HNUEVOCOMANDO= NN en config, ésta línea será HCODE=config.HNUEVOCOMANDO

regexp consiste en una expresion regular que filtará los comandos validos para acceder a nuestro plugin sin el simbolo de exclamacion. En éste caso, podemos ver que se define el comando last en minusculas y después de un espacio, debería ir una palabra con dígitos o guiones bajos. Dicha expresión va entre paréntesis, ya que se extraerá como parámetro para nuestro plugin. Si queremos, podemos definir tantos parámetros como queramos.

HELP. Es una lista con 3 o más cadenas de caracteres, de las cuales, la primera contiene la sintaxis del comando. La segunda, y subsiguientes, contiene el mismo texto de ayuda y las últimas líneas, contienen como mínimo un ejemplo de uso. Esto servirá para integrar nuestro plugin en el sistema de ayuda de botube2, que dicho sea de paso, es un plugin también (help).

4. Capa de modelo de datos. Clase implementada sobre la anteriormente importada (DBC).

class MDBC(DBC):

    def __init__(self, db):

        super(MDBC, self).__init__(db)

    def lastNick(self, nickName, nick):

        gmt=self.getGMT(nick)
        query=''''''SELECT CONVERT_TZ(MAX(ev.datetime), ''+00:00'', ''%s'') as dt FROM Events as ev, Nicks as n
        WHERE n.idNick=ev.idNick AND n.NickName regexp ''^%s$'';'''''' % (gmt, re.escape(nickName))
        row=self.conn.select(query)

        return (row, gmt) # dt


Aquí podemos ver que se llama para su inicialización, en __init__ a la clase padre. Esto debe siempre estar presente, ya que sin esa inicialización, probablemente no funcione bien nuestra clase de modelo de datos. Podemos añadir a dicha definición, los métodos que necesitemos para nuestro plugin. Si queremos modificar la base de datos, podemos hacerlo, pero siempre añadiendo tablas aparte a las ya existentes. Si no respetamos ésto, podría no funcionar bien nuestro bot, así que se recomienda encarecidamente lo previamente expuesto. En el caso del método del plugin <last> lastNick, podemos ver que se obtiene mediante la clase padre y getGMT la zona horaria del nick seleccionado. Posteriormente, se define una consulta a la base de datos y se devuelven los datos que se necesitan. Para ejecutar la sentencia SQL SELECT, podemos usar self.conn.select(query) para efectuar la llamada a la clase padre y que nos devuelva los datos. Si se trata de sentencias SQL distintas de SELECT (DROP, UPDATE...) deberemos llamar a self.conn.execute(query).</last>

Por último, se devuelven los datos requeridos por nuestro plugin en return, según necesidades.

5. Clase de Control y Muestra.

Aquí podemos definir propiamente el funcionamiento de los comandos de nuestro plugin y la respuesta a eventos del sistema (onJoin cuando se une alguien al canal, onQuit cuando abandona alguien el IRC, etc... : mirar commands.py para mas informacion).

>class mcommands(commands):

    def __init__(self, fsend, db):

        super(mcommands, self).__init__(fsend, db, regexp=regexp)

    def execute(self, nick, ip, channel, operation):

        if self.preExecute(ACCESS, operation, nick, HELP):

            (row, gmt)=self.db.lastNick(self.b[0], nick)
            if len(row)>0 and row[0][0] is not None:
                response="%s last seen at %s (gmt%s)" % (self.b[0], row[0][0], gmt)
            else:
                response="%s Not found" % (self.b[0])
            self.sendChannel(response)
            return True
        else:
            return False        

Las 3 primeras líneas son obligatorias y deben estar ahí, tal cual, como inicialización de la clase base.

- Si no se quiere ejecutar un comando específico en el plugin, deberemos preceder su nombre de archivo con guion bajo "_". Puedes ver _url.py como ejemplo de éste caso específico. -

El resto, será propio de nuestro plugin. En éste caso, execute es el método que ejecutará las órdenes definidas en nuestro plugin, esto es, las precedidas del síbolo de exclamación, por ejemplo !last. Así será en todos los casos para dicho tipo de comandos. La redefinición de execute, debe ser siempre la misma. Así como la línea que sigue (self.preExecute), que nos controlará los accesos al plugin además de extraer en self.b los parámetros definidos en la expresión regular definida el principio del plugin.

Esta funcion deberá devolver True, si se ejecutó el plugin y False, caso contrario. De ésta manera, podremos hacer que botube2 detecte errores de sintaxis en la definición de la expresión regular de nuestro plugin.

En cuanto al resto de comandos de execute, podemos ver que se llama a la capa modelo de datos, método lastNick, con el nombre de nick como primer parámetro y como segundo, el nick de la persona que llama al plugin. Posteriormente, se comprueba que los datos recibidos del modelo de datos, son correctos y de esa manera, verificamos que el nick se encuentra en la base de datos. Asignamos la respuesta adecuada a la variable response, la cual no tiene porqué llamarse así, pero en éste caso, la utilizamos en self.sendChannel, de modo que podamos ver en nuestro cliente de IRC el correspondiente mensaje de última actividad del nick en el canal o bien el mensaje de nick not found (no encontrado).

Añadir que deberemos añadir el nombre de nuestro plugin en el archivo botube2.py para registrarlo de ésta manera:

from plugins import help, last, search, set_access, set_autoop, set_autovoice, set_gmt, stats, set_kickban

Aquí podemos ver que last está como plugin registrado en botube2. Si activamos el DEBUG en config.py, podremos ver qué plugins se cargan y otros mensajes de funcionamiento de botube2, incluido nuestro plugin.

Para fallos, mejoras y cualquier tipo de problema o feedback, no dudeis en postear en sourceforge y os ayudaré encantado.

https://sourceforge.net/projects/botube2/ Javier García <javiergargon at="" gmail.com=""></javiergargon>

blog comments powered by Disqus

Puertos trampa, con python e iptables

  • por javier
  • 22 de Marzo de 2023

Otro quick&dirty script en python. En éste caso, vamos a crear los "puertos trampa" que queramos, de manera que quien se conecte, se bloqueará mediante una sencilla regla de iptables. Para ello, nuestro firewall deberá estar basado en iptables, caso contrario, no funcionará el invento. Sin más dilación, os muestro el script, que os podeis descargar al final del artículo.

Update cookies preferences