{-# options_haddock prune #-}
module Ribosome.Host.Handler.Codec where
import Data.Aeson (eitherDecodeStrict')
import qualified Data.ByteString as ByteString
import Data.MessagePack (Object)
import qualified Data.Text as Text
import Exon (exon)
import qualified Options.Applicative as Optparse
import Options.Applicative (defaultPrefs, execParserPure, info, renderFailure)
import Ribosome.Host.Class.Msgpack.Decode (MsgpackDecode (fromMsgpack))
import Ribosome.Host.Class.Msgpack.Encode (MsgpackEncode (toMsgpack))
import Ribosome.Host.Data.Args (ArgList (ArgList), Args (Args), JsonArgs (JsonArgs), OptionParser (optionParser), Options (Options))
import Ribosome.Host.Data.Bang (Bang (NoBang))
import Ribosome.Host.Data.Bar (Bar (Bar))
import Ribosome.Host.Data.Report (Report, basicReport)
import Ribosome.Host.Data.RpcHandler (Handler, RpcHandlerFun)
decodeArg ::
Member (Stop Report) r =>
MsgpackDecode a =>
Object ->
Sem r a
decodeArg :: forall (r :: EffectRow) a.
(Member (Stop Report) r, MsgpackDecode a) =>
Object -> Sem r a
decodeArg =
Either Report a -> Sem r a
forall err (r :: EffectRow) a.
Member (Stop err) r =>
Either err a -> Sem r a
stopEither (Either Report a -> Sem r a)
-> (Object -> Either Report a) -> Object -> Sem r a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Report) -> Either Text a -> Either Report a
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Text -> Report
forall a. IsString a => Text -> a
fromText (Either Text a -> Either Report a)
-> (Object -> Either Text a) -> Object -> Either Report a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Object -> Either Text a
forall a. MsgpackDecode a => Object -> Either Text a
fromMsgpack
extraError ::
Member (Stop Report) r =>
[Object] ->
Sem r a
[Object]
o =
Report -> Sem r a
forall e (r :: EffectRow) a. Member (Stop e) r => e -> Sem r a
stop (String -> Report
forall a. IsString a => String -> a
fromString [exon|Extraneous arguments: #{show o}|])
optArg ::
Member (Stop Report) r =>
MsgpackDecode a =>
a ->
[Object] ->
Sem r ([Object], a)
optArg :: forall (r :: EffectRow) a.
(Member (Stop Report) r, MsgpackDecode a) =>
a -> [Object] -> Sem r ([Object], a)
optArg a
dflt = \case
[] -> ([Object], a) -> Sem r ([Object], a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([], a
dflt)
(Object
o : [Object]
rest) -> do
a
a <- Object -> Sem r a
forall (r :: EffectRow) a.
(Member (Stop Report) r, MsgpackDecode a) =>
Object -> Sem r a
decodeArg Object
o
pure ([Object]
rest, a
a)
class HandlerArg a r where
handlerArg :: [Object] -> Sem r ([Object], a)
instance {-# overlappable #-} (
Member (Stop Report) r,
MsgpackDecode a
) => HandlerArg a r where
handlerArg :: [Object] -> Sem r ([Object], a)
handlerArg = \case
[] -> Report -> Sem r ([Object], a)
forall e (r :: EffectRow) a. Member (Stop e) r => e -> Sem r a
stop Report
"too few arguments"
(Object
o : [Object]
rest) -> do
a
a <- Object -> Sem r a
forall (r :: EffectRow) a.
(Member (Stop Report) r, MsgpackDecode a) =>
Object -> Sem r a
decodeArg Object
o
pure ([Object]
rest, a
a)
instance (
HandlerArg a r
) => HandlerArg (Maybe a) r where
handlerArg :: [Object] -> Sem r ([Object], Maybe a)
handlerArg = \case
[] -> ([Object], Maybe a) -> Sem r ([Object], Maybe a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([], Maybe a
forall a. Maybe a
Nothing)
[Object]
os -> (a -> Maybe a) -> ([Object], a) -> ([Object], Maybe a)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second a -> Maybe a
forall a. a -> Maybe a
Just (([Object], a) -> ([Object], Maybe a))
-> Sem r ([Object], a) -> Sem r ([Object], Maybe a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Object] -> Sem r ([Object], a)
forall a (r :: EffectRow).
HandlerArg a r =>
[Object] -> Sem r ([Object], a)
handlerArg [Object]
os
instance HandlerArg Bar r where
handlerArg :: [Object] -> Sem r ([Object], Bar)
handlerArg [Object]
os =
([Object], Bar) -> Sem r ([Object], Bar)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([Object]
os, Bar
Bar)
instance (
Member (Stop Report) r
) => HandlerArg Bang r where
handlerArg :: [Object] -> Sem r ([Object], Bang)
handlerArg =
Bang -> [Object] -> Sem r ([Object], Bang)
forall (r :: EffectRow) a.
(Member (Stop Report) r, MsgpackDecode a) =>
a -> [Object] -> Sem r ([Object], a)
optArg Bang
NoBang
instance (
Member (Stop Report) r
) => HandlerArg Args r where
handlerArg :: [Object] -> Sem r ([Object], Args)
handlerArg [Object]
os =
case (Object -> Either Text Text) -> [Object] -> Either Text [Text]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Object -> Either Text Text
forall a. MsgpackDecode a => Object -> Either Text a
fromMsgpack [Object]
os of
Right [Text]
a ->
([Object], Args) -> Sem r ([Object], Args)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([], Text -> Args
Args ([Text] -> Text
Text.unwords [Text]
a))
Left Text
e ->
Text -> [Text] -> Sem r ([Object], Args)
forall (r :: EffectRow) a.
(Member (Stop Report) r, HasCallStack) =>
Text -> [Text] -> Sem r a
basicReport [exon|Invalid arguments: #{show os}|] [Item [Text]
"Invalid type for Args", [Object] -> Text
forall b a. (Show a, IsString b) => a -> b
show [Object]
os, Text
Item [Text]
e]
instance (
Member (Stop Report) r
) => HandlerArg ArgList r where
handlerArg :: [Object] -> Sem r ([Object], ArgList)
handlerArg [Object]
os =
case (Object -> Either Text Text) -> [Object] -> Either Text [Text]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Object -> Either Text Text
forall a. MsgpackDecode a => Object -> Either Text a
fromMsgpack [Object]
os of
Right [Text]
a ->
([Object], ArgList) -> Sem r ([Object], ArgList)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([], [Text] -> ArgList
ArgList [Text]
a)
Left Text
e ->
Text -> [Text] -> Sem r ([Object], ArgList)
forall (r :: EffectRow) a.
(Member (Stop Report) r, HasCallStack) =>
Text -> [Text] -> Sem r a
basicReport [exon|Invalid arguments: #{show os}|] [Item [Text]
"Invalid type for ArgList", [Object] -> Text
forall b a. (Show a, IsString b) => a -> b
show [Object]
os, Text
Item [Text]
e]
instance (
Member (Stop Report) r,
FromJSON a
) => HandlerArg (JsonArgs a) r where
handlerArg :: [Object] -> Sem r ([Object], JsonArgs a)
handlerArg [Object]
os =
case (String -> Text) -> Either String a -> Either Text a
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first String -> Text
forall a. ToText a => a -> Text
toText (Either String a -> Either Text a)
-> ([ByteString] -> Either String a)
-> [ByteString]
-> Either Text a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Either String a
forall a. FromJSON a => ByteString -> Either String a
eitherDecodeStrict' (ByteString -> Either String a)
-> ([ByteString] -> ByteString) -> [ByteString] -> Either String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
ByteString.concat ([ByteString] -> Either Text a)
-> Either Text [ByteString] -> Either Text a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Object -> Either Text ByteString)
-> [Object] -> Either Text [ByteString]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Object -> Either Text ByteString
forall a. MsgpackDecode a => Object -> Either Text a
fromMsgpack [Object]
os of
Right a
a ->
([Object], JsonArgs a) -> Sem r ([Object], JsonArgs a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([], a -> JsonArgs a
forall a. a -> JsonArgs a
JsonArgs a
a)
Left Text
e ->
Text -> [Text] -> Sem r ([Object], JsonArgs a)
forall (r :: EffectRow) a.
(Member (Stop Report) r, HasCallStack) =>
Text -> [Text] -> Sem r a
basicReport [exon|Invalid arguments: #{show os}|] [Item [Text]
"Invalid type for JsonArgs", [Object] -> Text
forall b a. (Show a, IsString b) => a -> b
show [Object]
os, Text
Item [Text]
e]
instance (
Member (Stop Report) r,
OptionParser a
) => HandlerArg (Options a) r where
handlerArg :: [Object] -> Sem r ([Object], Options a)
handlerArg [Object]
os =
case ParserResult a -> Either Text a
forall {b}. ParserResult b -> Either Text b
result (ParserResult a -> Either Text a)
-> ([String] -> ParserResult a) -> [String] -> Either Text a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParserPrefs -> ParserInfo a -> [String] -> ParserResult a
forall a. ParserPrefs -> ParserInfo a -> [String] -> ParserResult a
execParserPure ParserPrefs
defaultPrefs (Parser a -> InfoMod a -> ParserInfo a
forall a. Parser a -> InfoMod a -> ParserInfo a
info (forall a. OptionParser a => Parser a
optionParser @a) InfoMod a
forall a. Monoid a => a
mempty) ([String] -> Either Text a)
-> Either Text [String] -> Either Text a
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Object -> Either Text String) -> [Object] -> Either Text [String]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Object -> Either Text String
forall a. MsgpackDecode a => Object -> Either Text a
fromMsgpack [Object]
os of
Right a
a ->
([Object], Options a) -> Sem r ([Object], Options a)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([], a -> Options a
forall a. a -> Options a
Options a
a)
Left Text
e ->
Text -> [Text] -> Sem r ([Object], Options a)
forall (r :: EffectRow) a.
(Member (Stop Report) r, HasCallStack) =>
Text -> [Text] -> Sem r a
basicReport [exon|Invalid arguments: #{show os}|] [Item [Text]
"Invalid type for Options", [Object] -> Text
forall b a. (Show a, IsString b) => a -> b
show [Object]
os, Text
Item [Text]
e]
where
result :: ParserResult b -> Either Text b
result = \case
Optparse.Success b
a -> b -> Either Text b
forall a b. b -> Either a b
Right b
a
Optparse.Failure ParserFailure ParserHelp
e -> Text -> Either Text b
forall a b. a -> Either a b
Left (String -> Text
forall a. ToText a => a -> Text
toText ((String, ExitCode) -> String
forall a b. (a, b) -> a
fst (ParserFailure ParserHelp -> String -> (String, ExitCode)
renderFailure ParserFailure ParserHelp
e String
"Ribosome")))
Optparse.CompletionInvoked CompletionResult
_ -> Text -> Either Text b
forall a b. a -> Either a b
Left Text
"Internal optparse error"
class HandlerCodec h r | h -> r where
handlerCodec :: h -> RpcHandlerFun r
instance (
MsgpackEncode a
) => HandlerCodec (Handler r a) r where
handlerCodec :: Handler r a -> RpcHandlerFun r
handlerCodec Handler r a
h = \case
[] -> a -> Object
forall a. MsgpackEncode a => a -> Object
toMsgpack (a -> Object) -> Handler r a -> Sem (Stop Report : r) Object
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Handler r a
h
[Object]
o -> RpcHandlerFun r
forall (r :: EffectRow) a.
Member (Stop Report) r =>
[Object] -> Sem r a
extraError [Object]
o
instance (
HandlerArg a (Stop Report : r),
HandlerCodec b r
) => HandlerCodec (a -> b) r where
handlerCodec :: (a -> b) -> RpcHandlerFun r
handlerCodec a -> b
h [Object]
o = do
([Object]
rest, a
a) <- [Object] -> Sem (Stop Report : r) ([Object], a)
forall a (r :: EffectRow).
HandlerArg a r =>
[Object] -> Sem r ([Object], a)
handlerArg [Object]
o
b -> RpcHandlerFun r
forall h (r :: EffectRow). HandlerCodec h r => h -> RpcHandlerFun r
handlerCodec (a -> b
h a
a) [Object]
rest