module Marvin.Internal.Types where
import Control.Lens
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Logger
import Data.Aeson
import Data.Char (isAlphaNum, isLetter)
import qualified Data.Configurator.Types as C
import Data.String
import qualified Data.Text as T
import qualified Data.Text.Lazy as L
import Marvin.Interpolate.Text
import Text.Read (readMaybe)
data Event a
= MessageEvent (Message a)
| ChannelJoinEvent (User a) (Channel a)
| ChannelLeaveEvent (User a) (Channel a)
| TopicChangeEvent L.Text (Channel a)
type EventHandler a = Event a -> IO ()
type InitEventHandler a = a -> IO (EventHandler a)
type RunWithAdapter a = C.Config -> InitEventHandler a -> RunnerM ()
class IsAdapter a where
type User a
type Channel a
adapterId :: AdapterId a
messageChannel :: a -> Channel a -> L.Text -> RunnerM ()
runWithAdapter :: RunWithAdapter a
getUsername :: a -> User a -> RunnerM L.Text
getChannelName :: a -> Channel a -> RunnerM L.Text
resolveChannel :: a -> L.Text -> RunnerM (Maybe (Channel a))
newtype User' a = User' {unwrapUser' :: User a}
newtype Channel' a = Channel' {unwrapChannel' :: Channel a}
newtype TimeStamp = TimeStamp { unwrapTimeStamp :: Double } deriving Show
data Message a = Message
{ sender :: User a
, channel :: Channel a
, content :: L.Text
, timestamp :: TimeStamp
}
instance FromJSON TimeStamp where
parseJSON (String s) = maybe mzero (return . TimeStamp) $ readMaybe (T.unpack s)
parseJSON _ = mzero
instance ToJSON TimeStamp where
toJSON = toJSON . show . unwrapTimeStamp
newtype ScriptId = ScriptId { unwrapScriptId :: T.Text } deriving (Show, Eq)
newtype AdapterId a = AdapterId { unwrapAdapterId :: T.Text } deriving (Show, Eq)
instance ShowT ScriptId where showT = unwrapScriptId
instance ShowT (AdapterId a) where showT = unwrapAdapterId
applicationScriptId :: ScriptId
applicationScriptId = ScriptId "bot"
type RunnerM = LoggingT IO
verifyIdString :: String -> (String -> a) -> String -> a
verifyIdString name _ "" = error $ name ++ " must not be empty"
verifyIdString name f s@(x:xs)
| isLetter x && all (\c -> isAlphaNum c || c == '-' || c == '_' ) xs = f s
| otherwise = error $ "first character of " ++ name ++ " must be a letter, all other characters can be alphanumeric, '-' or '_'"
instance IsString ScriptId where
fromString = verifyIdString "script id" (ScriptId . fromString)
instance IsString (AdapterId a) where
fromString = verifyIdString "adapter id" (AdapterId . fromString)
class HasScriptId s a | s -> a where
scriptId :: Lens' s a
class (IsScript m, MonadIO m) => HasConfigAccess m where
getConfigInternal :: m C.Config
class IsScript m where
getScriptId :: m ScriptId
instance C.Configured LogLevel where
convert (C.String s) =
case T.strip $ T.toLower s of
"debug" -> Just LevelDebug
"warning" -> Just LevelWarn
"error" -> Just LevelError
"info" -> Just LevelInfo
_ -> Nothing
convert _ = Nothing