<commit_before>{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Concurrent
import Control.Monad (forever)
import Control.Monad.Trans
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy as LB
import Data.Aeson (eitherDecode, encode)
import Data.IORef
import qualified Data.List.NonEmpty as NE
import Network.HTTP.Types
import qualified Network.Wai as Wai
import Network.Wai.Handler.Warp
import Network.Wai.Handler.WebSockets
import Network.WebSockets
import Scrabble
import System.IO.Unsafe

type PlayerName = B.ByteString

-- | Run the web app
main :: IO ()
main = do
  _ <- liftIO gameStartThread
  r <- liftIO $ newIORef 0
  run 8000 (socketsApp r)

-- | This is the main web app that handles all requests
--   it handles web socket connections itself, and passes
--   all other requests to the default app
socketsApp :: IORef Int -> Wai.Application
socketsApp ref = websocketsOr defaultConnectionOptions wsApp defaultApp where

  -- | The app that handles web socket requests
  wsApp :: ServerApp  -- ServerApp is just this: IORef Int -> PendingConnection -> IO ()
  wsApp pending_conn = do
    i <- readIORef ref
    case i of
      0 -> connect player1 pending_conn ref 1
      1 -> connect player2 pending_conn ref 2
      _ -> rejectRequest pending_conn "too many players"

  -- | This is a simple app that just serves up some html and javascript
  defaultApp :: Wai.Application
  defaultApp request respond = go where
    go = do
      putStrLn (B.unpack $ Wai.rawPathInfo request)
      respond $ case Wai.rawPathInfo request of
        "/"        -> plainIndex
        "/game.js" -> gameJS
        bad        -> notFound (LB.fromStrict bad)
    plainIndex    = Wai.responseFile status200 [(hContentType, "text/html")]       "web/wai-server/index.html" Nothing
    gameJS        = Wai.responseFile status200 [(hContentType, "text/javascript")] "web/wai-server/game.js" Nothing
    notFound path = Wai.responseLBS  status404 [("Content-Type", "text/plain")] (LB.append "404 - Not Found: " path)

  -- | Connect with the incoming websocket request, set up communication with it in general.
  connect :: Show a => MVar (PlayerName, Connection) -> PendingConnection -> IORef a -> a -> IO ()
  connect convar pending_conn ref i = do
    conn <- acceptRequest pending_conn
    writeIORef ref i
    -- as soon as we connect, they must send their name.
    name <- receiveData conn :: IO B.ByteString
    putMVar convar (name, conn)
    forkPingThread conn 30
    forever $ receiveMove name conn -- listen for moves, forever.

  -- | receive a move (and game) from a player, and attempt to apply it
  --   if it isn't the players turn, or the move results in an error,
  --   then send the error message back on the connection
  --   if it succeeds, send the new game state to both players
  -- TODO: check if it is the players turn.
  receiveMove :: B.ByteString -> Connection -> IO ()
  receiveMove pName conn = go where<commit_msg>send player an id when connection is confirmed<commit_after>{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Concurrent
import Control.Monad (forever)
import Control.Monad.Trans
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy as LB
import Data.Aeson (eitherDecode, encode)
import Data.IORef
import qualified Data.List.NonEmpty as NE
import Network.HTTP.Types
import qualified Network.Wai as Wai
import Network.Wai.Handler.Warp
import Network.Wai.Handler.WebSockets
import Network.WebSockets
import Scrabble
import System.IO.Unsafe

type PlayerName = B.ByteString

-- | Run the web app
main :: IO ()
main = do
  _ <- liftIO gameStartThread
  r <- liftIO $ newIORef 0
  run 8000 (socketsApp r)

-- | This is the main web app that handles all requests
--   it handles web socket connections itself, and passes
--   all other requests to the default app
socketsApp :: IORef Int -> Wai.Application
socketsApp ref = websocketsOr defaultConnectionOptions wsApp defaultApp where

  -- | The app that handles web socket requests
  wsApp :: ServerApp  -- ServerApp is just this: IORef Int -> PendingConnection -> IO ()
  wsApp pending_conn = do
    i <- readIORef ref
    case i of
      0 -> connect player1 pending_conn ref 1
      1 -> connect player2 pending_conn ref 2
      _ -> rejectRequest pending_conn "too many players"

  -- | This is a simple app that just serves up some html and javascript
  defaultApp :: Wai.Application
  defaultApp request respond = go where
    go = do
      putStrLn (B.unpack $ Wai.rawPathInfo request)
      respond $ case Wai.rawPathInfo request of
        "/"        -> plainIndex
        "/game.js" -> gameJS
        bad        -> notFound (LB.fromStrict bad)
    plainIndex    = Wai.responseFile status200 [(hContentType, "text/html")]       "web/wai-server/index.html" Nothing
    gameJS        = Wai.responseFile status200 [(hContentType, "text/javascript")] "web/wai-server/game.js" Nothing
    notFound path = Wai.responseLBS  status404 [("Content-Type", "text/plain")] (LB.append "404 - Not Found: " path)

  -- | Connect with the incoming websocket request, set up communication with it in general.
  connect :: Show a => MVar (PlayerName, Connection) -> PendingConnection -> IORef a -> a -> IO ()
  connect convar pending_conn ref i = do
    conn <- acceptRequest pending_conn
    writeIORef ref i
    -- as soon as we connect, they must send their name.
    name <- receiveData conn :: IO B.ByteString
    -- send them back an id
    sendTextData conn (B.pack $ show i)
    putMVar convar (name, conn)
    forkPingThread conn 30
    forever $ receiveMove name conn -- listen for moves, forever.

  -- | receive a move (and game) from a player, and attempt to apply it
  --   if it isn't the players turn, or the move results in an error,
  --   then send the error message back on the connection
  --   if it succeeds, send the new game state to both players
  -- TODO: check if it is the players turn.
  receiveMove :: B.ByteString -> Connection -> IO ()
  receiveMove pName conn = go where
{'fraction_non_alphanumeric': 0.08299028486744607, 'fraction_numerical': 0.008562489708546023, 'mean_word_length': 3.1291638341264445, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6682266', 'n_tokens_mistral': 1814, 'n_tokens_neox': 1727, 'n_words': 702}