Reputation: 550
I'm trying to make websockets work with servant-server:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
import Control.Monad.IO.Class
import Data.Text (Text)
import Network.Wai.Handler.Warp (run)
import Network.WebSockets
import Servant hiding (route)
import Servant.API.WebSocket
type API = Raw
:<|> "game" :> WebSocketPending
myAPI :: Proxy API
myAPI = Proxy
server :: Server API
server = serveDirectoryFileServer "site"
:<|> game "From socket server"
game :: MonadIO m => Text -> PendingConnection -> m ()
game msg pending = do
conn <- liftIO $ acceptRequest pending
liftIO $ sendTextData conn msg
app :: Application
app = serve myAPI server
main :: IO ()
main = run 8080 app
The intention is to send a string From socket server
back to a client for testing.
In Firefox console:
// Create WebSocket connection.
socket = new WebSocket('ws://localhost:8080/game');
// Connection opened
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});
// Listen for messages
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
I got an error frome firefox:
Firefox can’t establish a connection to the server at ws://localhost:8080/game
Could someone give me a hint?
Update:
Here's the code that worked after re-ordering the API.
type API = "game" :> WebSocketPending
:<|> Raw
myAPI :: Proxy API
myAPI = Proxy
server :: Server API
server = game
:<|> serveDirectoryFileServer "site"
game :: MonadIO m => PendingConnection -> m ()
game pending = do
conn <- liftIO $ acceptRequest pending
liftIO $ withPingThread conn 30 (return ()) $ do
forever $ do
msg <- receiveData conn :: IO Text
sendTextData conn msg
Upvotes: 2
Views: 702
Reputation: 18259
The problem turns out to be the order of your API endpoints in the type definition.
The type combinator (:<|>)
is described in the docs, as
Union of two APIs, first takes precedence in case of overlap.
and since Raw essentially matches everything, your original definition was treating all requests as "raw" requests, never forwarding to your Websocket server.
Simply switching the order - of the arguments to (:<|>)
in both the type and the server
definition - fixes this problem, as you observed.
Upvotes: 1