Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upload and parse scenarios #1798

Merged
merged 5 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .hlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#
- functions:
- {name: Data.List.head, within: []}
- {name: Prelude.head, within: []}
- {name: Prelude.head, within: [Swarm.Web.Tournament.Database.Query]}
- {name: Data.List.NonEmpty.fromList, within: [Swarm.Util]}
- {name: Prelude.tail, within: []}
- {name: Prelude.!!, within: [Swarm.Util.indexWrapNonEmpty, TestEval]}
Expand Down
99 changes: 99 additions & 0 deletions app/tournament/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
-- |
-- SPDX-License-Identifier: BSD-3-Clause
module Main where

import Control.Monad.Trans.Reader (runReaderT)
import Data.IORef (newIORef)
import Data.Maybe (fromMaybe)
import Network.Wai.Handler.Warp (Port)
import Options.Applicative
import Swarm.Game.State (Sha1 (..))
import Swarm.Web.Tournament
import Swarm.Web.Tournament.Database.Query
import System.Environment (lookupEnv)
import System.Posix.User (getEffectiveUserName)

data AppOpts = AppOpts
{ userWebPort :: Maybe Port
-- ^ Explicit port on which to run the web API
, gameGitVersion :: Sha1
, isLocalSocketConnection :: Bool
}

webPort :: Parser (Maybe Int)
webPort =
optional $
option
auto
( long "port"
<> metavar "PORT"
<> help ("Set the web service port (or disable it with 0). Default to " <> show defaultPort <> ".")
)

gameVersion :: Parser Sha1
kostmo marked this conversation as resolved.
Show resolved Hide resolved
gameVersion =
Sha1
<$> option
str
( long "version"
<> metavar "VERSION"
<> help "Set the git version of the game"
)

parseNativeDev :: Parser Bool
parseNativeDev =
switch
(long "native-dev" <> help "Running locally outside of a Docker container for development")

cliParser :: Parser AppOpts
cliParser = AppOpts <$> webPort <*> gameVersion <*> parseNativeDev

cliInfo :: ParserInfo AppOpts
cliInfo =
info
(cliParser <**> helper)
( header "Swarm tournament"
<> progDesc "Hosts a tournament server."
<> fullDesc
)

deduceConnType :: Bool -> IO DbConnType
deduceConnType isLocalSocketConn =
if isLocalSocketConn
then LocalDBOverSocket . Username <$> getEffectiveUserName
else do
maybeDbPassword <- lookupEnv envarPostgresPasswordKey
case maybeDbPassword of
Just dbPasswordEnvar -> return $ LocalDBFromDockerOverNetwork $ Password dbPasswordEnvar
Nothing -> RemoteDB <$> newIORef Nothing

main :: IO ()
main = do
opts <- execParser cliInfo
connType <- deduceConnType $ isLocalSocketConnection opts
webMain
(AppData (gameGitVersion opts) (persistenceFunctions connType) connType)
(fromMaybe defaultPort $ userWebPort opts)
where
persistenceFunctions connMode =
PersistenceLayer
{ lookupScenarioFileContent = withConnInfo lookupScenarioContent
, scenarioStorage =
ScenarioPersistence
{ lookupCache = withConnInfo lookupScenarioSolution
, storeCache = withConnInfo insertScenario
}
, solutionStorage =
ScenarioPersistence
{ lookupCache = withConnInfo lookupSolutionSubmission
, storeCache = withConnInfo insertSolutionSubmission
}
}
where
withConnInfo f x = do
-- This gets deferred and re-executed upon each invocation
-- of a DB interaction function.
-- We need this behavior because the password fetched via API
-- expires after 15 min.
connInfo <- mkConnectInfo connMode
runReaderT (f x) connInfo
10 changes: 10 additions & 0 deletions scripts/build-game.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash -ex

cd $(git rev-parse --show-toplevel)

# NOTE: There are several executables within the swarm.cabal project.
# If you only want to play the swarm game, you should specify an explicit
# target 'swarm:exe:swarm' to the 'stack' command, to avoid building
# extra dependencies.

stack build --fast swarm:swarm
5 changes: 2 additions & 3 deletions scripts/play.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#!/bin/bash -ex

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd $SCRIPT_DIR/..
cd $(git rev-parse --show-toplevel)

# This compiles without optimizations and then runs the resulting executable.
# It's been observed in certain versions of GHC that compiling with optimizations
# results in the swarm UI freezing for a potentially long time upon starting a scenario.
# See https://github.com/swarm-game/swarm/issues/1000#issuecomment-1378632269
stack build --fast swarm:swarm && stack exec swarm -- "$@"
scripts/build-game.sh && stack exec swarm -- "$@"
Loading
Loading