rewrite: New Scheduled Session System.
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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
64
src/core/setting_types.py
Normal 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
|
||||
Reference in New Issue
Block a user