new feature: add modules of commands instead of list of commands
This commit is contained in:
parent
7e33a90fb2
commit
8178a602fd
|
@ -0,0 +1,13 @@
|
|||
from irc_api import api
|
||||
from irc_api.api import auto_help
|
||||
|
||||
|
||||
@api.channel("#glados")
|
||||
@api.on(lambda m: "blague" in m.text.lower())
|
||||
def fun(bot, msg, *args):
|
||||
bot.send(msg.to, "Mais je suis nuuuullle en blagues euh.")
|
||||
|
||||
|
||||
@api.command("limite")
|
||||
def history_limit(bot, msg, *args):
|
||||
bot.send(msg.to, f"limite historique : {bot.history._History__limit}")
|
|
@ -1,5 +1,5 @@
|
|||
from irc_api import api
|
||||
from random import choice
|
||||
from irc_api.api import auto_help
|
||||
|
||||
|
||||
@api.on(lambda m: "au revoir glados" in m.text.lower())
|
||||
|
@ -14,8 +14,7 @@ def greetings_bye(bot, msg, *args):
|
|||
"#glados."
|
||||
)
|
||||
def greetings_hello(bot, msg, *args):
|
||||
bot.send(msg.to, args)
|
||||
bot.send(msg.to, f"Oh un utilisateur sur #glados :o")
|
||||
bot.send(msg.to, f"Bonjour à toi")
|
||||
|
||||
|
||||
@api.command("test")
|
||||
|
@ -26,22 +25,12 @@ def test(bot, msg, *args):
|
|||
|
||||
@api.channel("#glados")
|
||||
def react_on_glados(bot, msg, *args):
|
||||
"""Répond de manière random à tout les messages posté sur #glados."""
|
||||
answers = (
|
||||
f"Yo {msg.author} o/",
|
||||
"Alors, de quoi on parle ?",
|
||||
"Ça va ?",
|
||||
"Bon, tu as fini de spammer ou bien ?",
|
||||
"Ça roule ?",
|
||||
"Hey you! Ah, you finally awake…",
|
||||
)
|
||||
bot.send(msg.to, choice(answers))
|
||||
"""Répète le dernier message envoyé sur #glados."""
|
||||
if bot.history.get()[-1].author == msg.author:
|
||||
bot.counter += 1
|
||||
else:
|
||||
bot.counter = 1
|
||||
|
||||
|
||||
commands = [
|
||||
api.auto_help,
|
||||
greetings_bye,
|
||||
greetings_hello,
|
||||
test,
|
||||
# react_on_glados
|
||||
]
|
||||
if bot.counter > 3:
|
||||
bot.send(msg.to, f"Bon, {msg.author}, tu vas arrêter de spammer un jour ou bien ?")
|
||||
bot.counter = 0
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import logging
|
||||
from irc_api.irc import IRC
|
||||
import re
|
||||
from irc_api.irc import IRC, History
|
||||
|
||||
|
||||
PREFIX = ""
|
||||
|
@ -83,7 +84,14 @@ class Bot:
|
|||
start : NoneType, public
|
||||
Runs the bot and connects it to IRC and V5 servers.
|
||||
"""
|
||||
def __init__(self, auth: tuple, irc_params: tuple, channels: list, prefix: str=""):
|
||||
def __init__(
|
||||
self,
|
||||
auth: tuple,
|
||||
irc_params: tuple,
|
||||
channels: list=["#general"],
|
||||
*commands_modules,
|
||||
**kwargs
|
||||
):
|
||||
"""Initialize the Bot instance.
|
||||
|
||||
Parameters
|
||||
|
@ -96,50 +104,97 @@ class Bot:
|
|||
The prefix on which the bot will react.
|
||||
"""
|
||||
global PREFIX
|
||||
PREFIX = prefix
|
||||
if kwargs.get('prefix'):
|
||||
PREFIX = kwargs.get('prefix')
|
||||
|
||||
self.auth = auth
|
||||
self.irc = IRC(*irc_params)
|
||||
self.history = History(kwargs.get('limit'))
|
||||
self.channels = channels
|
||||
self.auth = auth
|
||||
self.callbacks = {}
|
||||
|
||||
self.send = self.irc.send
|
||||
if commands_modules:
|
||||
self.add_commands_modules(*commands_modules)
|
||||
|
||||
def start(self):
|
||||
"""Starts the bot and connect it to the given IRC and V5 servers."""
|
||||
# Start IRC
|
||||
self.irc.start(self.auth[0], self.auth[1])
|
||||
self.irc.connexion(self.auth[0], self.auth[1])
|
||||
|
||||
# Join channels
|
||||
for channel in self.channels:
|
||||
self.irc.join(channel)
|
||||
|
||||
# Run IRC
|
||||
self.irc.run()
|
||||
# mainloop
|
||||
while True:
|
||||
message = self.irc.receive()
|
||||
self.history.add(message)
|
||||
logging.info("received %s", message)
|
||||
if message is not None:
|
||||
for callback in self.callbacks.values():
|
||||
if not False in [event(message) for event in callback.events]:
|
||||
logging.info("matched %s", callback.name)
|
||||
callback(message, *parse(message.text)[callback.cmnd_type:])
|
||||
|
||||
def add_command(self, command):
|
||||
command.bot = self
|
||||
self.irc.callbacks.append(command)
|
||||
|
||||
def add_commands(self, commands):
|
||||
"""Add a package of commands to the bot.
|
||||
def send(self, target: str, message: str):
|
||||
"""Send a message to the specified target (channel or user).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
commands_pack : CommandsPack
|
||||
A commands pack which contains command's instances.
|
||||
target : str
|
||||
The target of the message. It can be a channel or user (private message).
|
||||
message : str
|
||||
The content of the message to send.
|
||||
"""
|
||||
self.irc.send(f"PRIVMSG {target} :{message}")
|
||||
|
||||
def add_command(self, command):
|
||||
command.bot = self
|
||||
self.callbacks[command.name] = command
|
||||
|
||||
def add_commands(self, *commands):
|
||||
"""Add a list of commands to the bot.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
commands : list
|
||||
A list of command's instances.
|
||||
"""
|
||||
for command in commands:
|
||||
self.add_command(command)
|
||||
|
||||
def add_commands_modules(self, *commands_modules):
|
||||
for commands_module in commands_modules:
|
||||
for cmnd_name in dir(commands_module):
|
||||
cmnd = getattr(commands_module, cmnd_name)
|
||||
if isinstance(cmnd, Command):
|
||||
self.add_command(cmnd)
|
||||
|
||||
def remove_command(self, command_name: str):
|
||||
if command_name in self.callbacks.keys():
|
||||
self.callbacks.pop(command_name)
|
||||
|
||||
|
||||
@command("aide")
|
||||
def auto_help(bot, msg, *args):
|
||||
"""Aide des commandes disponibles."""
|
||||
known_cmnds = {cmnd.name: cmnd for cmnd in bot.irc.callbacks}
|
||||
if args and args[0] in known_cmnds.keys():
|
||||
if args and args[0] in bot.callbacks.keys():
|
||||
bot.send(msg.to, f"Aide sur la commande : {args[0]}")
|
||||
bot.send(msg.to, f" {known_cmnds[args[0]].desc}")
|
||||
bot.send(msg.to, f" {bot.callbacks[args[0]].desc}")
|
||||
else:
|
||||
bot.irc.send(msg.to, f"Liste des commandes ({PREFIX}aide <cmnd> pour plus d'info)")
|
||||
for cmnd in bot.irc.callbacks:
|
||||
bot.irc.send(msg.to, f" – {cmnd.name}")
|
||||
bot.send(msg.to, f"Liste des commandes ({PREFIX}aide <cmnd> pour plus d'info)")
|
||||
for cmnd_name in bot.callbacks.keys():
|
||||
bot.send(msg.to, f" – {cmnd_name}")
|
||||
|
||||
|
||||
def parse(message):
|
||||
pattern = re.compile(r"((\"[\w\ \-\']+\"\ *)|(\'[\w\ \-\"]+\'\ *)|([\w\'\-]+\ *))")
|
||||
args_to_return = []
|
||||
for match in re.findall(pattern, message):
|
||||
match = match[0].strip().rstrip()
|
||||
if (match.startswith("\"") and match.endswith("\"")) \
|
||||
or (match.startswith("'") and match.endswith("'")):
|
||||
args_to_return.append(match[1: -1])
|
||||
else:
|
||||
args_to_return.append(match)
|
||||
return args_to_return
|
||||
|
|
104
irc_api/irc.py
104
irc_api/irc.py
|
@ -70,8 +70,6 @@ class IRC:
|
|||
|
||||
# Public attributes
|
||||
self.connected = False # Simple lock
|
||||
self.callbacks = []
|
||||
|
||||
|
||||
# Private attributes
|
||||
self.__socket = ssl.create_default_context().wrap_socket(
|
||||
|
@ -82,7 +80,7 @@ class IRC:
|
|||
self.__handler = Thread(target=self.__handle)
|
||||
|
||||
# Public methods
|
||||
def start(self, nick: str, password: str):
|
||||
def connexion(self, nick: str, password: str):
|
||||
"""Start the IRC layer. Manage authentication as well.
|
||||
|
||||
Parameters
|
||||
|
@ -94,37 +92,14 @@ class IRC:
|
|||
"""
|
||||
self.__handler.start()
|
||||
|
||||
self.__send(f"USER {nick} * * :{nick}")
|
||||
self.__send(f"NICK {nick}")
|
||||
self.__waitfor(lambda m: "NOTICE" in m and "/AUTH" in m)
|
||||
self.__send(f"AUTH {nick}:{password}")
|
||||
self.__waitfor(lambda m: "You are now logged in" in m)
|
||||
self.send(f"USER {nick} * * :{nick}")
|
||||
self.send(f"NICK {nick}")
|
||||
self.waitfor(lambda m: "NOTICE" in m and "/AUTH" in m)
|
||||
self.send(f"AUTH {nick}:{password}")
|
||||
self.waitfor(lambda m: "You are now logged in" in m)
|
||||
|
||||
self.connected = True
|
||||
|
||||
def run(self):
|
||||
"""Handle new messages."""
|
||||
while True:
|
||||
message = self.receive()
|
||||
logging.info("received %s", message)
|
||||
if message is not None:
|
||||
for callback in self.callbacks:
|
||||
if not False in [event(message) for event in callback.events]:
|
||||
logging.info("matched %s", callback.name)
|
||||
callback(message, *parse(message.text)[callback.cmnd_type:])
|
||||
|
||||
def send(self, target: str, message: str):
|
||||
"""Send a message to the specified target (channel or user).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
target : str
|
||||
The target of the message. It can be a channel or user (private message).
|
||||
message : str
|
||||
The content of the message to send.
|
||||
"""
|
||||
self.__send(f"PRIVMSG {target} :{message}")
|
||||
|
||||
def receive(self):
|
||||
"""Receive a private message.
|
||||
|
||||
|
@ -148,28 +123,10 @@ class IRC:
|
|||
channel : str
|
||||
The name of the channel to join.
|
||||
"""
|
||||
self.__send(f"JOIN {channel}")
|
||||
self.send(f"JOIN {channel}")
|
||||
logging.info("joined %s", channel)
|
||||
|
||||
# Private methods
|
||||
def __handle(self):
|
||||
"""Handle raw messages from irc and manage ping."""
|
||||
while True:
|
||||
# Get incoming messages
|
||||
data = self.__socket.recv(4096).decode()
|
||||
|
||||
# Split multiple lines
|
||||
for msg in data.split('\r\n'):
|
||||
# Manage ping
|
||||
if msg.startswith("PING"):
|
||||
self.__send(msg.replace("PING", "PONG"))
|
||||
|
||||
# Or add a new message to inbox
|
||||
elif len(msg):
|
||||
self.__inbox.put(msg)
|
||||
logging.debug("received %s", msg)
|
||||
|
||||
def __send(self, raw: str):
|
||||
def send(self, raw: str):
|
||||
"""Wrap and encode raw message to send.
|
||||
|
||||
Parameters
|
||||
|
@ -179,7 +136,7 @@ class IRC:
|
|||
"""
|
||||
self.__socket.send(f"{raw}\r\n".encode())
|
||||
|
||||
def __waitfor(self, condition):
|
||||
def waitfor(self, condition):
|
||||
"""Wait for a raw message that matches the condition.
|
||||
|
||||
Parameters
|
||||
|
@ -198,6 +155,44 @@ class IRC:
|
|||
msg = self.__inbox.get()
|
||||
return msg
|
||||
|
||||
# Private methods
|
||||
def __handle(self):
|
||||
"""Handle raw messages from irc and manage ping."""
|
||||
while True:
|
||||
# Get incoming messages
|
||||
data = self.__socket.recv(4096).decode()
|
||||
|
||||
# Split multiple lines
|
||||
for msg in data.split('\r\n'):
|
||||
# Manage ping
|
||||
if msg.startswith("PING"):
|
||||
self.send(msg.replace("PING", "PONG"))
|
||||
|
||||
# Or add a new message to inbox
|
||||
elif len(msg):
|
||||
self.__inbox.put(msg)
|
||||
logging.debug("received %s", msg)
|
||||
|
||||
|
||||
class History:
|
||||
def __init__(self, limit: int=100):
|
||||
self.__content = []
|
||||
if limit:
|
||||
self.__limit = limit
|
||||
else:
|
||||
self.__limit = 100
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__content)
|
||||
|
||||
def add(self, elmnt):
|
||||
if len(self.__content) == self.__limit:
|
||||
self.__content.pop(0)
|
||||
self.__content.append(elmnt)
|
||||
|
||||
def get(self):
|
||||
return self.__content
|
||||
|
||||
|
||||
class Message:
|
||||
"""Parse the raw message in three fields : author, the channel, and text.
|
||||
|
@ -232,8 +227,3 @@ class Message:
|
|||
|
||||
def __str__(self):
|
||||
return f"{self.author} to {self.to}: {self.text}"
|
||||
|
||||
|
||||
def parse(message):
|
||||
pattern = re.compile(r"(((\"|\')[\w\ \-]+(\"|\')\ *)|([\w\'\-]+\ *))")
|
||||
return [match[0].strip("\"' ").rstrip("\"' ") for match in re.findall(pattern, message)]
|
||||
|
|
13
main.py
13
main.py
|
@ -13,7 +13,8 @@ import re
|
|||
from irc_api import api
|
||||
|
||||
|
||||
from glados_cmnds import commands
|
||||
import glados_cmnds as gcmnds
|
||||
import fun_cmnds as fcmnds
|
||||
from secrets import USER, PASSWORD
|
||||
|
||||
|
||||
|
@ -21,14 +22,16 @@ LOG_FORMAT = "%(asctime)s [%(levelname)s] <%(filename)s> %(funcName)s: %(message
|
|||
logging.basicConfig(format=LOG_FORMAT, level=logging.DEBUG)
|
||||
|
||||
|
||||
glados = api.Bot(
|
||||
class MyBot(api.Bot):
|
||||
counter = 1
|
||||
|
||||
glados = MyBot(
|
||||
(USER, PASSWORD),
|
||||
('irc.planet-casio.com', 6697),
|
||||
["#general", "#glados"],
|
||||
"!"
|
||||
gcmnds, fcmnds,
|
||||
prefix="!",
|
||||
)
|
||||
|
||||
glados.add_commands(commands)
|
||||
|
||||
|
||||
glados.start()
|
||||
|
|
Loading…
Reference in New Issue