@@ -22,6 +22,8 @@ module Language.Javascript.JSaddle.WebSockets (
2222 , sendCommand
2323 , sendLazyCommand
2424 , sendAsyncCommand
25+ , syncPoint
26+ , syncAfter
2527) where
2628
2729import Control.Exception (throwIO)
@@ -51,9 +53,8 @@ import Network.Wai.Handler.WebSockets (websocketsOr)
5153
5254import Language.Javascript.JSaddle.Types
5355 (Command(..), AsyncCommand(..), Result(..), JSContextRef(..), JSVal(..),
54− Object(..), JSValueReceived(..), JSM, Batch(..), JSValueForSend(..))
56+ Object(..), JSValueReceived(..), JSM, Batch(..), JSValueForSend(..), runJSaddle)
5557import Language.Javascript.JSaddle.Exception (JSException(..))
56−import Language.Javascript.JSaddle.Monad (runJSaddle)
5758import Language.Javascript.JSaddle.Native (wrapJSVal)
5859import Language.Javascript.JSaddle.WebSockets.Files (mkEmbedded)
5960import Network.Wai.Handler.Warp
@@ -84,6 +85,17 @@ sendAsyncCommand cmd = do
8485 s <- asks doSendAsyncCommand
8586 liftIO $ s cmd
8687
88+-- | Forces execution of pending asyncronous code
89+syncPoint :: JSM ()
90+syncPoint = void $ sendCommand Sync
91+
92+-- | Forces execution of pending asyncronous code after performing `f`
93+syncAfter :: JSM a -> JSM a
94+syncAfter f = do
95+ result <- f
96+ syncPoint
97+ return result
98+
8799jsaddleOr :: ConnectionOptions -> JSM () -> Application -> Application
88100jsaddleOr opts entryPoint = websocketsOr opts wsApp
89101 where
@@ -127,9 +139,11 @@ jsaddleOr opts entryPoint = websocketsOr opts wsApp
127139 atomically (readTChan recvChan) >>= putMVar resultMVar
128140 (batch, Nothing) -> do
129141 sendTextData conn $ encode batch
130− SyncResult <- atomically $ readTChan recvChan
142+ atomically (readTChan recvChan) >>= \case
143+ SyncResult -> return ()
144+ ThrowJSValue e -> atomically (discardToSyncPoint commandChan) >>= (`putMVar` ThrowJSValue e)
145+ _ -> error "Unexpected result processing batch"
131146 return ()
132−
133147 runJSaddle ctx entryPoint
134148
135149 readBatch :: TChan (Either AsyncCommand (Command, MVar Result)) -> STM (Batch, Maybe (MVar Result))
@@ -144,6 +158,11 @@ jsaddleOr opts entryPoint = websocketsOr opts wsApp
144158 tryReadTChan chan >>= \case
145159 Nothing -> return (Batch (reverse asyncCmds) Sync, Nothing)
146160 Just cmd -> loop cmd asyncCmds
161+ discardToSyncPoint :: TChan (Either AsyncCommand (Command, MVar Result)) -> STM (MVar Result)
162+ discardToSyncPoint chan =
163+ readTChan chan >>= \case
164+ Right (_, resultMVar) -> return resultMVar
165+ _ -> discardToSyncPoint chan
147166
148167jsaddleApp :: Application
149168jsaddleApp = staticApp ($(mkSettings mkEmbedded)) {ssIndices = [unsafeToPiece "index.html"]}
@@ -151,4 +170,4 @@ jsaddleApp = staticApp ($(mkSettings mkEmbedded)) {ssIndices = [unsafeToPiece "i
151170run :: Int -> JSM () -> IO ()
152171run port f =
153172 runSettings (setPort port (setTimeout 3600 defaultSettings)) $
154− jsaddleOr defaultConnectionOptions f jsaddleApp
173+ jsaddleOr defaultConnectionOptions (f >> syncPoint) jsaddleApp