rewrite: New Scheduled Session System.

This commit is contained in:
2023-06-30 11:15:39 +03:00
parent b7d66ffe8c
commit a7c5af59a7
31 changed files with 4588 additions and 44 deletions

View File

@@ -1,6 +1,11 @@
from .cog import CoreCog
from .config import ConfigCog
from babel.translator import LocalBabel
babel = LocalBabel('lion-core')
async def setup(bot):
await bot.add_cog(CoreCog(bot))

View File

@@ -1,9 +1,11 @@
from typing import Optional
from cachetools import LRUCache
import itertools
import datetime
import discord
from meta import LionCog, LionBot, LionContext
from utils.data import MEMBERS
from data import WeakCache
from .data import CoreData
@@ -99,7 +101,7 @@ class Lions(LionCog):
('guildid',),
*((guildid,) for guildid in missing)
).with_adapter(self.data.Guild._make_rows)
rows = (*rows, *new_rows)
rows = itertools.chain(rows, new_rows)
for row in rows:
guildid = row.guildid
@@ -107,6 +109,35 @@ class Lions(LionCog):
return guild_map
async def fetch_users(self, *userids) -> dict[int, LionUser]:
"""
Fetch (or create) multiple LionUsers simultaneously, using cache where possible.
"""
user_map = {}
missing = set()
for userid in userids:
luser = self.lion_users.get(userid, None)
user_map[userid] = luser
if luser is None:
missing.add(userid)
if missing:
rows = await self.data.User.fetch_where(userid=list(missing))
missing.difference_update(row.userid for row in rows)
if missing:
new_rows = await self.data.User.table.insert_many(
('userid',),
*((userid,) for userid in missing)
).with_adapter(self.data.user._make_rows)
rows = itertools.chain(rows, new_rows)
for row in rows:
userid = row.userid
self.lion_users[userid] = user_map[userid] = LionUser(self.bot, row)
return user_map
async def fetch_member(self, guildid, userid, member: Optional[discord.Member] = None) -> LionMember:
"""
Fetch the given LionMember, using cache for data if possible.
@@ -124,11 +155,46 @@ class Lions(LionCog):
self.lion_members[key] = lmember
return lmember
async def fetch_members(self, *members: tuple[int, int]):
async def fetch_members(self, *memberids: tuple[int, int]) -> dict[tuple[int, int], LionMember]:
"""
Fetch or create multiple members simultaneously.
"""
# TODO: Actually batch this (URGENT)
members = {}
for key in members:
members[key] = await self.fetch_member(*key)
member_map = {}
missing = set()
# Retrieve what we can from cache
for memberid in memberids:
lmember = self.lion_members.get(memberid, None)
member_map[memberid] = lmember
if lmember is None:
missing.add(memberid)
# Fetch or create members that weren't in cache
if missing:
# First fetch or create the guilds and users
lguilds = await self.fetch_guilds(*(gid for gid, _ in missing))
lusers = await self.fetch_users(*(uid for _, uid in missing))
# Now attempt to load members from data
rows = await self.data.Member.fetch_where(MEMBERS(*missing))
missing.difference_update((row.guildid, row.userid) for row in rows)
# Create any member rows that are still missing
if missing:
new_rows = await self.data.Member.table.insert_many(
('guildid', 'userid'),
*missing
).with_adapter(self.data.Member._make_rows)
rows = itertools.chain(rows, new_rows)
# We have all the data, now construct the member objects
for row in rows:
key = (row.guildid, row.userid)
self.lion_members[key] = member_map[key] = LionMember(
self.bot,
row,
lguilds[row.guildid],
lusers[row.userid]
)
return member_map

64
src/core/setting_types.py Normal file
View File

@@ -0,0 +1,64 @@
"""
Additional abstract setting types useful for StudyLion settings.
"""
from settings.setting_types import IntegerSetting
from meta import conf
from meta.errors import UserInputError
from constants import MAX_COINS
from babel.translator import ctx_translator
from . import babel
_p = babel._p
class CoinSetting(IntegerSetting):
"""
Setting type mixin describing a LionCoin setting.
"""
_min = 0
_max = MAX_COINS
_accepts = _p('settype:coin|accepts', "A positive integral number of coins.")
@classmethod
async def _parse_string(cls, parent_id, string: str, **kwargs):
"""
Parse the user input into an integer.
"""
if not string:
return None
try:
num = int(string)
except Exception:
t = ctx_translator.get().t
raise UserInputError(t(_p(
'settype:coin|parse|error:notinteger',
"The coin quantity must be a positive integer!"
))) from None
if num > cls._max:
t = ctx_translator.get().t
raise UserInputError(t(_p(
'settype:coin|parse|error:too_large',
"Provided number of coins was too high!"
))) from None
elif num < cls._min:
t = ctx_translator.get().t
raise UserInputError(t(_p(
'settype:coin|parse|error:too_large',
"Provided number of coins was too low!"
))) from None
return num
@classmethod
def _format_data(cls, parent_id, data, **kwargs):
if data is not None:
t = ctx_translator.get().t
formatted = t(_p(
'settype:coin|formatted',
"{coin}**{amount}**"
)).format(coin=conf.emojis.coin, amount=data)
return formatted