chat.hs 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. {-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
  2. import Yesod.Core
  3. import Yesod.WebSockets
  4. import qualified Data.Text.Lazy as TL
  5. import Control.Monad (forever)
  6. import Control.Monad.Trans.Reader
  7. import Control.Concurrent (threadDelay)
  8. import Data.Time
  9. import Conduit
  10. import Data.Monoid ((<>))
  11. import Control.Concurrent.STM.Lifted
  12. import Data.Text (Text)
  13. data App = App (TChan Text)
  14. instance Yesod App
  15. mkYesod "App" [parseRoutes|
  16. / HomeR GET
  17. |]
  18. chatApp :: WebSocketsT Handler ()
  19. chatApp = do
  20. sendTextData ("Welcome to the chat server, please enter your name." :: Text)
  21. name <- receiveData
  22. sendTextData $ "Welcome, " <> name
  23. App writeChan <- getYesod
  24. readChan <- atomically $ do
  25. writeTChan writeChan $ name <> " has joined the chat"
  26. dupTChan writeChan
  27. race_
  28. (forever $ atomically (readTChan readChan) >>= sendTextData)
  29. (sourceWS $$ mapM_C (\msg ->
  30. atomically $ writeTChan writeChan $ name <> ": " <> msg))
  31. getHomeR :: Handler Html
  32. getHomeR = do
  33. webSockets chatApp
  34. defaultLayout $ do
  35. [whamlet|
  36. <div #output>
  37. <form #form>
  38. <input #input autofocus>
  39. |]
  40. toWidget [lucius|
  41. \#output {
  42. width: 600px;
  43. height: 400px;
  44. border: 1px solid black;
  45. margin-bottom: 1em;
  46. p {
  47. margin: 0 0 0.5em 0;
  48. padding: 0 0 0.5em 0;
  49. border-bottom: 1px dashed #99aa99;
  50. }
  51. }
  52. \#input {
  53. width: 600px;
  54. display: block;
  55. }
  56. |]
  57. toWidget [julius|
  58. var url = document.URL,
  59. output = document.getElementById("output"),
  60. form = document.getElementById("form"),
  61. input = document.getElementById("input"),
  62. conn;
  63. url = url.replace("http:", "ws:").replace("https:", "wss:");
  64. conn = new WebSocket(url);
  65. conn.onmessage = function(e) {
  66. var p = document.createElement("p");
  67. p.appendChild(document.createTextNode(e.data));
  68. output.appendChild(p);
  69. };
  70. form.addEventListener("submit", function(e){
  71. conn.send(input.value);
  72. input.value = "";
  73. e.preventDefault();
  74. });
  75. |]
  76. main :: IO ()
  77. main = do
  78. chan <- atomically newBroadcastTChan
  79. warp 3000 $ App chan