-- | Things that can be upgraded from snowflakes to their full data module Calamity.Types.Upgradeable (Upgradeable (..)) where import Calamity.Cache.Eff import Calamity.Client.Types import Calamity.HTTP as H import Calamity.Internal.SnowflakeMap qualified as SM import Calamity.Internal.Utils import Calamity.Types.Model.Channel import Calamity.Types.Model.Guild import Calamity.Types.Model.User import Calamity.Types.Snowflake import Control.Applicative import Optics import Polysemy qualified as P import Polysemy.Fail qualified as P import Polysemy.NonDet qualified as P {- | A typeclass that represents snowflakes that can be upgraded to their complete data, either through the cache or HTTP. -} class Upgradeable a ids | a -> ids, ids -> a where -- | Upgrade a snowflake to its complete data. -- -- If it existed in the cache then it is returned from there, otherwise we -- fetch from HTTP and update the cache on success. upgrade :: (BotC r) => ids -> P.Sem r (Maybe a) maybeToAlt :: (Alternative f) => Maybe a -> f a maybeToAlt (Just x) = pure x maybeToAlt Nothing = empty instance Upgradeable User (Snowflake User) where upgrade uid = P.runNonDetMaybe ((getUser uid >>= maybeToAlt) <|> gethttp) where gethttp = P.failToNonDet $ do Right u <- invoke $ H.GetUser uid setUser u pure u instance Upgradeable Member (Snowflake Guild, Snowflake Member) where upgrade (gid, mid) = P.runNonDetMaybe (getcache <|> gethttp) where getcache = P.failToNonDet $ do Just g <- getGuild gid Just m <- pure (g ^. #members % at mid) pure m gethttp = P.failToNonDet $ do Right m <- invoke $ H.GetGuildMember gid (coerceSnowflake @_ @User mid) -- getcache could have failed becuase the member wasn't cached updateGuild gid (#members % at mid ?~ m) pure m instance Upgradeable Guild (Snowflake Guild) where upgrade gid = P.runNonDetMaybe ((getGuild gid >>= maybeToAlt) <|> gethttp) where gethttp = P.failToNonDet $ do Right g <- invoke $ H.GetGuild gid pure g insertChannel :: (BotC r) => Channel -> P.Sem r () insertChannel (DMChannel' dm) = setDM dm insertChannel (GuildChannel' ch) = updateGuild (getID ch) (#channels % at (getID @GuildChannel ch) ?~ ch) insertChannel _ = pure () instance Upgradeable Channel (Snowflake Channel) where upgrade cid = P.runNonDetMaybe (getcacheDM <|> getcacheGuild <|> gethttp) where getcacheDM = DMChannel' <<$>> getDM (coerceSnowflake cid) >>= maybeToAlt getcacheGuild = GuildChannel' <<$>> getGuildChannel (coerceSnowflake cid) >>= maybeToAlt gethttp = P.failToNonDet $ do Right c <- invoke $ H.GetChannel cid insertChannel c pure c instance Upgradeable GuildChannel (Snowflake GuildChannel) where upgrade cid = P.runNonDetMaybe (getcache <|> gethttp) where getcache = getGuildChannel (coerceSnowflake cid) >>= maybeToAlt gethttp = P.failToNonDet $ do Right c <- invoke $ H.GetChannel (coerceSnowflake @_ @Channel cid) insertChannel c GuildChannel' c' <- pure c pure c' instance Upgradeable VoiceChannel (Snowflake VoiceChannel) where upgrade s = upgrade (coerceSnowflake @_ @Channel s) <&> \case Just (GuildChannel' (GuildVoiceChannel vc)) -> Just vc _ -> Nothing instance Upgradeable DMChannel (Snowflake DMChannel) where upgrade s = upgrade (coerceSnowflake @_ @Channel s) <&> \case Just (DMChannel' dc) -> Just dc _ -> Nothing instance Upgradeable GroupChannel (Snowflake GroupChannel) where upgrade s = upgrade (coerceSnowflake @_ @Channel s) <&> \case Just (GroupChannel' gc) -> Just gc _ -> Nothing instance Upgradeable TextChannel (Snowflake TextChannel) where upgrade s = upgrade (coerceSnowflake @_ @Channel s) <&> \case Just (GuildChannel' (GuildTextChannel tc)) -> Just tc _ -> Nothing instance Upgradeable Category (Snowflake Category) where upgrade s = upgrade (coerceSnowflake @_ @Channel s) <&> \case Just (GuildChannel' (GuildCategory c)) -> Just c _ -> Nothing instance Upgradeable Emoji (Snowflake Guild, Snowflake Emoji) where upgrade (gid, eid) = P.runNonDetMaybe (getcache <|> gethttp) where getcache = P.failToNonDet $ do Just g <- getGuild gid Just m <- pure (g ^. #emojis % at eid) pure m gethttp = P.failToNonDet $ do Right e <- invoke $ H.GetGuildEmoji gid eid updateGuild gid (#emojis % at eid ?~ e) pure e instance Upgradeable Role (Snowflake Guild, Snowflake Role) where upgrade (gid, rid) = P.runNonDetMaybe (getcache <|> gethttp) where getcache = P.failToNonDet $ do Just g <- getGuild gid Just r <- pure (g ^. #roles % at rid) pure r gethttp = P.failToNonDet $ do Right rs <- invoke $ H.GetGuildRoles gid let sm = SM.fromList rs updateGuild gid (#roles %~ (<> sm)) Just r <- pure (sm ^. at rid) pure r