Commit 45afebaa authored by Yuanle Song's avatar Yuanle Song
Browse files

rd-api Main: exit if env variable doesn't parse.

For port number, if parse fail, it will exit on start up.
previously env var with parse error are ignored silently.
parent 26eafdb3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
ignore "Redundant do"
ignore "Reduce duplication" = TestEither
+31 −17
Original line number Diff line number Diff line
@@ -2,8 +2,8 @@ module Main (main) where

import Data.String (fromString)
import System.Environment (getEnvironment)
import Data.Monoid ((<>))
import Control.Monad (when)
import Data.Semigroup ((<>))
import Control.Monad (mzero, when)
import Control.Monad.IO.Class (liftIO)
import System.Directory (setCurrentDirectory)
import Data.Maybe (fromJust)
@@ -26,21 +26,35 @@ import OptsDoc (rdApiDescription)
import App (mkWaiApp)
import Worker (startWorkers)

-- | convert Maybe String to Maybe Int
toIntMaybe :: Maybe String -> Maybe Int
toIntMaybe Nothing = Nothing
toIntMaybe (Just s) = case reads s of
                        [(i, [])] -> Just i
                        _ -> Nothing
-- | parse int env var, if it exists and is an int, return Right (Just i).
-- if it exists and doesn't parse, return Left msg with key and value info.
-- otherwise, return Right Nothing.
parseIntEnv :: String -> [(String, String)] -> Either T.Text (Maybe Int)
parseIntEnv key env =
  case lookup key env of
    Nothing -> Right Nothing
    Just s -> case reads s of
                  [(i, [])] -> Right $ Just i
                  _ -> Left $ "failed to parse " <> T.pack key <> " from env variable: " <> T.pack s

updateRDConfigFromEnvPure :: [(String, String)] -> RDConfig -> Either T.Text RDConfig
updateRDConfigFromEnvPure env = Right
    .(\c -> maybe c (\h -> c { host=h }) (lookup "HOST" env))
    .(\c -> maybe c (\p -> c { port=p }) (toIntMaybe (lookup "PORT" env)))
    .(\c -> maybe c (\h -> c { redisHost=h }) (lookup "REDIS_HOST" env))
    .(\c -> maybe c (\p -> c { redisPort=p }) (toIntMaybe (lookup "REDIS_PORT" env)))
    .(\c -> maybe c (\d -> c { webRoot=d }) (lookup "WEB_ROOT" env))
    .(\c -> maybe c (\i -> c { fileWorkerCount=i }) (toIntMaybe (lookup "WORKER" env)))
updateRDConfigFromEnvPure env c0 =
  (\c -> Right $ maybe c (\h -> c { host=h }) (lookup "HOST" env)) c0 >>=
  (\c -> either
           Left
           (maybe (Right c) (\i -> Right $ c { port=i }))
           (parseIntEnv "PORT" env)) >>=
  (\c -> Right $ maybe c (\h -> c { redisHost=h })
                 (lookup "REDIS_HOST" env)) >>=
  (\c -> either
           Left
           (maybe (Right c) (\i -> Right $ c { redisPort=i }))
           (parseIntEnv "REDIS_PORT" env)) >>=
  (\c -> Right $ maybe c (\d -> c { webRoot=d }) (lookup "WEB_ROOT" env)) >>=
  (\c -> either
           Left
           (maybe (Right c) (\i -> Right $ c { fileWorkerCount=i }))
           (parseIntEnv "WORKER" env))

-- | update RDConfig if some env variables are defined.
-- return IO (Right RDConfig) on success
@@ -55,8 +69,8 @@ runApiServer rdConfig = do
  configE <- liftIO $ updateRDConfigFromEnv rdConfig
  configMaybe <- case configE of
    Left e -> do
      liftIO $ logl rc0 $ sformat ("Error: some config from env variable failed to parse: " % stext) e
      return Nothing
      liftIO $ logl rc0 $ sformat ("Error: " % stext) e
      mzero    -- early exit
    Right config -> return $ Just config
  let config = fromJust configMaybe
  connEi <- runExceptT $ scriptIO $ R.checkedConnect $ R.defaultConnectInfo {
+1 −1
Original line number Diff line number Diff line
name:                reliable-download
version:             1.1.0.0
version:             1.1.1.0
synopsis:            provide reliable download service via HTTP
description:         reliable-download web application and cli tool
homepage:            "https://github.com/sylecn/reliable-download#readme"
+58 −11
Original line number Diff line number Diff line
@@ -4,23 +4,70 @@ import qualified Data.Text as T

import Test.Hspec

step1 :: Either T.Text String
step1 = Left "step1 failed"

step2 :: Either T.Text String
step2 = Right "step2 ok"

step3 :: Either T.Text String
step3 = Right "step3 ok"

test1 :: Either T.Text String
test1 = Left "test1 failed"
test1 = do
  _ <- step1
  _ <- step2
  step3

test2 :: Either T.Text Int
test2 = do
  _ <- Left "err1"
  _ <- Right (2 :: Int)
  _ <- Right (3 :: Int)
  Right (5 :: Int)

test3 :: Either T.Text Int
test3 = do
  _ <- Right (2 :: Int)
  _ <- Right (3 :: Int)
  Right (5 :: Int)

two :: Either T.Text Int
two = Right 2

negtwo :: Either T.Text Int
negtwo = Right (-2)

inc :: Int -> Either T.Text Int
inc v = if v < 0 then
             Left "I don't work on negative value"
         else
             Right $ v + 1

incBy :: Int -> Int -> Either T.Text Int
incBy i v = if v < 0 then
             Left "I don't work on negative value"
         else
             Right $ v + i

test2 :: Either T.Text String
test2 = Right "test2 ok"
test4 :: Either T.Text Int
test4 = do
  i <- two
  j <- inc i
  incBy 5 j

test3 :: Either T.Text String
test3 = Right "test3 ok"

test :: Either T.Text String
test = do
  _ <- test1
  _ <- test2
  test3
test5 :: Either T.Text Int
test5 = do
  i <- negtwo
  inc i

spec :: Spec
spec = do
  describe "either" $ do
    it "should be that" $ do
      test `shouldBe` test1
      test1 `shouldBe` step1
      test2 `shouldBe` Left "err1"
      test3 `shouldBe` Right (5 :: Int)
      test4 `shouldBe` Right (8 :: Int)
      test5 `shouldBe` Left "I don't work on negative value"