Beta/core/messaging.py

135 lines
4.6 KiB
Python
Raw Normal View History

2026-02-06 22:23:20 +01:00
"""Messaging utilities for Superviseur bot."""
import discord
import logging
from typing import Optional, List, Dict
logger = logging.getLogger('Superviseur')
class MessagingManager:
"""Manages message sending with rate limiting and chunking."""
def __init__(self, bot):
self.bot = bot
async def send_message_with_limit(
self,
channel: discord.abc.Messageable,
content: str
) -> None:
"""Send a message, splitting into multiple if it exceeds 2000 chars."""
while len(content) > 2000:
split_index = content.rfind(' ', 0, 2000)
if split_index == -1:
split_index = 2000
chunk = content[:split_index]
await channel.send(chunk)
content = content[split_index:].lstrip()
if content:
await channel.send(content)
async def reply_with_limit(
self,
message: discord.Message,
content: str
) -> None:
"""Reply to a message, splitting if it exceeds 2000 chars."""
if not message.channel:
logger.warning(f"Cannot send message: no channel")
return
if hasattr(message.channel, 'permissions_for'):
perms = message.channel.permissions_for(
message.guild.me if message.guild else message.author
)
if not perms.send_messages:
logger.warning(f"Cannot send message in channel {message.channel}")
return
first_chunk = True
while len(content) > 2000:
split_index = content.rfind(' ', 0, 2000)
if split_index == -1:
split_index = 2000
chunk = content[:split_index]
if first_chunk:
try:
await message.reply(chunk)
except (discord.errors.HTTPException, discord.errors.NotFound):
try:
await message.channel.send(chunk)
except discord.errors.Forbidden:
logger.error(f"Forbidden to send in channel {message.channel}")
first_chunk = False
else:
try:
await message.channel.send(chunk)
except discord.errors.Forbidden:
logger.error(f"Forbidden to send in channel {message.channel}")
return
content = content[split_index:].lstrip()
if content:
if first_chunk:
try:
await message.reply(content)
except (discord.errors.HTTPException, discord.errors.NotFound):
try:
await message.channel.send(content)
except discord.errors.Forbidden:
logger.error(f"Forbidden to send in channel {message.channel}")
else:
try:
await message.channel.send(content)
except discord.errors.Forbidden:
logger.error(f"Forbidden to send in channel {message.channel}")
async def send_embed(
self,
target: discord.abc.Messageable,
title: str,
description: str,
color: discord.Color = discord.Color.light_grey(),
thumbnail_url: Optional[str] = None,
is_asset: bool = False,
fields: Optional[List[Dict[str, str]]] = None
) -> None:
"""Send a clinical Samaritan-style embed with support for fields and clickable links."""
# Clinical formatting - we avoid the global ``` to allow markdown (links, mentions)
display_title = f"{title}"
embed = discord.Embed(
title=display_title,
description=description,
color=color
)
if fields:
for field in fields:
embed.add_field(
name=field.get("name", "---"),
value=field.get("value", "---"),
inline=field.get("inline", True)
)
if is_asset:
embed.set_author(
name="SYSTEM: BÊTA | PRIMARY ASSET LINK",
icon_url="https://i.imgur.com/xH3X5rR.png"
)
if thumbnail_url:
embed.set_thumbnail(url=thumbnail_url)
embed.set_footer(text=f"HEURISTIC ANALYSIS COMPLETE | {self.bot.system_name} v2.0")
try:
await target.send(embed=embed)
except discord.errors.Forbidden:
logger.error(f"Cannot send DM/Message to {target}")