[server] Add return value to tree modules
Now, tree modules can't just stop, they can Just stop. Sorry... But they can return values now, with a tiny bit of type class trickery.
This commit is contained in:
parent
220b5a3234
commit
2a2b148046
6 changed files with 55 additions and 39 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Forest.Server
|
module Forest.Server
|
||||||
|
|
@ -29,8 +30,8 @@ sendUpdatesThread conn nodeChan nodeA = do
|
||||||
|
|
||||||
{- Main server application that receives and processes client packets -}
|
{- Main server application that receives and processes client packets -}
|
||||||
|
|
||||||
receivePackets :: TreeModule a => WS.Connection -> a -> IO ()
|
receivePackets :: TreeModule a () => WS.Connection -> a () -> IO ()
|
||||||
receivePackets conn treeModule = whileM $ do
|
receivePackets conn treeModule = runUntilJustM $ do
|
||||||
packet <- receivePacket conn
|
packet <- receivePacket conn
|
||||||
case packet of
|
case packet of
|
||||||
ClientEdit path text -> do
|
ClientEdit path text -> do
|
||||||
|
|
@ -47,7 +48,7 @@ receivePackets conn treeModule = whileM $ do
|
||||||
act treeModule path
|
act treeModule path
|
||||||
ClientHello _ -> closeWithErrorMessage conn "Invalid packet: Hello can only be sent once"
|
ClientHello _ -> closeWithErrorMessage conn "Invalid packet: Hello can only be sent once"
|
||||||
|
|
||||||
serverApp :: TreeModule a => Int -> ModuleConstructor a -> WS.ServerApp
|
serverApp :: TreeModule a () => Int -> ModuleConstructor (a ()) -> WS.ServerApp
|
||||||
serverApp pingDelay constructor pendingConnection = do
|
serverApp pingDelay constructor pendingConnection = do
|
||||||
conn <- WS.acceptRequest pendingConnection
|
conn <- WS.acceptRequest pendingConnection
|
||||||
chan <- newChan
|
chan <- newChan
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
|
||||||
module Forest.TreeModule
|
module Forest.TreeModule
|
||||||
( TreeModule(..)
|
( TreeModule(..)
|
||||||
, ModuleConstructor
|
, ModuleConstructor
|
||||||
|
|
@ -7,17 +9,17 @@ import qualified Data.Text as T
|
||||||
|
|
||||||
import Forest.Node
|
import Forest.Node
|
||||||
|
|
||||||
class TreeModule a where
|
class TreeModule a r where
|
||||||
edit :: a -> Path -> T.Text -> IO Bool
|
edit :: a r -> Path -> T.Text -> IO (Maybe r)
|
||||||
edit _ _ _ = pure True
|
edit _ _ _ = pure Nothing
|
||||||
|
|
||||||
delete :: a -> Path -> IO Bool
|
delete :: a r -> Path -> IO (Maybe r)
|
||||||
delete _ _ = pure True
|
delete _ _ = pure Nothing
|
||||||
|
|
||||||
reply :: a -> Path -> T.Text -> IO Bool
|
reply :: a r -> Path -> T.Text -> IO (Maybe r)
|
||||||
reply _ _ _ = pure True
|
reply _ _ _ = pure Nothing
|
||||||
|
|
||||||
act :: a -> Path -> IO Bool
|
act :: a r -> Path -> IO (Maybe r)
|
||||||
act _ _ = pure True
|
act _ _ = pure Nothing
|
||||||
|
|
||||||
type ModuleConstructor a = (Node -> IO ()) -> (a -> IO ()) -> IO ()
|
type ModuleConstructor a = (Node -> IO ()) -> (a -> IO ()) -> IO ()
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,22 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Forest.TreeModule.Animate
|
module Forest.TreeModule.Animate
|
||||||
( AnimateModule
|
( AnimateModule
|
||||||
, animateModule
|
, animateModule
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
|
|
||||||
import Forest.TreeModule
|
|
||||||
import Forest.Node
|
import Forest.Node
|
||||||
|
import Forest.TreeModule
|
||||||
import Forest.Util
|
import Forest.Util
|
||||||
|
|
||||||
data AnimateModule = AnimateModule
|
data AnimateModule r = AnimateModule
|
||||||
|
|
||||||
instance TreeModule AnimateModule where
|
instance TreeModule AnimateModule () where
|
||||||
|
|
||||||
animateModule :: Int -> [Node] -> ModuleConstructor AnimateModule
|
animateModule :: Int -> [Node] -> ModuleConstructor (AnimateModule ())
|
||||||
animateModule delay frames sendNode continue =
|
animateModule delay frames sendNode continue =
|
||||||
withThread (animateThread frames) $ continue AnimateModule
|
withThread (animateThread frames) $ continue AnimateModule
|
||||||
where
|
where
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Forest.TreeModule.Const
|
module Forest.TreeModule.Const
|
||||||
( ConstModule
|
( ConstModule
|
||||||
|
|
@ -9,11 +10,11 @@ module Forest.TreeModule.Const
|
||||||
import Forest.Node
|
import Forest.Node
|
||||||
import Forest.TreeModule
|
import Forest.TreeModule
|
||||||
|
|
||||||
data ConstModule = ConstModule
|
data ConstModule r = ConstModule
|
||||||
|
|
||||||
instance TreeModule ConstModule where
|
instance TreeModule ConstModule () where
|
||||||
|
|
||||||
constModule :: Node -> ModuleConstructor ConstModule
|
constModule :: Node -> ModuleConstructor (ConstModule ())
|
||||||
constModule node sendNode continue = do
|
constModule node sendNode continue = do
|
||||||
sendNode node
|
sendNode node
|
||||||
continue ConstModule
|
continue ConstModule
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{-# LANGUAGE ExistentialQuantification #-}
|
{-# LANGUAGE ExistentialQuantification #-}
|
||||||
{-# LANGUAGE KindSignatures #-}
|
{-# LANGUAGE KindSignatures #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE RankNTypes #-}
|
{-# LANGUAGE RankNTypes #-}
|
||||||
|
|
||||||
module Forest.TreeModule.Fork
|
module Forest.TreeModule.Fork
|
||||||
|
|
@ -16,31 +17,32 @@ import qualified Data.Text as T
|
||||||
import Forest.Node
|
import Forest.Node
|
||||||
import Forest.TreeModule
|
import Forest.TreeModule
|
||||||
|
|
||||||
data Prong = forall a . TreeModule a => Prong a
|
data Prong = forall r a . TreeModule a r => Prong (a r)
|
||||||
data ProngConstructor = forall a . TreeModule a => ProngConstructor (ModuleConstructor a)
|
data ProngConstructor = forall r a . TreeModule a r =>
|
||||||
|
ProngConstructor (ModuleConstructor (a r))
|
||||||
|
|
||||||
newtype ForkModule = ForkModule (Map.Map NodeId Prong)
|
newtype ForkModule r = ForkModule (Map.Map NodeId Prong)
|
||||||
|
|
||||||
instance TreeModule ForkModule where
|
instance TreeModule ForkModule () where
|
||||||
edit _ (Path []) _ = pure True
|
edit _ (Path []) _ = pure Nothing
|
||||||
edit (ForkModule prongs) (Path (x:xs)) text = case prongs Map.!? x of
|
edit (ForkModule prongs) (Path (x:xs)) text = case prongs Map.!? x of
|
||||||
Just (Prong a) -> edit a (Path xs) text
|
Just (Prong a) -> Just () <$ edit a (Path xs) text
|
||||||
Nothing -> pure True
|
Nothing -> pure Nothing
|
||||||
|
|
||||||
delete _ (Path []) = pure True
|
delete _ (Path []) = pure Nothing
|
||||||
delete (ForkModule prongs) (Path (x:xs)) = case prongs Map.!? x of
|
delete (ForkModule prongs) (Path (x:xs)) = case prongs Map.!? x of
|
||||||
Just (Prong a) -> delete a (Path xs)
|
Just (Prong a) -> Just () <$ delete a (Path xs)
|
||||||
Nothing -> pure True
|
Nothing -> pure Nothing
|
||||||
|
|
||||||
reply _ (Path []) _ = pure True
|
reply _ (Path []) _ = pure Nothing
|
||||||
reply (ForkModule prongs) (Path (x:xs)) text = case prongs Map.!? x of
|
reply (ForkModule prongs) (Path (x:xs)) text = case prongs Map.!? x of
|
||||||
Just (Prong a) -> reply a (Path xs) text
|
Just (Prong a) -> Just () <$ reply a (Path xs) text
|
||||||
Nothing -> pure True
|
Nothing -> pure Nothing
|
||||||
|
|
||||||
act _ (Path []) = pure True
|
act _ (Path []) = pure Nothing
|
||||||
act (ForkModule prongs) (Path (x:xs)) = case prongs Map.!? x of
|
act (ForkModule prongs) (Path (x:xs)) = case prongs Map.!? x of
|
||||||
Just (Prong a) -> act a (Path xs)
|
Just (Prong a) -> Just () <$ act a (Path xs)
|
||||||
Nothing -> pure True
|
Nothing -> pure Nothing
|
||||||
|
|
||||||
sendNodeFromProng
|
sendNodeFromProng
|
||||||
:: T.Text
|
:: T.Text
|
||||||
|
|
@ -68,7 +70,7 @@ constructProngs text nodesVar sendNode =
|
||||||
constructProng nodeId (ProngConstructor constructor) =
|
constructProng nodeId (ProngConstructor constructor) =
|
||||||
Prong <$> cont (constructor $ sendNodeFromProng text nodesVar sendNode nodeId)
|
Prong <$> cont (constructor $ sendNodeFromProng text nodesVar sendNode nodeId)
|
||||||
|
|
||||||
forkModule :: T.Text -> [ProngConstructor] -> ModuleConstructor ForkModule
|
forkModule :: T.Text -> [ProngConstructor] -> ModuleConstructor (ForkModule ())
|
||||||
forkModule text prongs sendNode continue = do
|
forkModule text prongs sendNode continue = do
|
||||||
nodesVar <- newMVar Map.empty
|
nodesVar <- newMVar Map.empty
|
||||||
let digits = length $ show $ length prongs
|
let digits = length $ show $ length prongs
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ module Forest.Util
|
||||||
( findPrev
|
( findPrev
|
||||||
, findNext
|
, findNext
|
||||||
, whileM
|
, whileM
|
||||||
|
, runUntilJustM
|
||||||
, withThread
|
, withThread
|
||||||
, sendPacket
|
, sendPacket
|
||||||
, closeWithErrorMessage
|
, closeWithErrorMessage
|
||||||
|
|
@ -34,6 +35,14 @@ whileM f = do
|
||||||
then whileM f
|
then whileM f
|
||||||
else pure ()
|
else pure ()
|
||||||
|
|
||||||
|
-- | Run a monadic action until it returns @Just a@ for the first time.
|
||||||
|
runUntilJustM :: Monad m => m (Maybe a) -> m a
|
||||||
|
runUntilJustM f = do
|
||||||
|
result <- f
|
||||||
|
case result of
|
||||||
|
Nothing -> runUntilJustM f
|
||||||
|
Just a -> pure a
|
||||||
|
|
||||||
sendPacket :: ToJSON a => WS.Connection -> a -> IO ()
|
sendPacket :: ToJSON a => WS.Connection -> a -> IO ()
|
||||||
sendPacket conn packet = WS.sendTextData conn $ encode packet
|
sendPacket conn packet = WS.sendTextData conn $ encode packet
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue