attempting to fix communication again

This commit is contained in:
nek0 2024-10-31 19:19:13 +01:00
parent 60fc061d00
commit 5e4c7ca992
8 changed files with 69 additions and 38 deletions

View file

@ -35,7 +35,7 @@ connectSocket
:: FilePath :: FilePath
-> IO Socket -> IO Socket
connectSocket path = do connectSocket path = do
sock <- socket AF_UNIX Stream defaultProtocol sock <- socket AF_UNIX Stream 0
setSocketOption sock KeepAlive 1 setSocketOption sock KeepAlive 1
connect sock (SockAddrUnix path) connect sock (SockAddrUnix path)
pure sock pure sock
@ -122,7 +122,10 @@ receiveMessage sock queue st = do
let mJsonMsg = A.decode' msg let mJsonMsg = A.decode' msg
maybe maybe
(putStrLn $ "received garbled data: " <> B8.unpack (B8.fromStrict rawMsg)) (putStrLn $ "received garbled data: " <> B8.unpack (B8.fromStrict rawMsg))
(STM.atomically . STM.writeTQueue queue) (\jsonMsg -> do
print jsonMsg
STM.atomically $ STM.writeTQueue queue jsonMsg
)
mJsonMsg mJsonMsg
) )
msgs msgs

View file

@ -2,8 +2,6 @@ module Client.Game where
import Control.Concurrent.STM (atomically, readTMVar) import Control.Concurrent.STM (atomically, readTMVar)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Loops import Control.Monad.Loops
import Control.Monad.RWS import Control.Monad.RWS

View file

@ -39,7 +39,7 @@ bindSocket path = do
unless (isSupportedSockAddr sockAddr) unless (isSupportedSockAddr sockAddr)
(error $ "invalid socket path " <> path) (error $ "invalid socket path " <> path)
-- removeIfExists path -- removeIfExists path
sock <- socket AF_UNIX Stream defaultProtocol sock <- socket AF_UNIX Stream 0
bind sock sockAddr bind sock sockAddr
Net.listen sock 5 Net.listen sock 5
pure sock pure sock
@ -77,7 +77,7 @@ disconnectClients clientList clients = do
maybe maybe
(pure ()) (pure ())
(\uuid -> do (\uuid -> do
sendMessage ServerQuit uuid clientList queueMessage ServerQuit uuid clientList
dropClient clientList (ccSocket client) dropClient clientList (ccSocket client)
) )
(ccUUID client) (ccUUID client)
@ -101,11 +101,25 @@ processRequests = do
Left (_ :: SomeException) -> Left (_ :: SomeException) ->
putStrLn "Main socket vanished!" putStrLn "Main socket vanished!"
Right (clientSock, _) -> do Right (clientSock, _) -> do
clientThreadId <- liftIO $ forkIO $ forever $ do messageQueue <- STM.newTQueueIO
receiveMessage clientSock queue socketList sockCOntainer <- STM.newTMVarIO clientSock
clientWriteThreadId <- liftIO $ forkIO $ forever $ do
receiveMessage sockCOntainer queue socketList
clientListenThreadId <- liftIO $ forkIO $ forever $ do
sendMessageQueue sockCOntainer messageQueue
print clientSock
liftIO $ STM.atomically $ do liftIO $ STM.atomically $ do
list <- STM.takeTMVar socketList list <- STM.takeTMVar socketList
STM.putTMVar socketList (ClientComms Nothing clientSock clientThreadId : list) STM.putTMVar
socketList
(ClientComms
Nothing
clientSock
messageQueue
clientWriteThreadId
clientListenThreadId
: list
)
putStrLn "accepted new connection" putStrLn "accepted new connection"
abortCondition <- serverStop <$> STM.atomically (STM.readTMVar st) abortCondition <- serverStop <$> STM.atomically (STM.readTMVar st)
unless abortCondition $ unless abortCondition $

View file

