@@ -22,6 +22,8 @@ module Language.Javascript.JSaddle.WebSockets (
22 , sendCommand
22 , sendCommand
23 , sendLazyCommand
23 , sendLazyCommand
24 , sendAsyncCommand
24 , sendAsyncCommand
27import Control.Exception (throwIO)
29import Control.Exception (throwIO)
@@ -51,9 +53,8 @@ import Network.Wai.Handler.WebSockets (websocketsOr)
52import Language.Javascript.JSaddle.Types
54import Language.Javascript.JSaddle.Types
53 (Command(..), AsyncCommand(..), Result(..), JSContextRef(..), JSVal(..),
55 (Command(..), AsyncCommand(..), Result(..), JSContextRef(..), JSVal(..),
54− Object(..), JSValueReceived(..), JSM, Batch(..), JSValueForSend(..))
56+ Object(..), JSValueReceived(..), JSM, Batch(..), JSValueForSend(..), runJSaddle)
55import Language.Javascript.JSaddle.Exception (JSException(..))
57import Language.Javascript.JSaddle.Exception (JSException(..))
56−import Language.Javascript.JSaddle.Monad (runJSaddle)
57import Language.Javascript.JSaddle.Native (wrapJSVal)
58import Language.Javascript.JSaddle.Native (wrapJSVal)
58import Language.Javascript.JSaddle.WebSockets.Files (mkEmbedded)
59import Language.Javascript.JSaddle.WebSockets.Files (mkEmbedded)
59import Network.Wai.Handler.Warp
60import Network.Wai.Handler.Warp
@@ -84,6 +85,17 @@ sendAsyncCommand cmd = do
84 s <- asks doSendAsyncCommand
85 s <- asks doSendAsyncCommand
85 liftIO $ s cmd
86 liftIO $ s cmd
88+-- | Forces execution of pending asyncronous code
90+syncPoint = void $ sendCommand Sync
92+-- | Forces execution of pending asyncronous code after performing `f`
93+syncAfter :: JSM a -> JSM a
87jsaddleOr :: ConnectionOptions -> JSM () -> Application -> Application
99jsaddleOr :: ConnectionOptions -> JSM () -> Application -> Application
88jsaddleOr opts entryPoint = websocketsOr opts wsApp
100jsaddleOr opts entryPoint = websocketsOr opts wsApp
@@ -127,9 +139,11 @@ jsaddleOr opts entryPoint = websocketsOr opts wsApp
127 atomically (readTChan recvChan) >>= putMVar resultMVar
139 atomically (readTChan recvChan) >>= putMVar resultMVar
128 (batch, Nothing) -> do
140 (batch, Nothing) -> do
129 sendTextData conn $ encode batch
141 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"
131 return ()
146 return ()
133 runJSaddle ctx entryPoint
147 runJSaddle ctx entryPoint
135 readBatch :: TChan (Either AsyncCommand (Command, MVar Result)) -> STM (Batch, Maybe (MVar Result))
149 readBatch :: TChan (Either AsyncCommand (Command, MVar Result)) -> STM (Batch, Maybe (MVar Result))
@@ -144,6 +158,11 @@ jsaddleOr opts entryPoint = websocketsOr opts wsApp
144 tryReadTChan chan >>= \case
158 tryReadTChan chan >>= \case
145 Nothing -> return (Batch (reverse asyncCmds) Sync, Nothing)
159 Nothing -> return (Batch (reverse asyncCmds) Sync, Nothing)
146 Just cmd -> loop cmd asyncCmds
160 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
148jsaddleApp :: Application
167jsaddleApp :: Application
149jsaddleApp = staticApp ($(mkSettings mkEmbedded)) {ssIndices = [unsafeToPiece "index.html"]}
168jsaddleApp = staticApp ($(mkSettings mkEmbedded)) {ssIndices = [unsafeToPiece "index.html"]}
@@ -151,4 +170,4 @@ jsaddleApp = staticApp ($(mkSettings mkEmbedded)) {ssIndices = [unsafeToPiece "i
151run :: Int -> JSM () -> IO ()
170run :: Int -> JSM () -> IO ()
152run port f =
171run port f =
153 runSettings (setPort port (setTimeout 3600 defaultSettings)) $
172 runSettings (setPort port (setTimeout 3600 defaultSettings)) $
154− jsaddleOr defaultConnectionOptions f jsaddleApp
173+ jsaddleOr defaultConnectionOptions (f >> syncPoint) jsaddleApp