rewrite: Initial rewrite skeleton.
Remove modules that will no longer be required. Move pending modules to pending-rewrite folders.
This commit is contained in:
34
bot/meta/pending-rewrite/client.py
Normal file
34
bot/meta/pending-rewrite/client.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from discord import Intents
|
||||
from cmdClient.cmdClient import cmdClient
|
||||
|
||||
from . import patches
|
||||
from .interactions import InteractionType
|
||||
from .config import conf
|
||||
from .sharding import shard_number, shard_count
|
||||
from LionContext import LionContext
|
||||
|
||||
|
||||
# Initialise client
|
||||
owners = [int(owner) for owner in conf.bot.getlist('owners')]
|
||||
intents = Intents.all()
|
||||
intents.presences = False
|
||||
client = cmdClient(
|
||||
prefix=conf.bot['prefix'],
|
||||
owners=owners,
|
||||
intents=intents,
|
||||
shard_id=shard_number,
|
||||
shard_count=shard_count,
|
||||
baseContext=LionContext
|
||||
)
|
||||
client.conf = conf
|
||||
|
||||
|
||||
# TODO: Could include client id here, or app id, to avoid multiple handling.
|
||||
NOOP_ID = 'NOOP'
|
||||
|
||||
|
||||
@client.add_after_event('interaction_create')
|
||||
async def handle_noop_interaction(client, interaction):
|
||||
if interaction.interaction_type in (InteractionType.MESSAGE_COMPONENT, InteractionType.MODAL_SUBMIT):
|
||||
if interaction.custom_id == NOOP_ID:
|
||||
interaction.ack()
|
||||
122
bot/meta/pending-rewrite/config.py
Normal file
122
bot/meta/pending-rewrite/config.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from discord import PartialEmoji
|
||||
import configparser as cfgp
|
||||
|
||||
from .args import args
|
||||
|
||||
|
||||
class configEmoji(PartialEmoji):
|
||||
__slots__ = ('fallback',)
|
||||
|
||||
def __init__(self, *args, fallback=None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fallback = fallback
|
||||
|
||||
@classmethod
|
||||
def from_str(cls, emojistr: str):
|
||||
"""
|
||||
Parses emoji strings of one of the following forms
|
||||
`<a:name:id> or fallback`
|
||||
`<:name:id> or fallback`
|
||||
`<a:name:id>`
|
||||
`<:name:id>`
|
||||
"""
|
||||
splits = emojistr.rsplit(' or ', maxsplit=1)
|
||||
|
||||
fallback = splits[1] if len(splits) > 1 else None
|
||||
emojistr = splits[0].strip('<> ')
|
||||
animated, name, id = emojistr.split(':')
|
||||
return cls(
|
||||
name=name,
|
||||
fallback=PartialEmoji(name=fallback),
|
||||
animated=bool(animated),
|
||||
id=int(id)
|
||||
)
|
||||
|
||||
|
||||
class MapDotProxy:
|
||||
"""
|
||||
Allows dot access to an underlying Mappable object.
|
||||
"""
|
||||
__slots__ = ("_map", "_converter")
|
||||
|
||||
def __init__(self, mappable, converter=None):
|
||||
self._map = mappable
|
||||
self._converter = converter
|
||||
|
||||
def __getattribute__(self, key):
|
||||
_map = object.__getattribute__(self, '_map')
|
||||
if key == '_map':
|
||||
return _map
|
||||
if key in _map:
|
||||
_converter = object.__getattribute__(self, '_converter')
|
||||
if _converter:
|
||||
return _converter(_map[key])
|
||||
else:
|
||||
return _map[key]
|
||||
else:
|
||||
return object.__getattribute__(_map, key)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._map.__getitem__(key)
|
||||
|
||||
|
||||
class Conf:
|
||||
def __init__(self, configfile, section_name="DEFAULT"):
|
||||
self.configfile = configfile
|
||||
|
||||
self.config = cfgp.ConfigParser(
|
||||
converters={
|
||||
"intlist": self._getintlist,
|
||||
"list": self._getlist,
|
||||
"emoji": configEmoji.from_str,
|
||||
}
|
||||
)
|
||||
self.config.read(configfile)
|
||||
|
||||
self.section_name = section_name if section_name in self.config else 'DEFAULT'
|
||||
|
||||
self.default = self.config["DEFAULT"]
|
||||
self.section = MapDotProxy(self.config[self.section_name])
|
||||
self.bot = self.section
|
||||
|
||||
# Config file recursion, read in configuration files specified in every "ALSO_READ" key.
|
||||
more_to_read = self.section.getlist("ALSO_READ", [])
|
||||
read = set()
|
||||
while more_to_read:
|
||||
to_read = more_to_read.pop(0)
|
||||
read.add(to_read)
|
||||
self.config.read(to_read)
|
||||
new_paths = [path for path in self.section.getlist("ALSO_READ", [])
|
||||
if path not in read and path not in more_to_read]
|
||||
more_to_read.extend(new_paths)
|
||||
|
||||
self.emojis = MapDotProxy(
|
||||
self.config['EMOJIS'] if 'EMOJIS' in self.config else self.section,
|
||||
converter=configEmoji.from_str
|
||||
)
|
||||
|
||||
global conf
|
||||
conf = self
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.section[key].strip()
|
||||
|
||||
def __getattr__(self, section):
|
||||
return self.config[section]
|
||||
|
||||
def get(self, name, fallback=None):
|
||||
result = self.section.get(name, fallback)
|
||||
return result.strip() if result else result
|
||||
|
||||
def _getintlist(self, value):
|
||||
return [int(item.strip()) for item in value.split(',')]
|
||||
|
||||
def _getlist(self, value):
|
||||
return [item.strip() for item in value.split(',')]
|
||||
|
||||
def write(self):
|
||||
with open(self.configfile, 'w') as conffile:
|
||||
self.config.write(conffile)
|
||||
|
||||
|
||||
conf = Conf(args.config)
|
||||
110
bot/meta/pending-rewrite/logger.py
Normal file
110
bot/meta/pending-rewrite/logger.py
Normal file
@@ -0,0 +1,110 @@
|
||||
import sys
|
||||
import logging
|
||||
import asyncio
|
||||
from discord import AllowedMentions
|
||||
|
||||
from cmdClient.logger import cmd_log_handler
|
||||
|
||||
from utils.lib import mail, split_text
|
||||
|
||||
from .client import client
|
||||
from .config import conf
|
||||
from . import sharding
|
||||
|
||||
|
||||
# Setup the logger
|
||||
logger = logging.getLogger()
|
||||
log_fmt = logging.Formatter(
|
||||
fmt=('[{asctime}][{levelname:^8}]' +
|
||||
'[SHARD {}]'.format(sharding.shard_number) +
|
||||
' {message}'),
|
||||
datefmt='%d/%m | %H:%M:%S',
|
||||
style='{'
|
||||
)
|
||||
# term_handler = logging.StreamHandler(sys.stdout)
|
||||
# term_handler.setFormatter(log_fmt)
|
||||
# logger.addHandler(term_handler)
|
||||
# logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
class LessThanFilter(logging.Filter):
|
||||
def __init__(self, exclusive_maximum, name=""):
|
||||
super(LessThanFilter, self).__init__(name)
|
||||
self.max_level = exclusive_maximum
|
||||
|
||||
def filter(self, record):
|
||||
# non-zero return means we log this message
|
||||
return 1 if record.levelno < self.max_level else 0
|
||||
|
||||
|
||||
logger.setLevel(logging.NOTSET)
|
||||
|
||||
logging_handler_out = logging.StreamHandler(sys.stdout)
|
||||
logging_handler_out.setLevel(logging.DEBUG)
|
||||
logging_handler_out.setFormatter(log_fmt)
|
||||
logging_handler_out.addFilter(LessThanFilter(logging.WARNING))
|
||||
logger.addHandler(logging_handler_out)
|
||||
|
||||
logging_handler_err = logging.StreamHandler(sys.stderr)
|
||||
logging_handler_err.setLevel(logging.WARNING)
|
||||
logging_handler_err.setFormatter(log_fmt)
|
||||
logger.addHandler(logging_handler_err)
|
||||
|
||||
|
||||
# Define the context log format and attach it to the command logger as well
|
||||
@cmd_log_handler
|
||||
def log(message, context="GLOBAL", level=logging.INFO, post=True):
|
||||
# Add prefixes to lines for better parsing capability
|
||||
lines = message.splitlines()
|
||||
if len(lines) > 1:
|
||||
lines = [
|
||||
'┌ ' * (i == 0) + '│ ' * (0 < i < len(lines) - 1) + '└ ' * (i == len(lines) - 1) + line
|
||||
for i, line in enumerate(lines)
|
||||
]
|
||||
else:
|
||||
lines = ['─ ' + message]
|
||||
|
||||
for line in lines:
|
||||
logger.log(level, '\b[{}] {}'.format(
|
||||
str(context).center(22, '='),
|
||||
line
|
||||
))
|
||||
|
||||
# Fire and forget to the channel logger, if it is set up
|
||||
if post and client.is_ready():
|
||||
asyncio.ensure_future(live_log(message, context, level))
|
||||
|
||||
|
||||
# Live logger that posts to the logging channels
|
||||
async def live_log(message, context, level):
|
||||
if level >= logging.INFO:
|
||||
if level >= logging.WARNING:
|
||||
log_chid = conf.bot.getint('error_channel') or conf.bot.getint('log_channel')
|
||||
else:
|
||||
log_chid = conf.bot.getint('log_channel')
|
||||
|
||||
# Generate the log messages
|
||||
if sharding.sharded:
|
||||
header = f"[{logging.getLevelName(level)}][SHARD {sharding.shard_number}][{context}]"
|
||||
else:
|
||||
header = f"[{logging.getLevelName(level)}][{context}]"
|
||||
|
||||
if len(message) > 1900:
|
||||
blocks = split_text(message, blocksize=1900, code=False)
|
||||
else:
|
||||
blocks = [message]
|
||||
|
||||
if len(blocks) > 1:
|
||||
blocks = [
|
||||
"```md\n{}[{}/{}]\n{}\n```".format(header, i+1, len(blocks), block) for i, block in enumerate(blocks)
|
||||
]
|
||||
else:
|
||||
blocks = ["```md\n{}\n{}\n```".format(header, blocks[0])]
|
||||
|
||||
# Post the log messages
|
||||
if log_chid:
|
||||
[await mail(client, log_chid, content=block, allowed_mentions=AllowedMentions.none()) for block in blocks]
|
||||
|
||||
|
||||
# Attach logger to client, for convenience
|
||||
client.log = log
|
||||
Reference in New Issue
Block a user