@ -37,7 +37,7 @@ handleMessage stateContainer readerContainer msg = do
let clientIdx = findIndex (isNothing . ccUUID) clients let clientIdx = findIndex (isNothing . ccUUID) clients
clientSock = ccSocket $ clients !! fromJust clientIdx clientSock = ccSocket $ clients !! fromJust clientIdx
newClients = map newClients = map
(\old@(ClientComms mUUID oldClientSock _) -> (\old@(ClientComms mUUID oldClientSock _ _ _) ->
if oldClientSock == clientSock && isNothing mUUID if oldClientSock == clientSock && isNothing mUUID
then then
old old
@ -49,7 +49,7 @@ handleMessage stateContainer readerContainer msg = do
clients clients
void $ liftIO $ STM.atomically $ STM.swapTMVar clientList newClients void $ liftIO $ STM.atomically $ STM.swapTMVar clientList newClients
putStrLn $ "Accepted Client with UUID " <> show clientId putStrLn $ "Accepted Client with UUID " <> show clientId
sendMessage (AcceptClient clientId) clientId clientList queueMessage (AcceptClient clientId) clientId clientList
ClientMessage clientId payload -> ClientMessage clientId payload ->
case payload of case payload of
ClientQuit -> do ClientQuit -> do
@ -67,7 +67,7 @@ handleMessage stateContainer readerContainer msg = do
currentPlayers <- STM.readTMVar (scPlayers stateContainer) currentPlayers <- STM.readTMVar (scPlayers stateContainer)
void $ STM.swapTMVar (scPlayers stateContainer) $ void $ STM.swapTMVar (scPlayers stateContainer) $
Player clientId freshWizard False (now, uuid) : currentPlayers Player clientId freshWizard False (now, uuid) : currentPlayers
sendMessage (ProvideInitialWizard freshWizard) clientId clientList queueMessage (ProvideInitialWizard freshWizard) clientId clientList
ClientReady -> do ClientReady -> do
putStrLn $ "client " <> show clientId <> " is ready!" putStrLn $ "client " <> show clientId <> " is ready!"
now <- getCurrentTime now <- getCurrentTime
@ -118,14 +118,9 @@ handleMessages = do
serverState <- get serverState <- get
readerContainer <- ask readerContainer <- ask
liftIO $ do liftIO $ do
msgs <- STM.atomically $ do msgs <- STM.atomically $
emptyState <- STM.isEmptyTQueue queue
if emptyState
then
pure []
else
STM.flushTQueue queue STM.flushTQueue queue
void $ do do
mapM_ mapM_
(handleMessage serverState readerContainer) (handleMessage serverState readerContainer)
msgs msgs

View file

@ -11,10 +11,12 @@ import qualified Data.Aeson as A
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy.Char8 as B8 import qualified Data.ByteString.Lazy.Char8 as B8
import Foreign.Marshal import Foreign.Marshal hiding (void)
import Network.Socket import Network.Socket
-- internal imports
import Library.Types import Library.Types
import Server.Communication.Send import Server.Communication.Send
@ -22,19 +24,20 @@ import Server.Types
-- | receive a 'ClientMessage' -- | receive a 'ClientMessage'
receiveMessage receiveMessage
:: Socket :: STM.TMVar Socket
-> STM.TQueue ClientMessage -> STM.TQueue ClientMessage
-> STM.TMVar [ClientComms] -> STM.TMVar [ClientComms]
-> IO () -> IO ()
receiveMessage sock queue clientList = do receiveMessage sockContainer queue clientList = do
sock <- STM.atomically $ STM.readTMVar sockContainer
let maxBufferLength = 4096 let maxBufferLength = 4096
mMsg <- do mMsg <- do
ptr <- mallocArray maxBufferLength ptr <- mallocArray maxBufferLength
eBufferLength <- eBufferLength <-
try $ recvBuf sock ptr maxBufferLength try $ recvBuf sock ptr maxBufferLength
bufferLength <- case eBufferLength of bufferLength <- case eBufferLength of
Left (_ :: IOException) -> do Left (e :: IOException) -> do
putStrLn "Socket vanished, cleaning up…" putStrLn ("Socket vanished, cleaning up after " <> show e)
dropClient clientList sock dropClient clientList sock
pure 0 pure 0
Right len -> pure len Right len -> pure len

View file

@ -42,32 +42,46 @@ import Library.Types
import Server.Types import Server.Types
-- | Sends a specified message through given socket to the client -- | Sends a specified message through given socket to the client
sendMessage queueMessage
:: ServerMessage :: ServerMessage
-> UUID -> UUID
-> STM.TMVar [ClientComms] -> STM.TMVar [ClientComms]
-> IO () -> IO ()
sendMessage msg uuid clientList = do queueMessage msg uuid clientList = do
clients <- STM.atomically $ STM.readTMVar clientList clients <- STM.atomically $ STM.readTMVar clientList
let mSock = ccSocket <$> find (\client -> ccUUID client == Just uuid) clients let mQueue = ccQueue <$> find (\client -> ccUUID client == Just uuid) clients
msgJson = A.encode msg
msgVector = VS.fromList $ B.unpack $ B.toStrict ('<' `B8.cons` (msgJson `B8.snoc` '>'))
-- putStrLn $ "Sending: " <> B8.unpack msgJson
maybe maybe
(putStrLn $ "unknown client UUID: " <> show uuid) (putStrLn $ "unknown client UUID: " <> show uuid)
(\sock -> (\queue ->
STM.atomically $ STM.writeTQueue queue msg
)
mQueue
sendMessageQueue
:: STM.TMVar Socket
-> STM.TQueue ServerMessage
-> IO ()
sendMessageQueue sockContainer queue = do
sock <- STM.atomically $ STM.takeTMVar sockContainer
msgs <- STM.atomically $ STM.flushTQueue queue
mapM_
(\msg -> do
print msg
let msgJson = A.encode msg
msgVector = VS.fromList $ B.unpack $ B.toStrict ('<' `B8.cons` (msgJson `B8.snoc` '>'))
VS.unsafeWith VS.unsafeWith
msgVector msgVector
(\ptr -> do (\ptr -> do
eResult <- try $ void $ sendBuf sock ptr (VS.length msgVector) eResult <- try $ void $ sendBuf sock ptr (VS.length msgVector)
case eResult of case eResult of
Left (_ :: IOException) -> Left (e :: IOException) ->
putStrLn $ "can't reach client " <> show uuid putStrLn $ "can't reach client after " <> show e
Right _ -> Right _ ->
pure () pure ()
) )
) )
mSock msgs
STM.atomically $ STM.putTMVar sockContainer sock
sendPings :: Game () sendPings :: Game ()
sendPings = do sendPings = do
@ -91,7 +105,7 @@ sendPings = do
else do else do
random <- liftIO nextRandom random <- liftIO nextRandom
let newPong = (lastPongTime, random) let newPong = (lastPongTime, random)
liftIO $ sendMessage liftIO $ queueMessage
( Ping random ( Ping random
) )
plId plId
@ -165,4 +179,4 @@ sendUpdate stateContainer tileMap player = do
sendSlice slice (Player playerId wizard _ _) = do sendSlice slice (Player playerId wizard _ _) = do
let msg = TickUpdate slice wizard let msg = TickUpdate slice wizard
print slice print slice
liftIO $ sendMessage msg playerId (scClientSockets stateContainer) liftIO $ queueMessage msg playerId (scClientSockets stateContainer)

View file

@ -70,6 +70,8 @@ data StateContainer = StateContainer
data ClientComms = ClientComms data ClientComms = ClientComms
{ ccUUID :: Maybe UUID { ccUUID :: Maybe UUID
, ccSocket :: Socket , ccSocket :: Socket
, ccQueue :: STM.TQueue ServerMessage
, ccWriter :: ThreadId
, ccListener :: ThreadId , ccListener :: ThreadId
} }
deriving (Eq) deriving (Eq)

View file

@ -15,6 +15,8 @@ extra-doc-files: CHANGELOG.md
common warnings common warnings
ghc-options: -Wall -threaded -rtsopts ghc-options: -Wall -threaded -rtsopts
-fwrite-ide-info
-hiedir=.hie
library library
import: warnings import: warnings