@@ -27,16 +27,19 @@ import Brick.BChan
2727import Control.Carrier.Lift (runM )
2828import Control.Carrier.Throw.Either (runThrow )
2929import Control.Concurrent (forkIO , threadDelay )
30+ import Control.Exception (bracket , try )
3031import Control.Lens (Setter' , view , (%~) , (?~) , (^.) )
3132import Control.Monad (forever , void , when )
3233import Control.Monad.IO.Class (liftIO )
3334import Data.IORef (IORef , modifyIORef , newIORef , readIORef , writeIORef )
35+ import Data.List.NonEmpty qualified as NE
3436import Data.Maybe (fromMaybe )
3537import Data.Text qualified as T
3638import Data.Text.IO qualified as T
3739import GitHash (GitInfo )
3840import Graphics.Vty qualified as V
3941import Graphics.Vty.CrossPlatform qualified as V
42+ import Network.Socket qualified as Net
4043import Swarm.Failure (SystemFailure )
4144import Swarm.Game.State.Runtime
4245import Swarm.Log (LogSource (SystemLog ), Severity (.. ))
@@ -135,9 +138,17 @@ defaultMetrics = 6543
135138startMetricsThread :: Maybe Int -> Store -> IO (Either String Int )
136139startMetricsThread (Just 0 ) _ = pure $ Left " Metrics API disabled."
137140startMetricsThread mPort store = do
138- let p = fromMaybe 6543 mPort
139- _ <- WaiMetrics. forkServerWith store " localhost" p
140- pure $ Right p
141+ let port = fromMaybe 6543 mPort
142+ portCheck <- checkPortFree port
143+ case portCheck of
144+ Right () -> Right port <$ WaiMetrics. forkServerWith store " localhost" port
145+ Left e -> pure . Left $ " Can not start on port '" <> show port <> " ': " <> show e
146+ where
147+ checkPortFree :: Int -> IO (Either IOError () )
148+ checkPortFree port = do
149+ let hints = Net. defaultHints {Net. addrFlags = [Net. AI_PASSIVE ], Net. addrSocketType = Net. Stream }
150+ addr <- NE. head <$> Net. getAddrInfo (Just hints) Nothing (Just $ show port)
151+ try @ IOError . bracket (Net. openSocket addr) Net. close $ flip Net. bind (Net. addrAddress addr)
141152
142153-- | Create a channel for app events.
143154--
0 commit comments