I have a servant
server implementing a web socket ticketing system for authorization. I'm using servant-websockets
with a Conduit endpoint. I've defined an input message:
data WSInput
= Auth {token :: String}
| InMessage {inValue :: Value}
deriving (Show, Generic)
and since the ticket will just last a couple of seconds, my conduit pipe will just check the Auth message for the first message in. The out message is like:
data WSOutput
= PoisonPill
| AuthOK
| OutMessage {outValue :: Value}
deriving (Show, Generic)
The pipe could be something like:
wsConduit =
mapMC checkTokenExists
.| takeWhileC
( \case
PoisonPill -> False
otherwise -> True
)
The pipe is just an echo after authentication. The checkTokenExists
is just needed for the first message and in fact is blocking all InMessage
so I cannot leave it there.
I could have some state in the checkTokenExists
to let pass InMessage
s after authorization but to me seems it feels like the best way would be to replace completely the mapMC checkTokenExists
by a filterC
just letting app messages in.
How could I dynamically change the shape of the conduit flow based on a single element of the inflow?
"Change shape of program based on input" = Monad
. And for this reason, ConduitT
is a Monad
, with operations await
and yield
. Just say what you mean:
checkTokenExists :: MonadIO m => WSInput -> m Bool
-- should be along the lines of
wsConduit = do
auth <- checkTokenExists <$> await
if auth then forever $ await >>= yield
else yield PoisonPill